How to use the same layout template(s) both with and without WordPress

Premise

Say you have a website that you want to run partly with WordPress (say a Blog section) and partly without WordPress, using the same design. I’ll demonstrate a technique for using the same layout template(s) for WordPress content and other content without duplicating code, and in the process also demonstrate that it’s not necessary to use the header & footer include scheme that WordPress advocates.

I haven’t actually used this technique extensively yet, so consider it experimental and try it if you want.

The intended audience for this post is website developers, specifically those competent with PHP. I expect this to be most relevant to people using a custom design that has been turned into a WordPress theme.

You can use a template engine to implement this technique, such as my own, or just PHP arrays. I’ll demonstrate both.

Demo

There are demo files available using plain PHP and my templating engine. The demos assume that WordPress is installed in a blog subdirectory of your document root directory and that permalinks are enabled, e.g. so that pages can be linked to using the slug instead of the ID.

If you have such a WordPress setup, then you can do the following:

  • Merge the docroot directory from the chosen demo with your document root directory.
  • Activate “JMM Shared Layout Example” as your theme.

Otherwise you can adapt the demo files or instructions here to suit your environment.

Layout Templating

The typical WordPress theming process would be to take an HTML layout template and chop it up into fragments such as header.php, footer.php, and then include those fragments into the templates for pages, posts, etc.

I haven’t been a fan of the header & footer include scheme, whether using WordPress or not. Rather than interpolate template HTML into content, I’ve preferred to interpolate content into templates.

The first step in this technique is to create a layout template, call it layout.php or whatever you like. That will serve part of the purpose of WordPress’s header.php and footer.php, and another file, wordpress-layout.php will serve the rest of the purpose.

Put all of the HTML that is used for the layout / design of your site into layout.php. Don’t include any content for a specific page or post, or any code that relies on WordPress, such as calls to wp_head() or wp_footer().

In the simplest case, you’ll wind up with something like this (I’ve included comments as placeholders):


<!DOCTYPE html>

<html lang="en-US">

<head>

<meta http-equiv="Content-Type" content="text/plain; charset=UTF-8" />

<title><!-- UNIQUE-TITLE --></title>

<!-- UNIQUE-HEAD-CONTENT -->

</head>


<body>

<!-- UNIQUE-PRIMARY-CONTENT -->

</body>

</html>

“Static” Content

Now, for content, we’ll start with a “static” page not served by WordPress.

Notice that this script starts off by including an init.php script. I’ll explain that in the next section.

Here is what your content pages will look like:

<?php

require_once "{$_SERVER[ 'DOCUMENT_ROOT' ]}/init.php";


$config[ 'site-section' ] = 'contact';


$content[ 'title' ] = "Contact Us";


ob_start();

?>

<link rel="stylesheet" type="text/css" media="all" href="rsrc/contact.css" />

<?php

$content[ 'head' ] = ob_get_clean();


$content[ 'primary-content-heading' ] = $content[ 'title' ];


ob_start();

?>

<p>
This is the Contact page primary content.
</p>

<p>
The quick brown fox jumps over the lazy dog.  The quick brown fox jumps over the lazy dog.  The quick brown fox jumps over the lazy dog.  The quick brown fox jumps over the lazy dog.
</p>

<?php

$content[ 'primary' ] = ob_get_clean();


ob_start();

?>

<p>

This is the Contact page secondary (sidebar) content.
</p>


<p>
Blah blah blah, blah blah.  Blah blah blah, blah blah.Blah blah blah, blah blah.Blah blah blah, blah blah.Blah blah blah, blah blah.
</p>

<?php

$content[ 'secondary' ] = ob_get_clean();


include ( SITE_TEMPLATES_PATH . "/layout.php" );


<?php

require_once "{$_SERVER[ 'DOCUMENT_ROOT' ]}/init.php";


$view->set_config_item( 'site-section', 'contact' );


$view->set_content_item( 'title', "Contact Us" );


$view->start_set_content_item( 'head' );

?>

<link rel="stylesheet" type="text/css" media="all" href="rsrc/contact.css" />

<?php

$view->end_set_content_item( 'head' );


$view->set_content_item( 'primary-content-heading', $view->get_content_item( 'title' ) );


$view->start_set_content_item( 'primary' );

?>

<p>
This is the Contact page primary content.
</p>

<p>
The quick brown fox jumps over the lazy dog.  The quick brown fox jumps over the lazy dog.  The quick brown fox jumps over the lazy dog.  The quick brown fox jumps over the lazy dog.
</p>

<?php

