My experience developing in WordPress is that the callback orientation of hooks allow developers to design any structure to a theme, easilly turning it into a mess, and for the cases of complex websites, a huge mess. That way it's dificult to know how a theme works with WordPress.
Trying to solve this problem, the proposal is to change the WordPress behavior always the same way. This simple structure aims to be a guideline for complex WordPress themes with lots of queries and custom rewrite rules by relying in the MVC architecture, then you can explicitly define where, how and when queries are chosen and executed.
Translating from the Wordpress theme dictionary, we get something like this:
- Model: Custom post types and taxonomies used by the theme;
- View: WordPress templates of the theme according to the template hierarchy;
- Controller: The rewrite rules and query variables.
Organize your post types and taxonomies inside the models
directory,
declaring each one of them in its<entity>.php
file. All files in this
directory will be automatically included.
To link queries from URLs to views you'll use the router.php
file:
-
Define a rewrite rule in the
_query_rules
function:return array( '^sample-rule/([^/]+)/?$' => 'custom_query=$matches[1]', // sample rule // another rule here // one more rule here // .. );
-
Create a variable in the
$_query
object in the_init_query_object
function:$_query = (object) array( // built-in template var 'template' = false, // My custom query 'custom_query' = false, /* other variables here ... */ );
-
Define the condition to use this variable in the
_query_processor
function.function _query_processor( &$query ) { global $_query, $post, $wpdb, $wp_query; /* other conditions /* } elseif ( $custom_query = get_query_var( 'custom_query' ) ) { /* Define the template to be used. If left to false, then WordPress will choose the template */ $_query->template = 'custom-template'; /* Define a new query maybe ysing $custom_query */ $args = array( /* custom args */ ); $_query->custom_query = new WP_Query( $args ); } }
Like this, the custom-template.php
will be loaded with the $_query
object
containing a $_query->custom_query
attribute to be used.
<?php global $_query; ?>
<?php wp_header(); ?>
<!-- lots of stuff here -->
<?php if ( $_query->custom_query->have_posts() ) : ?>
<?php while ( $_query->custom_query->have_posts() ) : ?>
<?php $_query->custom_query->the_post(); ?>
<!-- post loop like any other -->
<?php endwhile; ?>
<?php else : ?>
<p><code>$_query->custom_query</code> has no posts.</p>
<?php endif; ?>
<?php wp_footer(); ?>
So, using these guidelines also implies in some rules for developers:
- Never make queries or any theme logic outside the
_query_processor
. Always use an attribute of$_query
to pass data to the templates. - Always use the
$_query->template
attribute to define wich template will be loaded, and set it in thequery_processor
to be explicit wether you want WordPress to choose it or not.