A better way to organize Wordpress templates.
A better way to develop Wordpress templates., (*1)
All the template files reside in the templates
folder.
Any template files at the theme's root folder will not work, (*3)
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., (*4)
Example:
- templates/single/post.php
will be used in place of single-post.php
.
- templates/page/about-us.php
will be used in place of page-about-us.php
.
- templates/archive/4.php
will be used in place of archive-4.php
.
- Template-type files will still be used as is; e.g., templates/single.php
, templates/page.php
, etc., (*5)
In general, files are organized by {type}/{slug|id|custom-name}.php
format., (*6)
Custom page templates should be placed in the templates
folder., (*7)
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., (*8)
Example:, (*9)
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., (*10)
Template Wrapper allows route registration through template_routes
hook.
Routes are placed in src/routes.php
in the following manner:, (*12)
// src/routes.php add_filter( 'template_routes', function () { return array( $template_slug => $callable, ); });
$template_slug (String), (*13)
The "route" to the template slug. This is similar to the Wordpress's template hierarchy, though transformed to become directory-based., (*14)
$callable (Function or Object/Class Method), (*15)
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., (*16)
Example:, (*17)
// 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. <a name="wrapper"></a> ## Template Wrapper This is inspired by **scribu**'s [theme wrapper](http://scribu.net/wordpress/theme-wrappers.html) 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. <a name="template-includes"></a> ## Template Includes The Template Wrapper provides a way to include templates and passing data through `include_template` method of the `Wrapper` class. ```php // single.php use QtGye\TemplateWrapper\Wrapper;This is an awesome post!
To avoid having to declare Wrapper's namespace in every template, it is recommended to wrap it in a global function instead, like so:, (*18)
// functions.php function include_template ( $template_slug ='', $data = [] ) { QtGye\TemplateWrapper\Wrapper::include_template( $template_slug, $data ); }
$template_slug (String), (*19)
The slug of the template file relative to the templates folder. In the example, it will load
templates/modules/content.php
., (*20)
$data (Assoc. Array), (*21)
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., (*22)
The route callable handles the data being passed to the template. Through reflection, the callable may receive user-defined globals as arguments., (*24)
Example: ```php class MyControllerClass {, (*25)
// 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; }
} ```, (*26)
The user-defined global data is defined in the src/global.php
through the template_global_data
hook. These globals are available within templates., (*27)
Example: ```php // src/global.php, (*28)
add_filter('template_global_data', function ( $predefined_globals ) { // For some reason, use $wp_roles global global $wp_roles;, (*29)
// $wp_roles variable is now ready to be used in the templates return compact('wp_roles');
}); ```, (*30)
Template Wrapper provides pre-defined globals to which user-defined globals are merged:
$wp, $wpdb, $wp_query, $post, $authordata, $page;, (*31)
Template Wrapper provides a way to handle ajax routing using action., (*33)
Register ajax routes through the ajax_routes
hook.
```php
// src/routes.php, (*34)
add_action( 'ajax_routes', function () { return array( // Matches ?action=items 'items' => [ "MyController", "ajax" ], ); });
```, (*35)
Within the ajax callback, GET parameters and user-defined globals are passed through reflection., (*36)
```php class MyController {, (*37)
// 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; }
} ```, (*38)