$view->end_set_content_item( 'primary' );


$view->start_set_content_item( 'secondary' );

?>

<p>
This is the Contact page secondary (sidebar) content.
</p>


<p>
Blah blah blah, blah blah.  Blah blah blah, blah blah.Blah blah blah, blah blah.Blah blah blah, blah blah.Blah blah blah, blah blah.
</p>

<?php

$view->end_set_content_item( 'secondary' );


echo $view->get_render( "layout.php" );



Here’s an example of a layout template that would go with that:


<!DOCTYPE html>

<html lang="<?php echo $content[ 'lang' ]; ?>">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $content[ 'charset' ]; ?>" />

<title><?php echo $content[ 'title' ]; ?></title>

<?php echo $content[ 'head' ]; ?>


</head>


<body>

<h1 id="SITE-primary-content-heading">
<?php echo $content[ 'primary-content-heading' ]; ?>

</h1>


<div id="SITE-primary-content">

<?php echo $content[ 'primary' ]; ?>

</div>
<!-- #SITE-primary-content -->

</body>

</html>


<!DOCTYPE html>

<html lang="<?php echo $view->get_content_item( 'lang' ); ?>">

<head>

<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $view->get_content_item( 'charset' ); ?>" />

<title><?php echo $view->get_content_item( 'title' ); ?></title>

<?php echo $view->get_content_item( 'head' ); ?>


</head>


<body>

<h1 id="SITE-primary-content-heading">
<?php echo $view->get_content_item( 'primary-content-heading' ); ?>

</h1>


<div id="SITE-primary-content">

<?php echo $view->get_content_item( 'primary' ); ?>


</div>
<!-- #SITE-primary-content -->

</body>

</html>


Init Script

init.php is for setting up default configuration parameters and content, and for initializing a template engine if you use one. Generally I treat data that is intended to be output in the HTML as “content”, and other data that is not intended to be output as “config”, but it’s not always totally cut and dry and often the distinction isn’t critical; it’s more for organizational purposes.

One thing I use config parameters for is to store data that influences the HTML that is generated, but that does not actually become part of the HTML. For example, I’ll often set a config param that identifies what section of a site a page belongs to, and then use that param to output a class for the navigation link that corresponds to that section, and style the class to highlight that link.

I recommend creating init.php and including it in all of your “static” content pages, and in the functions.php file of your WordPress theme. You can call init.php whatever you like and save it wherever you like, but your document root directory would be a reasonable choice.

Put any default content in init.php that you want to be accessible in your “static” content pages or in WordPress. You’ll be able to override any of it for the WordPress templates, and you don’t need to include anything that is only relevant to WordPress.

Here’s an example of what init.php would consist of:

<?php

define( 'SITE_TEMPLATES_PATH', "{$_SERVER[ 'DOCUMENT_ROOT' ]}/rsrc/site/templates" );


$config = array(
);
// array


$content = array(

  'charset' => 'UTF-8',

  'lang' => 'en-US',

  'text-dir' => 'ltr',

  'primary-stylesheet' => "/rsrc/site/site.css",

  'body-classes' => array(),

  'site-title' => "WordPress Layout Templating"

);
// array


<?php

define( 'SITE_TEMPLATES_PATH', "{$_SERVER[ 'DOCUMENT_ROOT' ]}/rsrc/site/templates" );


require_once "{$_SERVER[ 'DOCUMENT_ROOT' ]}/rsrc/site/lib/jmm-view/jmm-view.php";

$view = new JMM_View( array(

  '_views_path' => SITE_TEMPLATES_PATH,

  '_this_alias' => 'view'

) );


$view->set_content_items( array(

  'charset' => 'UTF-8',

  'lang' => 'en-US',

  'text-dir' => 'ltr',

  'primary-stylesheet' => "/rsrc/site/site.css",

  'body-classes' => array(),

  'site-title' => "WordPress Layout Templating"

) );


WordPress Templates

Now for the WordPress part. Your WordPress templates will not duplicate HTML / CSS from your layout templates. The WordPress templates will extract content from WordPress that will be inserted into the layout templates.

Setup your page / post templates like the content page example above, e.g. for a page:

<?php

$content[ 'title' ] = the_title( '', '', FALSE );

$content[ 'primary-content-heading' ] = $content[ 'title' ];


ob_start();


while ( have_posts() ) {

  the_post();

  $config[ 'site-section' ] = $post->post_name;

  the_content();

}
// while


$content[ 'primary' ] = ob_get_clean();


include locate_template( array( 'wordpress-layout.php' ) );


