Skip to content

Instantly share code, notes, and snippets.

@joaquinrfs
Forked from eric1234/README.md
Created December 28, 2022 08:58
Show Gist options
  • Save joaquinrfs/6334979f637af2c71b7acf1a00ceac56 to your computer and use it in GitHub Desktop.
Save joaquinrfs/6334979f637af2c71b7acf1a00ceac56 to your computer and use it in GitHub Desktop.
A better way of doing layouts in PHP

Usage

Creating a Layout File

Create a file called layout.php. Where you want the content to appear add <?php echo $content ?>. Here is an example:

<!DOCTYPE html>
<html>

<head>
  <title><?php echo $title ?></title>
</head>

<body>
  <div id="page">
    <?php echo $content ?>
  </div>
</body>
</html>

This should be placed in the same directory a your scripts.

Using the Layout File

Now just add the following to the top of every script (or some include the scripts pull in):

<?php require_once 'lib/layout.php'; ?>
My page content. This will be placed where $content is.

Any content outputted in your script will be placed where $content is outputted. Note I call the default layout file layout.php but also the file you are including is called layout.php. This is why I put it in the lib directory. To differentiate it. The one in your root directory is your layout content. The one in the lib directory is the one attached to this gist that does the magic.

Configuration

The $title variable is automatically pulled into the layout scope. To set the title simply place the following in your script:

<?php $title = 'Home page' ?>

You can place this before or after the layout require.

If you want to change where the layout file is located just set the $layout variable before calling layout. For example:

<?php
  $layout = __DIR__.'/path/to/layout.php';
  require_once 'layout.php';
?>

Content Filters

This script provides an excellent opportunity to apply a filter to the entire output. Similar to an after_filter in Rails. Simply add a callback function to the global variable $content_filters. You can do this before the call to layout.php (so you are defining $content_filters or after by simply appending. Example:

<?php
  require_once 'layout.php';
  $content_filter[] = 'adjust_markup';
?>

The callback should take the HTML as input and return the final HTML. Content filters only apply to the $content and not the layout. Also if the layout is not used then the content filters are not called.

Handling Redirects

Redirects are automatically handled. If you set the Location header and exit the layout script will automatically avoid rendering the layout and instead just exit.

<?php
# https://gist.github.com/2151128
if( !array_key_exists('layout', get_defined_vars()) )
$layout = realpath('./layout.php');
if( $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest' ) $layout = null;
$use_layout = true;
if(is_null($layout)) $use_layout = false;
function apply_content_filters($in) {
global $content_filters;
foreach($content_filters as $filter) {
$in = call_user_func($filter, $in);
}
return $in;
}
if( !isset($content_filters) ) $content_filters = array();
if( $use_layout ) ob_start();
function layout_shutdown() {
global $layout;
global $use_layout;
global $error_triggered;
if( !$use_layout ) return;
$content = apply_content_filters(ob_get_contents());
ob_end_clean();
if( $error_triggered || is_null($layout) ) {
echo $content;
return;
}
foreach(headers_list() as $header)
if( preg_match('/^Location/', $header) ) return;
global $title;
require $layout;
}
register_shutdown_function('layout_shutdown');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment