PHPackages                             qtgye/wp-template-wrapper - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. qtgye/wp-template-wrapper

ActiveLibrary[Templating &amp; Views](/categories/templating)

qtgye/wp-template-wrapper
=========================

A better way to organize Wordpress templates.

0.1.2(9y ago)411PHP

Since May 26Pushed 8y agoCompare

[ Source](https://github.com/qtgye/wp-template-wrapper)[ Packagist](https://packagist.org/packages/qtgye/wp-template-wrapper)[ RSS](/packages/qtgye-wp-template-wrapper/feed)WikiDiscussions master Synced 3w ago

READMEChangelogDependenciesVersions (4)Used By (0)

WP Template Wrapper
===================

[](#wp-template-wrapper)

A better way to develop Wordpress templates.

Features
--------

[](#features)

- [Organized Template Files](#template-files)
- [Template Based Routing](#routes)
- [Template Wrapper](#wrapper)
- [Template Includes](#template-includes)
- [Template Data](#template-data)
- [AJAX Routes](#ajax-routes)

Organized Template Files
------------------------

[](#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-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 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.

In general, files are organized by `{type}/{slug|id|custom-name}.php` format.

---

### Custom Page Templates

[](#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 the `page-templates` folder as a registry, containing only the template name.
> Create another one in the `templates/page` folder as a "view". This will be the one rendering your view.

Template Based Routing
----------------------

[](#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
----------------

[](#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.

Template Includes
-----------------

[](#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;

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:

```
// 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
-------------

[](#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

[](#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
-----------

[](#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:

[](#todos)

- \[\] Multiple wrappers

###  Health Score

25

—

LowBetter than 36% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

3

Last Release

3319d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/11515934?v=4)[Jayson Buquia](/maintainers/qtgye)[@qtgye](https://github.com/qtgye)

---

Top Contributors

[![qtgye](https://avatars.githubusercontent.com/u/11515934?v=4)](https://github.com/qtgye "qtgye (13 commits)")

### Embed Badge

![Health badge](/badges/qtgye-wp-template-wrapper/health.svg)

```
[![Health](https://phpackages.com/badges/qtgye-wp-template-wrapper/health.svg)](https://phpackages.com/packages/qtgye-wp-template-wrapper)
```

###  Alternatives

[limenius/react-bundle

Client and Server-side react rendering in a Symfony Bundle

3861.2M](/packages/limenius-react-bundle)[area17/laravel-auto-head-tags

Laravel Auto Head Tags helps you build the list of head elements for your app

4616.0k](/packages/area17-laravel-auto-head-tags)[jelix/wikirenderer

WikiRenderer is a library to generate HTML or anything else from wiki content.

1712.2k1](/packages/jelix-wikirenderer)[webkinder/sproutset

A Composer package for handling responsive images in Roots Bedrock + Sage + Blade projects.

281.8k](/packages/webkinder-sproutset)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
