GaryJones/Gamajo-Template-Loader Template, giống woocommerce (ok)
https://github.com/GaryJones/Gamajo-Template-Loader
Ví dụ 1:
C:\xampp\htdocs\wordpress5\wp-content\plugins\pw-sample-template-loader-plugin\pw-sample-template-loader.php
<?php
/*
Plugin Name: PW Sample Template Loader
Description: Illustrates how to build a template file loaded into a plugin using the Gamajo Template Loader class
Author: Pippin Williamson
Version: 1.0
*/
define( 'PW_SAMPLE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
if( ! class_exists( 'Gamajo_Template_Loader' ) ) {
require PW_SAMPLE_PLUGIN_DIR . 'class-gamajo-template-loader.php';
}
require PW_SAMPLE_PLUGIN_DIR . 'class-pw-template-loader.php';
function pw_sample_shortcode() {
$templates = new PW_Template_Loader;
ob_start();
$templates->get_template_part( 'content', 'header' );
$templates->get_template_part( 'content', 'middle' );
$templates->get_template_part( 'content', 'footer' );
return ob_get_clean();
}
add_shortcode( 'pw_sample', 'pw_sample_shortcode' );
C:\xampp\htdocs\wordpress5\wp-content\plugins\pw-sample-template-loader-plugin\class-gamajo-template-loader.php
<?php
/**
* Template Loader for Plugins.
*
* @package Gamajo_Template_Loader
* @author Gary Jones
* @link http://github.com/GaryJones/Gamajo-Template-Loader
* @copyright 2013 Gary Jones
* @license GPL-2.0+
*/
/**
* Template loader.
*
* Originally based on functions in Easy Digital Downloads (thanks Pippin!).
*
* When using in a plugin, create a new class that extends this one and just overrides the properties.
*
* @package Gamajo_Template_Loader
* @author Gary Jones
*/
class Gamajo_Template_Loader {
/**
* Prefix for filter names.
*
* @since 1.0.0
* @type string
*/
protected $filter_prefix = 'your_plugin';
/**
* Directory name where custom templates for this plugin should be found in the theme.
*
* @since 1.0.0
* @type string
*/
protected $theme_template_directory = 'your-plugin'; // or 'your-plugin-templates' etc.
/**
* Reference to the root directory path of this plugin.
*
* Can either be a defined constant, or a relative reference from where the subclass lives.
*
* @since 1.0.0
* @type string
*/
protected $plugin_directory = "YOUR_PLUGIN_DIR"; // or plugin_dir_path( dirname( __FILE__ ) ); etc.
/**
* Retrieve a template part.
*
* @since 1.0.0
*
* @uses Gamajo_Template_Loader::get_template_possble_parts() Create file names of templates.
* @uses Gamajo_Template_Loader::locate_template() Retrieve the name of the highest priority template
* file that exists.
*
* @param string $slug
* @param string $name Optional. Default null.
* @param bool $load Optional. Default true.
*
* @return string
*/
public function get_template_part( $slug, $name = null, $load = true ) {
// Execute code for this part
do_action( 'get_template_part_' . $slug, $slug, $name );
// Get files names of templates, for given slug and name.
$templates = $this->get_template_file_names( $slug, $name );
// Return the part that is found
return $this->locate_template( $templates, $load, false );
}
/**
* Given a slug and optional name, create the file names of templates.
*
* @since 1.0.0
*
* @param string $slug
* @param string $name
*
* @return array
*/
protected function get_template_file_names( $slug, $name ) {
if ( isset( $name ) ) {
$templates[] = $slug . '-' . $name . '.php';
}
$templates[] = $slug . '.php';
/**
* Allow template choices to be filtered.
*
* The resulting array should be in the order of most specific first, to least specific last.
* e.g. 0 => recipe-instructions.php, 1 => recipe.php
*
* @since 1.0.0
*
* @param array $templates Names of template files that should be looked for, for given slug and name.
* @param string $slug Template slug.
* @param string $name Template name.
*/
return apply_filters( $this->filter_prefix . '_get_template_part', $templates, $slug, $name );
}
/**
* Retrieve the name of the highest priority template file that exists.
*
* Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
* inherit from a parent theme can just overload one file. If the template is
* not found in either of those, it looks in the theme-compat folder last.
*
* @since 1.0.0
*
* @uses Gamajo_Tech_Loader::get_template_paths() Return a list of paths to check for template locations.
*
* @param string|array $template_names Template file(s) to search for, in order.
* @param bool $load If true the template file will be loaded if it is found.
* @param bool $require_once Whether to require_once or require. Default true.
* Has no effect if $load is false.
*
* @return string The template filename if one is located.
*/
protected function locate_template( $template_names, $load = false, $require_once = true ) {
// No file found yet
$located = false;
// Remove empty entries
$template_names = array_filter( (array) $template_names );
// Try to find a template file
foreach ( $template_names as $template_name ) {
// Trim off any slashes from the template name
$template_name = ltrim( $template_name, '/' );
// Try locating this template file by looping through the template paths
foreach ( $this->get_template_paths() as $template_path ) {
if ( file_exists( $template_path . $template_name ) ) {
$located = $template_path . $template_name;
break;
}
}
}
if ( $load && $located ) {
load_template( $located, $require_once );
}
return $located;
}
/**
* Return a list of paths to check for template locations.
*
* Default is to check in a child theme (if relevant) before a parent theme, so that themes which inherit from a
* parent theme can just overload one file. If the template is not found in either of those, it looks in the
* theme-compat folder last.
*
* @since 1.0.0
*
* @return mixed|void
*/
protected function get_template_paths() {
$theme_directory = trailingslashit( $this->theme_template_directory );
$file_paths = array(
10 => trailingslashit( get_template_directory() ) . $theme_directory,
100 => $this->get_templates_dir()
);
// Only add this conditionally, so non-child themes don't redundantly check active theme twice.
if ( is_child_theme() ) {
$file_paths[1] = trailingslashit( get_stylesheet_directory() ) . $theme_directory;
}
/**
* Allow ordered list of template paths to be amended.
*
* @since 1.0.0
*
* @param array $var Default is directory in child theme at index 1, parent theme at 10, and plugin at 100.
*/
$file_paths = apply_filters( $this->filter_prefix . '_template_paths', $file_paths );
// sort the file paths based on priority
ksort( $file_paths, SORT_NUMERIC );
return array_map( 'trailingslashit', $file_paths );
}
/**
* Return the path to the templates directory in this plugin.
*
* May be overridden in subclass.
*
* @since 1.0.0
*
* @return string
*/
protected function get_templates_dir() {
return $this->plugin_directory . 'templates';
}
}
C:\xampp\htdocs\wordpress5\wp-content\plugins\pw-sample-template-loader-plugin\class-pw-template-loader.php
<?php
/**
* Template loader for PW Sample Plugin.
*
* Only need to specify class properties here.
*
*/
class PW_Template_Loader extends Gamajo_Template_Loader {
/**
* Prefix for filter names.
*
* @since 1.0.0
* @type string
*/
protected $filter_prefix = 'pw';
/**
* Directory name where custom templates for this plugin should be found in the theme.
*
* @since 1.0.0
* @type string
*/
protected $theme_template_directory = 'pw-templates';
/**
* Reference to the root directory path of this plugin.
*
* @since 1.0.0
* @type string
*/
protected $plugin_directory = PW_SAMPLE_PLUGIN_DIR;
}
C:\xampp\htdocs\wordpress5\wp-content\plugins\pw-sample-template-loader-plugin\templates\content-header.php
<div id="pw-header">
<p>This is the header area.</p>
</div>
C:\xampp\htdocs\wordpress5\wp-content\plugins\pw-sample-template-loader-plugin\templates\content-middle.php
<div id="pw-content">
<p>This is the main content area.</p>
</div>
C:\xampp\htdocs\wordpress5\wp-content\plugins\pw-sample-template-loader-plugin\templates\content-footer.php
<div id="pw-footer">
<p>This is the footer area.</p>
</div>
C:\xampp\htdocs\wordpress5\wp-content\themes\twentytwentyone-child\pw-templates\content-header.php
<div id="pw-header">
<p>This is the header area theme child.</p>
</div>
Kết quả:
Ví dụ 2.1: Nhúng trực tiếp trong file hd-quiz\index.php khi update vẫn bị xóa 😂 và tiếp sau đây chúng ta sẽ nhúng nó vào child theme :(
C:\xampp\htdocs\wordpress5\wp-content\plugins\hd-quiz\index.php
// Lionel
define( 'PW_SAMPLE_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
if( ! class_exists( 'Gamajo_Template_Loader' ) ) {
require PW_SAMPLE_PLUGIN_DIR . 'class-gamajo-template-loader.php';
}
require PW_SAMPLE_PLUGIN_DIR . 'class-pw-template-loader.php';
function hdq_add_shortcode_edit($atts)
{
// Attributes
extract(
shortcode_atts(
array(
'quiz' => '',
),
$atts
)
);
// Code
ob_start();
include plugin_dir_path(__FILE__) . './includes/template-edit.php';
return ob_get_clean();
}
add_shortcode('HDquizs', 'hdq_add_shortcode_edit',30);
// Lionel
C:\xampp\htdocs\wordpress5\wp-content\plugins\hd-quiz\includes\template-edit.php
<?php
function hdq_multiple_choice_text_edit($question_ID, $question_number, $question, $quiz)
{ die($question_ID);
// require(dirname(__FILE__) . '/templates/default.php');
$templates = new PW_Template_Loader;
include $templates->get_template_part( 'default' );
}
function hdq_multiple_choice_image_edit($question_ID, $question_number, $question, $quiz)
{
// require(dirname(__FILE__) . '/templates/image.php');
$templates = new PW_Template_Loader;
include $templates->get_template_part( 'image' );
}
function hdq_text_based_edit($question_ID, $question_number, $question, $quiz)
{
// require(dirname(__FILE__) . '/templates/text.php');
$templates = new PW_Template_Loader;
include $templates->get_template_part( 'text' );
}
function hdq_title_edit($question_ID, $question_number, $question, $quiz)
{
// require(dirname(__FILE__) . '/templates/title.php');
$templates = new PW_Template_Loader;
include $templates->get_template_part( 'title' );
}
function hdq_select_all_apply_text_edit($question_ID, $question_number, $question, $quiz)
{
// require(dirname(__FILE__) . '/templates/select-all-text.php');
$templates = new PW_Template_Loader;
include $templates->get_template_part( 'select-all-text' );
}
// enqueue style and script
wp_enqueue_style(
'hdq_admin_style',
plugin_dir_url(__FILE__) . './css/hdq_style.css',
array(),
HDQ_PLUGIN_VERSION
);
wp_enqueue_script(
'hdq_admin_script',
plugins_url('./js/hdq_script.js?', __FILE__),
array('jquery'),
HDQ_PLUGIN_VERSION,
true
);
$buildQuiz = true;
if (!defined('HDQ_REDIRECT')) {
define('HDQ_REDIRECT', true);
}
if (!is_singular() && HDQ_REDIRECT) {
// if we are on a category, search, or home blog page
// replace quiz with direct link to post or page
hdq_print_quiz_in_loop();
$buildQuiz = false;
} else {
if (function_exists("is_amp_endpoint")) {
if (is_amp_endpoint()) {
hdq_print_quiz_in_loop();
$buildQuiz = false;
}
}
}
if ($buildQuiz === true) {
$quiz_ID = intval($quiz); // quiz ID from shortcode
// get quiz name
$quiz_name = get_term($quiz_ID, "quiz");
if ($quiz_name == null) {
echo 'This quiz no longer exists';
return;
}
$quiz_name = $quiz_name->name;
$quiz_settings = get_hdq_quiz($quiz_ID);
// get question order for query
$question_order = "menu_order"; // default
if (
$quiz_settings["randomize_questions"]["value"][0] === "yes" ||
$quiz_settings["pool_of_questions"]["value"] > 0
) {
$question_order = "rand";
}
$per_page = -1; // show all questions by default
$paginate = false;
if ($quiz_settings["wp_paginate"]["value"] > 0) {
if ($quiz_settings["pool_of_questions"]["value"] > 0) {
return;
} else {
$paginate = true;
$question_order = "menu_order";
$per_page = $quiz_settings["wp_paginate"]["value"];
}
}
if ($quiz_settings["pool_of_questions"]["value"] > 0) {
$per_page = $quiz_settings["pool_of_questions"]["value"];
}
$hdq_settings = hdq_get_settings();
// if we should display ads
$use_adcode = false;
$hdq_adcode = hdq_decode(hdq_decode($hdq_settings["hd_qu_adcode"]["value"]));
if ($hdq_adcode != "" && $hdq_adcode != null) {
$hdq_adcode = stripcslashes(urldecode($hdq_adcode));
$use_adcode = true;
}
$legacy_scroll = false;
if (isset($hdq_settings["hd_qu_legacy_scroll"]["value"]) && $hdq_settings["hd_qu_legacy_scroll"]["value"][0] == "yes") {
$legacy_scroll = true;
}
// Get the page or post featured image
// (try to send to facebook for sharing results)
$hdq_featured_image = "";
if (has_post_thumbnail()) {
$hdq_featured_image = wp_get_attachment_url(get_post_thumbnail_id(get_the_ID()), 'full');
}
$hdq_twitter_handle = $hdq_settings["hd_qu_tw"]["value"];
if ($hdq_twitter_handle == "" || $hdq_twitter_handle == null) {
$hdq_twitter_handle = "harmonic_design";
}
$hide_questions = "";
if(isset($quiz_settings["hide_questions"]["value"][0])){
$hide_questions = $quiz_settings["hide_questions"]["value"][0];
}
$finish = "Finish";
if(!isset($hdq_settings["hd_qu_finish"]) || $hdq_settings["hd_qu_finish"]["value"] !== ""){
$finish = $hdq_settings["hd_qu_finish"]["value"];
}
$next = "Next";
if(!isset($hdq_settings["hd_qu_next"]) || $hdq_settings["hd_qu_next"]["value"] !== ""){
$next = $hdq_settings["hd_qu_next"]["value"];
}
$results = "Results";
if(!isset($hdq_settings["hd_results"]) || $hdq_settings["hd_results"]["value"] !== ""){
$results = $hdq_settings["hd_results"]["value"];
}
$translations = array(
"finish" => $finish,
"next" => $next,
"results" => $results,
);
$jPaginate = false;
// create object for localized script
$hdq_local_vars = new \stdClass();
$hdq_local_vars->hdq_quiz_id = $quiz_ID;
$hdq_local_vars->hdq_timer = $quiz_settings["quiz_timer"]["value"];
$hdq_local_vars->hdq_timer_question = $quiz_settings["quiz_timer_question"]["value"][0];
$hdq_local_vars->hdq_show_results = $quiz_settings["show_results"]["value"][0];
$hdq_local_vars->hdq_results_correct = $quiz_settings["show_results_correct"]["value"][0];
$hdq_local_vars->hdq_show_extra_text = $quiz_settings["show_extra_text"]["value"][0];
$hdq_local_vars->hdq_show_results_now = $quiz_settings["show_results_now"]["value"][0];
$hdq_local_vars->hdq_stop_answer_reselect = $quiz_settings["stop_answer_reselect"]["value"][0];
$hdq_local_vars->hdq_pass_percent = $quiz_settings["quiz_pass_percentage"]["value"];
$hdq_local_vars->hdq_share_results = $quiz_settings["share_results"]["value"][0];
$hdq_local_vars->hdq_hide_questions = $hide_questions;
$hdq_local_vars->hdq_legacy_scroll = $legacy_scroll;
$hdq_local_vars->hdq_quiz_permalink = get_the_permalink();
$hdq_local_vars->hdq_twitter_handle = $hdq_twitter_handle;
$hdq_local_vars->hdq_quiz_name = $quiz_name;
$hdq_local_vars->hdq_ajax = admin_url('admin-ajax.php');
$hdq_local_vars->hdq_featured_image = $hdq_featured_image;
$hdq_local_vars->hdq_use_ads = $use_adcode;
$hdq_local_vars->hdq_submit = array();
$hdq_local_vars->hdq_init = array();
$hdq_local_vars->hdq_translations = $translations;
do_action("hdq_submit", $hdq_local_vars); // add functions to quiz complete
do_action("hdq_init", $hdq_local_vars); // add functions to quiz init
$hdq_local_vars = json_encode($hdq_local_vars);
wp_localize_script('hdq_admin_script', 'hdq_local_vars', array($hdq_local_vars));
?>
<div class="hdq_quiz_wrapper" id="hdq_<?php echo $quiz_ID; ?>">
<div class="hdq_before">
<?php do_action("hdq_before", $quiz_ID); ?>
</div>
<?php
hdq_print_quiz_start($quiz_settings["quiz_timer"]["value"], $use_adcode); ?>
<div class="hdq_quiz" <?php if ($quiz_settings["quiz_timer"]["value"] > 3 && $use_adcode !== true) {
echo 'style = "display:none;"';
} ?>>
<?php
if ($quiz_settings["results_position"]["value"] != "below") {
hdq_get_results($quiz_settings);
}
// Query through questions
wp_reset_postdata();
wp_reset_query();
global $post;
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
// WP_Query arguments
$args = array(
'post_type' => array('post_type_questionna'),
'tax_query' => array(
array(
'taxonomy' => 'quiz',
'terms' => $quiz_ID,
),
),
'pagination' => $paginate, // true or false
'posts_per_page' => $per_page, // also used for the pool of questions
'paged' => $paged,
'orderby' => $question_order, // defaults to menu_order
'order' => 'ASC',
);
$query = new WP_Query($args);
$i = 0; // question counter;
// figure out the starting question number (for WP Pagination)
$questionNumber = 0;
if ($per_page >= 1 && $paged > 1) {
$questionNumber = ($paged * $per_page) - $per_page + 1;
}
// The Loop
if ($query->have_posts()) {
while ($query->have_posts()) {
$query->the_post();
$i++;
$question_ID = get_the_ID();
$question = get_hdq_question($question_ID);
if ($question["paginate"]["value"][0] === "yes") {
$jPaginate = true;
hdq_print_jPaginate($quiz_ID);
}
// used to add custom data attributes to questions
$extra = apply_filters('hdq_extra_question_data', array(), $question, $quiz_ID);
$extra_data = "";
foreach($extra as $k => $d){
$extra_data = "data-".$k.'="'.$d.'" ';
}
$extra_data = sanitize_text_field($extra_data);
echo '<div class = "hdq_question" '.$extra_data.' data-type = "' . $question["question_type"]["value"] . '" id = "hdq_question_' . $question_ID . '">';
hdq_print_question_featured_image($question);
do_action("hdq_after_featured_image", $question);
// deal with randomized answer order here,
// so that you don't have to in your custom question type functions
$ans_cor = hdq_get_question_answers($question["answers"]["value"], $question["selected"]["value"], $quiz_settings["randomize_answers"]["value"][0]);
$question["answers"]["value"] = $ans_cor;
if ($question["question_type"]["value"] === "multiple_choice_text") {
hdq_multiple_choice_text_edit($question_ID, $i, $question, $quiz_settings);
} elseif ($question["question_type"]["value"] === "multiple_choice_image") {
hdq_multiple_choice_image_edit($question_ID, $i, $question, $quiz_settings);
} elseif ($question["question_type"]["value"] === "text_based") {
hdq_text_based_edit($question_ID, $i, $question, $quiz_settings);
} elseif ($question["question_type"]["value"] === "title") {
$i = $i - 1; // don't count this as a question
hdq_title($question_ID, $i, $question, $quiz_settings);
} elseif ($question["question_type"]["value"] === "select_all_apply_text") {
hdq_select_all_apply_text_edit($question_ID, $i, $question, $quiz_settings);
} else {
// TODO: Allow custom question types to be hookable
echo "Question type not found";
}
hdq_print_question_extra_text($question);
echo '</div>';
if ($use_adcode) {
if ($i % 5 == 0 && $i != 0) {
echo '<div class = "hdq_adset_container">';
echo $hdq_adcode;
echo '</div>';
}
}
}
}
wp_reset_postdata();
if ($query->max_num_pages > 1 || $per_page != "-1") {
if (isset($_GET['currentScore'])) {
echo '<input type = "hidden" id = "hdq_current_score" value = "' . intval($_GET['currentScore']) . '"/>';
}
if (isset($_GET['totalQuestions'])) {
echo '<input type = "hidden" id = "hdq_total_questions" value = "' . intval($_GET['totalQuestions']) . '"/>';
}
if ($quiz_settings["pool_of_questions"]["value"] == 0 || $quiz_settings["pool_of_questions"]["value"] == "") {
if ($query->max_num_pages != $paged) {
hdq_print_next($quiz_ID, $paged);
}
if ($query->max_num_pages == $paged) {
hdq_print_finish($quiz_ID, $jPaginate);
}
} else {
hdq_print_finish($quiz_ID, $jPaginate);
}
} else {
hdq_print_finish($quiz_ID, $jPaginate);
}
if ($quiz_settings["results_position"]["value"] == "below") {
hdq_get_results($quiz_settings);
} ?>
</div>
<div class="hdq_after">
<?php do_action("hdq_after", $quiz_ID); ?>
</div>
<div class="hdq_loading_bar"></div>
</div>
<?php
}
?>
C:\xampp\htdocs\wordpress5\wp-content\plugins\hd-quiz\class-gamajo-template-loader.php
<?php
/**
* Template Loader for Plugins.
*
* @package Gamajo_Template_Loader
* @author Gary Jones
* @link http://github.com/GaryJones/Gamajo-Template-Loader
* @copyright 2013 Gary Jones
* @license GPL-2.0+
*/
/**
* Template loader.
*
* Originally based on functions in Easy Digital Downloads (thanks Pippin!).
*
* When using in a plugin, create a new class that extends this one and just overrides the properties.
*
* @package Gamajo_Template_Loader
* @author Gary Jones
*/
class Gamajo_Template_Loader {
/**
* Prefix for filter names.
*
* @since 1.0.0
* @type string
*/
protected $filter_prefix = 'your_plugin';
/**
* Directory name where custom templates for this plugin should be found in the theme.
*
* @since 1.0.0
* @type string
*/
protected $theme_template_directory = 'your-plugin'; // or 'your-plugin-templates' etc.
/**
* Reference to the root directory path of this plugin.
*
* Can either be a defined constant, or a relative reference from where the subclass lives.
*
* @since 1.0.0
* @type string
*/
protected $plugin_directory = "YOUR_PLUGIN_DIR"; // or plugin_dir_path( dirname( __FILE__ ) ); etc.
/**
* Retrieve a template part.
*
* @since 1.0.0
*
* @uses Gamajo_Template_Loader::get_template_possble_parts() Create file names of templates.
* @uses Gamajo_Template_Loader::locate_template() Retrieve the name of the highest priority template
* file that exists.
*
* @param string $slug
* @param string $name Optional. Default null.
* @param bool $load Optional. Default true.
*
* @return string
*/
public function get_template_part( $slug, $name = null, $load = true ) {
// Execute code for this part
do_action( 'get_template_part_' . $slug, $slug, $name );
// Get files names of templates, for given slug and name.
$templates = $this->get_template_file_names( $slug, $name );
// Return the part that is found
return $this->locate_template( $templates, $load, false );
}
/**
* Given a slug and optional name, create the file names of templates.
*
* @since 1.0.0
*
* @param string $slug
* @param string $name
*
* @return array
*/
protected function get_template_file_names( $slug, $name ) {
if ( isset( $name ) ) {
$templates[] = $slug . '-' . $name . '.php';
}
$templates[] = $slug . '.php';
/**
* Allow template choices to be filtered.
*
* The resulting array should be in the order of most specific first, to least specific last.
* e.g. 0 => recipe-instructions.php, 1 => recipe.php
*
* @since 1.0.0
*
* @param array $templates Names of template files that should be looked for, for given slug and name.
* @param string $slug Template slug.
* @param string $name Template name.
*/
return apply_filters( $this->filter_prefix . '_get_template_part', $templates, $slug, $name );
}
/**
* Retrieve the name of the highest priority template file that exists.
*
* Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which
* inherit from a parent theme can just overload one file. If the template is
* not found in either of those, it looks in the theme-compat folder last.
*
* @since 1.0.0
*
* @uses Gamajo_Tech_Loader::get_template_paths() Return a list of paths to check for template locations.
*
* @param string|array $template_names Template file(s) to search for, in order.
* @param bool $load If true the template file will be loaded if it is found.
* @param bool $require_once Whether to require_once or require. Default true.
* Has no effect if $load is false.
*
* @return string The template filename if one is located.
*/
protected function locate_template( $template_names, $load = false, $require_once = true ) {
// No file found yet
$located = false;
// Remove empty entries
$template_names = array_filter( (array) $template_names );
// Try to find a template file
foreach ( $template_names as $template_name ) {
// Trim off any slashes from the template name
$template_name = ltrim( $template_name, '/' );
// Try locating this template file by looping through the template paths
foreach ( $this->get_template_paths() as $template_path ) {
if ( file_exists( $template_path . $template_name ) ) {
$located = $template_path . $template_name;
break;
}
}
}
if ( $load && $located ) {
load_template( $located, $require_once );
}
return $located;
}
/**
* Return a list of paths to check for template locations.
*
* Default is to check in a child theme (if relevant) before a parent theme, so that themes which inherit from a
* parent theme can just overload one file. If the template is not found in either of those, it looks in the
* theme-compat folder last.
*
* @since 1.0.0
*
* @return mixed|void
*/
protected function get_template_paths() {
$theme_directory = trailingslashit( $this->theme_template_directory );
$file_paths = array(
10 => trailingslashit( get_template_directory() ) . $theme_directory,
100 => $this->get_templates_dir()
);
// Only add this conditionally, so non-child themes don't redundantly check active theme twice.
if ( is_child_theme() ) {
$file_paths[1] = trailingslashit( get_stylesheet_directory() ) . $theme_directory;
}
/**
* Allow ordered list of template paths to be amended.
*
* @since 1.0.0
*
* @param array $var Default is directory in child theme at index 1, parent theme at 10, and plugin at 100.
*/
$file_paths = apply_filters( $this->filter_prefix . '_template_paths', $file_paths );
// sort the file paths based on priority
ksort( $file_paths, SORT_NUMERIC );
return array_map( 'trailingslashit', $file_paths );
}
/**
* Return the path to the templates directory in this plugin.
*
* May be overridden in subclass.
*
* @since 1.0.0
*
* @return string
*/
protected function get_templates_dir() {
return $this->plugin_directory . 'templates';
}
}
C:\xampp\htdocs\wordpress5\wp-content\plugins\hd-quiz\class-pw-template-loader.php
<?php
/**
* Template loader for PW Sample Plugin.
*
* Only need to specify class properties here.
*
*/
class PW_Template_Loader extends Gamajo_Template_Loader {
/**
* Prefix for filter names.
*
* @since 1.0.0
* @type string
*/
protected $filter_prefix = 'pw';
/**
* Directory name where custom templates for this plugin should be found in the theme.
*
* @since 1.0.0
* @type string
*/
protected $theme_template_directory = 'pw-templates';
/**
* Reference to the root directory path of this plugin.
*
* @since 1.0.0
* @type string
*/
protected $plugin_directory = PW_SAMPLE_PLUGIN_DIR;
}
C:\xampp\htdocs\wordpress5\wp-content\themes\twentytwentyone-child\pw-templates\image.php
<?php
// question type template
// multiple choice image
// print question title
hdq_print_question_title($question_number, $question);
// print out answers
$answers = $question["answers"]["value"];
echo '<div class = "hdq_answers">';
echo '<div class = "hdq_question_answers_images ggggggg4">';
for ($i = 0; $i < @count($answers); $i++) {
if ($answers[$i]["answer"] != "" && $answers[$i]["answer"] != null) {
$selected = 0;
if ($answers[$i]["correct"]) {
$selected = 1;
}
if($i === 0) {
?>
<div class = "hdq_row hdq_row_image one">
<label role = "button" aria-labelledby = "hda_label_<?php echo $i . '_' . $question_ID; ?>" id = "hda_label_<?php echo $i . '_' . $question_ID; ?>" class="hdq_label_answer" data-type = "image" data-id = "hdq_question_<?php echo $question_ID; ?>" for="hdq_option_<?php echo $i . '_' . $question_ID; ?>">
<?php
$image = "";
if ($answers[$i]["image"] != "" && $answers[$i]["image"] != 0) {
$image = hdq_get_answer_image_url($answers[$i]["image"]);
}
if ($image != "" && $image != null) {
echo '<img src = "'.$image.'" alt = "'.htmlentities($answers[$i]["answer"]).'"/>';
} ?>
<div>
<div class="hdq-options-check">
<input type="checkbox" autocomplete="off" data-id = "<?php echo $question_ID; ?>" class="hdq_option hdq_check_input" data-type = "image" value="<?php echo $selected; ?>" name="hdq_option_<?php echo $i . '_' . $question_ID; ?>" id="hdq_option_<?php echo $i . '_' . $question_ID; ?>">
<span class = "hdq_toggle"><span class = "hdq_aria_label"><?php echo $answers[$i]["answer"]; ?></span></span>
</div>
<?php echo $answers[$i]["answer"]; ?>
</div>
</label>
</div>
<?php
}else {
?>
<div class = "hdq_row hdq_row_image">
<label role = "button" aria-labelledby = "hda_label_<?php echo $i . '_' . $question_ID; ?>" id = "hda_label_<?php echo $i . '_' . $question_ID; ?>" class="hdq_label_answer" data-type = "image" data-id = "hdq_question_<?php echo $question_ID; ?>" for="hdq_option_<?php echo $i . '_' . $question_ID; ?>">
<?php
$image = "";
if ($answers[$i]["image"] != "" && $answers[$i]["image"] != 0) {
$image = hdq_get_answer_image_url($answers[$i]["image"]);
}
if ($image != "" && $image != null) {
echo '<img src = "'.$image.'" alt = "'.htmlentities($answers[$i]["answer"]).'"/>';
}
?>
<div>
<div class="hdq-options-check">
<input type="checkbox" autocomplete="off" data-id = "<?php echo $question_ID; ?>" class="hdq_option hdq_check_input" data-type = "image" value="<?php echo $selected; ?>" name="hdq_option_<?php echo $i . '_' . $question_ID; ?>" id="hdq_option_<?php echo $i . '_' . $question_ID; ?>">
<span class = "hdq_toggle"><span class = "hdq_aria_label"><?php echo $answers[$i]["answer"]; ?></span></span>
</div>
<?php echo $answers[$i]["answer"]; ?>
</div>
</label>
</div>
<?php
}
}
}
echo '</div>';
echo '</div>';
Ví dụ 2.2:
C:\xampp\htdocs\wordpress5\wp-content\themes\twentytwentyone-child\functions.php
<?php
// Lionel
define('PW_SAMPLE_PLUGIN_DIR', WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . "hd-quiz". DIRECTORY_SEPARATOR);
if (!class_exists('Gamajo_Template_Loader')) {
require PW_SAMPLE_PLUGIN_DIR . 'class-gamajo-template-loader.php';
}
require PW_SAMPLE_PLUGIN_DIR . 'class-pw-template-loader.php';
function hdq_add_shortcode_edit($atts) {
// Attributes
extract(
shortcode_atts(
array(
'quiz' => '',
),
$atts
)
);
// Code
ob_start();
include PW_SAMPLE_PLUGIN_DIR . 'includes/template-edit.php';
return ob_get_clean();
}
add_shortcode('HDquizs', 'hdq_add_shortcode_edit', 30);
// Lionel
?>
Gamajo Template Loader
A class to copy into your WordPress plugin, to allow loading template parts with fallback through the child theme > parent theme > plugin.
Description
Easy Digital Downloads, WooCommerce, and Events Calendar plugins, amongst others, allow you to add files to your theme to override the default templates that come with the plugin. As a developer, adding this convenience in to your own plugin can be a little tricky.
The get_template_part()
function in WordPress was never really designed with plugins in mind, since it relies on locate_template()
which only checks child and parent themes. So we can add in a final fallback that uses the templates in the plugin, we have to use a custom locate_template()
function, and a custom get_template_part()
function. The solution here just wraps them up as a class for convenience.
Installation
This isn't a WordPress plugin on its own, so the usual instructions don't apply. Instead:
Manually install class
Copy
class-gamajo-template-loader.php
into your plugin. It can be into a file in the plugin root, or better, anincludes
directory.
or:
Install class via Composer
Tell Composer to install this class as a dependency:
composer require gamajo/template-loader
Recommended: Install the Mozart package:
composer require coenjacobs/mozart --dev
and configure it.The class is now renamed to use your own prefix, to prevent collisions with other plugins bundling this class.
Implement class
Create a new file, such as
class-your-plugin-template-loader.php
, in the same directory.Create a class in that file that extends
Gamajo_Template_Loader
(or the new prefixed name, if you installed via Composer/Mozart). You can see the Meal Planner Template Loader example class below as a starting point if it helps.Override the class properties to suit your plugin. You could also override the
get_templates_dir()
method if it isn't right for you.You can now instantiate your custom template loader class, and use it to call the
get_template_part()
method. This could be within a shortcode callback, or something you want theme developers to include in their files.
// Template loader instantiated elsewhere, such as the main plugin file.
$meal_planner_template_loader = new Meal_Planner_Template_Loader;
Use it to call the
get_template_part()
method. This could be within a shortcode callback, or something you want theme developers to include in their files.$meal_planner_template_loader->get_template_part( 'recipe' );
If you want to pass data to the template, call the
set_template_data()
method with an array before callingget_template_part()
.set_template_data()
returns the loader object to allow for method chaining.$data = array( 'foo' => 'bar', 'baz' => 'boom' ); $meal_planner_template_loader ->set_template_data( $data ); ->get_template_part( 'recipe' );
The value of
bar
is now available inside the recipe template as$data->foo
.If you wish to use a different variable name, add a second parameter to
set_template_data()
:$data = array( 'foo' => 'bar', 'baz' => 'boom' ); $meal_planner_template_loader ->set_template_data( $data, 'context' ) ->get_template_part( 'recipe', 'ingredients' );
The value of
bar
is now available inside the recipe template as$context->foo
.This will try to load up
wp-content/themes/my-theme/meal-planner/recipe-ingredients.php
, orwp-content/themes/my-theme/meal-planner/recipe.php
, then fallback towp-content/plugins/meal-planner/templates/recipe-ingredients.php
orwp-content/plugins/meal-planner/templates/recipe.php
.
Meal Planner Example Class
<?php
/**
* Meal Planner
*
* @package Meal_Planner
* @author Gary Jones
* @link http://example.com/meal-planner
* @copyright 2013 Gary Jones
* @license GPL-2.0+
*/
if ( ! class_exists( 'Gamajo_Template_Loader' ) ) {
require plugin_dir_path( __FILE__ ) . 'class-gamajo-template-loader.php';
}
/**
* Template loader for Meal Planner.
*
* Only need to specify class properties here.
*
* @package Meal_Planner
* @author Gary Jones
*/
class Meal_Planner_Template_Loader extends Gamajo_Template_Loader {
/**
* Prefix for filter names.
*
* @since 1.0.0
*
* @var string
*/
protected $filter_prefix = 'meal_planner';
/**
* Directory name where custom templates for this plugin should be found in the theme.
*
* @since 1.0.0
*
* @var string
*/
protected $theme_template_directory = 'meal-planner';
/**
* Reference to the root directory path of this plugin.
*
* Can either be a defined constant, or a relative reference from where the subclass lives.
*
* In this case, `MEAL_PLANNER_PLUGIN_DIR` would be defined in the root plugin file as:
*
* ~~~
* define( 'MEAL_PLANNER_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
* ~~~
*
* @since 1.0.0
*
* @var string
*/
protected $plugin_directory = MEAL_PLANNER_PLUGIN_DIR;
/**
* Directory name where templates are found in this plugin.
*
* Can either be a defined constant, or a relative reference from where the subclass lives.
*
* e.g. 'templates' or 'includes/templates', etc.
*
* @since 1.1.0
*
* @var string
*/
protected $plugin_template_directory = 'templates';
}
Usage Example
The Cue plugin from AudioTheme uses this class. Starting at https://github.com/AudioTheme/cue/tree/develop/includes, it has this class in the vendor directory, then the required subclass of my class in the class-cue-template-loader.php
file, which sets a few basic properties. It also has a template in https://github.com/AudioTheme/cue/tree/develop/templates.
If you wanted the playlist to have different markup for your theme, you'd copy templates/playlist.php
to wp-content/themes/{your-active-theme}/cue/playlist.php
and do whatever changes you wanted. WordPress will look for that file first, before then checking a parent theme location (if your active theme is a child theme), before falling back to the default template that comes with the Cue plugin.
Change Log
See the change log.
License
Contributions
Contributions are welcome - fork, fix and send pull requests against the develop
branch please.
Credits
Built by Gary Jones Copyright 2013 Gary Jones
Last updated
Was this helpful?