qtgye / wp-template-wrapper
A better way to organize Wordpress templates.
This package is not auto-updated.
Last update: 2025-05-17 03:37:50 UTC
README
A better way to develop Wordpress templates.
Features
- Organized Template Files
- Template Based Routing
- Template Wrapper
- Template Includes
- Template Data
- AJAX Routes
Organized Template Files
All the template files reside in the templates
folder.
Any template files at the theme's root folder will not work
Template Slug
Template Wrapper transforms wordpress's default template file naming to provide better organization of the files.
'Slugged' template files, i.e. single-{post_type|post_name|post_id}
etc., are grouped in a subdirectory named to that type.
Example:
templates/single/post.php
will be used in place ofsingle-post.php
.templates/page/about-us.php
will be used in place ofpage-about-us.php
.templates/archive/4.php
will be used in place ofarchive-4.php
.- Template-type files will still be used as is; e.g.,
templates/single.php
,templates/page.php
, etc.
In general, files are organized by {type}/{slug|id|custom-name}.php
format.
Custom Page Templates
Custom page templates should be placed in the templates
folder.
Template Wrapper uses custom page template files only for registration in the admin.
That is, custom page template files will not be used as "views".
You have to create a file of the same name in the templates/page
folder.
Example:
To use a custom "Donate Page Template" using
custom-donate-page.php
,
Create one in thepage-templates
folder as a registry, containing only the template name.
Create another one in thetemplates/page
folder as a "view". This will be the one rendering your view.
Template Based Routing
Template Wrapper allows route registration through template_routes
hook.
Routes are placed in src/routes.php
in the following manner:
// src/routes.php add_filter( 'template_routes', function () { return array( $template_slug => $callable, ); });
$template_slug (String)
The "route" to the template slug. This is similar to the Wordpress's template hierarchy, though transformed to become directory-based.
$callable (Function or Object/Class Method)
The "controller". This will handle the data passed to the template. This can be either a function or an object/class method, similar to MVC approach.
Example:
// Matches is_single(), using a function name
'single' => 'post_data',
// Matches 'project' post type single, Using a static class method
'single/project' => [ 'MyControllerClass', 'project_single' ],
// Matches single for a post_id of 12
'single/12' => [ 'MyControllerClass', 'project_single' ],
// Will match about page, using a namespaced class method
'page/about' => [ '\\MyNamespace\\AnotherController', 'about' ],
// Will match a custom page template registered in `page-templates/custom-page.php`
'page/custom-page' => [ 'MyControllerClass', 'custom_page_data' ],
// Will match any page or single which is not registered in route
'page' => 'any_page_data',
'single' => 'any_single_data',
Note:
A "slugged" route doesnt require a template counterpart. Just like wordpress's template hierarchy, it will use the available template for that slug.
That is, a page/about
route will use templates/page.php
if templates/page/about.php
is not available.
Template Wrapper
This is inspired by scribu's theme wrapper which also implemented in Sage starter themes.
It allows you to have your main layout in wrapper.php
, and the main template will be automatically wrapped with it.
It prevents code repition caused by using get_header()
or get_footer()
at each main template.
Template Includes
The Template Wrapper provides a way to include templates and passing data through include_template
method of the Wrapper
class.
// single.php use QtGye\TemplateWrapper\Wrapper; <h1>This is an awesome post!</h1> <?php Wrapper::include_template( 'modules/content', $content_data ); ?>
To avoid having to declare Wrapper's namespace in every template, it is recommended to wrap it in a global function instead, like so:
// functions.php function include_template ( $template_slug ='', $data = [] ) { QtGye\TemplateWrapper\Wrapper::include_template( $template_slug, $data ); }
$template_slug (String)
The slug of the template file relative to the templates folder. In the example, it will load
templates/modules/content.php
.
$data (Assoc. Array)
The data to be passed into the included template. Note that user-defined globals are also available in the included templates, so if there are common variable names, the template data will override it.
Template Data
The route callable handles the data being passed to the template. Through reflection, the callable may receive user-defined globals as arguments.
Example:
class MyControllerClass { // Using the $post global static function about_page ( $post ) { $data = []; $data['id'] = $post->ID; $data['slug'] = $post->name; // The variables $id and $slug are now available in the template return $data; } }
Global Data
The user-defined global data is defined in the src/global.php
through the template_global_data
hook. These globals are available within templates.
Example:
// src/global.php add_filter('template_global_data', function ( $predefined_globals ) { // For some reason, use $wp_roles global global $wp_roles; // $wp_roles variable is now ready to be used in the templates return compact('wp_roles'); });
Template Wrapper provides pre-defined globals to which user-defined globals are merged:
$wp, $wpdb, $wp_query, $post, $authordata, $page;
AJAX Routes
Template Wrapper provides a way to handle ajax routing using action.
Register ajax routes through the ajax_routes
hook.
// src/routes.php add_action( 'ajax_routes', function () { return array( // Matches ?action=items 'items' => [ "MyController", "ajax" ], ); });
Within the ajax callback, GET parameters and user-defined globals are passed through reflection.
class MyController { // Handling ?action=items&filter=all&page=3 // The argument names should match the GET parameter names. Hence, order is irrelevant. static function ajax ( $page, $filter, $post ) { // $filter === 'all' // $page === '3' $response = [ 'items' => get_filtered_posts( $filter, $page), 'current_id' => $post->ID, ]; // Returned data is sent as json-encoded response. return $response; } }
TODOs:
- [] Multiple wrappers