document.write("
if(!defined('ABSPATH')) { die(); } /** * Plugin Name: Improved Template Hierarchy * Plugin URI: https://gschoppe.com/wordpress/better-template-hierarchy/ * Description: Implementation of suggested improvements to the WordPress Template Heirarchy * Author: Greg Schoppe * Author URI: https://gschoppe.com * Version: 1.1.0 **/ if( !class_exists('GJSImprovedTemplateHierarchy') ) { class GJSImprovedTemplateHierarchy { private static $persistently_cache; private static $cache_expiration = 1800; private $was_404 = false; private $custom_path_templates; private $current_template_path; private $theme; private $cache_hash; public static function Instance() { static $instance = null; if ($instance === null) { $instance = new self(); } return $instance; } private function __construct() { add_filter( 'init', array( $this, 'init') ); add_filter( 'pre_handle_404', array( $this, 'prevent_404_on_custom_path_templates' ) ); add_filter( 'redirect_canonical', array( $this, 'prevent_redirecting_custom_path_templates' ), 10, 2 ); add_filter( 'template_include', array( $this, 'insert_template_overrides' ), 0 ); } public function init() { // Initialize caching on first run. if ( ! isset( self::$persistently_cache ) ) { self::$persistently_cache = apply_filters( 'cache_custom_path_templates_persistently', false ); } $this->theme = wp_get_theme(); $this->cache_hash = md5( 'GJSImprovedTemplateHierarchy: ' . $this->theme->theme_root . '/' . $this->theme->stylesheet ); $this->populate_custom_path_templates(); } public function insert_template_overrides( $template ) { if( !apply_filters( 'disable_front_page_templates', false ) ) { if( is_front_page() && is_page() ) { $page_template = get_page_template_slug( get_the_ID() ); if( $page_template ) { $path = locate_template( $page_template ); if( $path ) { return $path; } } } } if( !apply_filters( 'disable_blog_template_file', false ) ) { if( is_home() ) { $path = locate_template( 'blog.php' ); if( $path ) { return $path; } } } if( !apply_filters( 'disable_custom_path_templates', false ) ) { if( $this->was_404 || apply_filters( 'force_custom_path_templates', false ) ) { $template_path = $this->get_current_template_path(); if( $template_path ) { add_filter( 'body_class', array( $this, 'add_template_body_classes' ) ); return $template_path; } } } return $template; } public function prevent_404_on_custom_path_templates( $short_circuit ) { global $wp_query; $template_path = $this->get_current_template_path(); if( $template_path ) { if( $wp_query->is_404 || ( property_exists( $wp_query, 'posts' ) && count( $wp_query->posts ) == 0 ) ) { $this->was_404 = true; } $wp_query->is_404 = false; status_header( 200 ); return true; } return $short_circuit; } public function prevent_redirecting_custom_path_templates( $new_url, $original_url ) { global $wp; if( $new_url ) { $request = add_query_arg( array(), $wp->request ); $request = trim( $request, '/' ); $slashed_request = '/' . $request . '/'; $canonical = get_site_url( null, $slashed_request); if( $canonical === $new_url ) { return $new_url; } $template_path = $this->get_current_template_path(); if( $template_path ) { if( $canonical !== $original_url ) { return $canonical; } else { return false; } } } return $new_url; } public function add_template_body_classes( $classes ) { $template_class = 'path-template-' . $this->get_current_template_slug(); $class_no_php = $template_class; if( substr( $class_no_php, -4 ) === '-php') { $class_no_php = substr( $class_no_php, 0, -4 ); } $new_classes = array( 'path-template', $template_class, $class_no_php ); return array_merge( $classes, $new_classes ); } // private functions private function populate_custom_path_templates() { $path_templates = $this->cache_get( 'custom_path_templates' ); if ( ! is_array( $path_templates ) ) { $path_templates = array(); $files = (array) wp_get_theme()->get_files( 'php', 1 ); foreach( $files as $file => $full_path ) { $header_template = array( 'path' => "Custom Path", 'subdirs' => "Parse Subdirectories" ); $header = get_file_data( $full_path, $header_template, 'custom_paths'); if( $header['path'] ) { $path = trim( $header['path'], '/' ); $path_templates[ $path ] = array( 'file' => $file, 'subdirs' => $this->is_truthy( $header['subdirs'] ) ); } } $this->cache_add( 'custom_path_templates', $path_templates ); } $this->custom_path_templates = $path_templates; } private function get_current_template_slug() { $path = $this->get_current_template_path(); $base = basename( $path ); $slug = sanitize_title( $base ); return $slug; } private function get_current_template_path() { global $wp; if( $this->current_template_path === null ) { $request = add_query_arg( array(), $wp->request ); $template_path = $this->get_matching_custom_template( $request ); $this->current_template_path = $template_path; } return $this->current_template_path; } private function get_matching_custom_template( $request ) { $request = trim( $request, '/' ); $path_parts = explode( '/', $request ); $templates = $this->custom_path_templates; $ancestor = false; while( $path_parts ) { $temp = implode( '/', $path_parts ); if( isset( $templates[$temp] ) ) { if( !$ancestor || $templates[$temp]['subdirs'] ) { $path = locate_template( $templates[$temp]['file'] ); if( $path ) { return $path; } } } $ancestor = true; array_pop( $path_parts ); } return false; } private function cache_get( $key ) { return wp_cache_get( $key . '-' . $this->cache_hash, 'GJSImprovedTemplateHierarchy' ); } private function cache_add( $key, $data ) { return wp_cache_add( $key . '-' . $this->cache_hash, $data, 'GJSImprovedTemplateHierarchy', self::$cache_expiration ); return false; } private function is_truthy( $value ) { $truthy_vals = array( 'true', 'yes' ); $truthy_vals = apply_filters( 'improved_template_hierarchy_truthy_values', $truthy_vals ); $value = trim( strtolower( $value ) ); $value = apply_filters( 'improved_template_hierarchy_truthy_test_value', $value ); return in_array( $value, $truthy_vals ); } } GJSImprovedTemplateHierarchy::Instance(); }