<?php

$view->set_content_item( 'title', the_title( '', '', FALSE ) );

$view->set_content_item( 'primary-content-heading', $view->get_content_item( 'title' ) );


$view->start_set_content_item( 'primary' );


while ( have_posts() ) {

  the_post();

  $view->set_config_item( 'site-section', $post->post_name );

  the_content();

}
// while


$view->end_set_content_item( 'primary' );


include locate_template( array( 'wordpress-layout.php' ) );


You can override any default config or content from init.php in those templates. But if the config or content needs to be overridden with the same value for multiple WordPress templates (e.g. you want the same config or content to apply to all WordPress-generated pages), it’s better to do it in a more central location.

Notice that instead of including the layout.php template shown before, this template includes wordpress-layout.php, which is the glue between the WordPress templates and layout.php. The purpose of wordpress-layout.php is to setup content and implement WordPress functionality that is relevant to all or several of your WordPress templates. At the end, wordpress-layout.php includes layout.php.

Possible examples of what you might do in wordpress-layout.php include: set the charset, add the blog name to page titles, set body classes, call wp_head() and wp_footer(), override default config or content from init.php that is relevant to multiple WordPress templates.

Here’s an example of what wordpress-layout.php might look like:

<?php

$config[ 'site-section' ] = $config[ 'site-section' ] ? $config[ 'site-section' ] : 'blog';


$content[ 'charset' ] = get_bloginfo( 'charset' );

$content[ 'lang' ] = get_bloginfo( 'language' );

$content[ 'text-dir' ] = get_bloginfo( 'text-direction' );

$content[ 'site-title' ] = get_bloginfo( 'name' );

$content[ 'title' ] = wp_title( '', FALSE );


$content[ 'primary-stylesheet' ] = get_stylesheet_directory_uri() . "/style.css";


$content[ 'body-classes' ] = get_body_class();


ob_start();

do_action( 'wp_head' );

$buffer = ob_get_clean();


$content[ 'head' ] = <<<DOCHERE

{$content[ 'head' ]}

{$buffer}

DOCHERE;


ob_start();

do_action( 'wp_footer' );

$content[ 'footer' ] = ob_get_clean();


include ( SITE_TEMPLATES_PATH . "/layout.php" );


<?php

$view->set_config_item( 'site-section', (

  $view->get_config_item( 'site-section' ) ?

  $view->get_config_item( 'site-section' ) :

  'blog'

) );


$view->set_content_item( 'charset', get_bloginfo( 'charset' ) );

$view->set_content_item( 'lang', get_bloginfo( 'language' ) );

$view->set_content_item( 'text-dir', get_bloginfo( 'text-direction' ) );

$view->set_content_item( 'site-title', get_bloginfo( 'name' ) );

$view->set_content_item( 'title', wp_title( '', FALSE ) );


$view->set_content_item( 'primary-stylesheet', ( get_stylesheet_directory_uri() . "/style.css" ) );


$view->set_content_item( 'body-classes', get_body_class() );


$view->start_set_content_item( 'head' );

echo $view->get_content_item( 'head' ) . "\n\n";

do_action( 'wp_head' );

$view->end_set_content_item( 'head' );


$view->start_set_content_item( 'footer' );

do_action( 'wp_footer' );

$view->end_set_content_item( 'footer' );


echo $view->get_render( "layout.php" );



wordpress-layout.php will be stored in the directory for your WordPress theme, so it does not actually have to be called that — it could just be called “layout.php” for example. I’m just using the name “wordpress-layout.php” in this article to clearly distinguish it from the non-WordPress layout.php template file (which could be called something else anyway).

Stylesheets

Save the stylesheet(s) for your layout template(s) wherever you like, then @import them in the style.css file for your WordPress theme. If you like, following the @import statement(s) you can add styles that are only relevant to WordPress content.


@import "/rsrc/site/site.css";


.widget {

  margin: 0 0 2em;

}

Including WordPress Templates

Notice that in some cases instead of using WordPress’s get_template_part() function, I’m using include locate_template(). That’s because the former changes the variable scope while the latter doesn’t.

Say you’re using plain PHP for your templating and you have a single.php template where you save some data in a $content array and then include a loop.php template. With get_template_part() your $content variable won’t be available in loop.php unless you access it via the global scope, e.g. $GLOBALS[ 'content' ]. With include locate_template(), $content will be in the local scope in loop.php.

Leave a Reply

Your email address will not be published. Required fields are marked *

Note: Comments are moderated. Spam comments will never be published.

Is this comment spam?