University of Missouri

Interface

Skip to search and archives

Tree analogy for includes

PHP includes with Cascade Server

Published on by Joshua Hughes | Posts by This Author

The University of Missouri makes heavy use of Hannon Hill’s Cascade Server, a XSLT-based content management system. This is a fairly advanced tutorial that assumes some basic familiarity with that product.

Now, one of the things that sets Cascade apart from other content management systems is it doesn’t build live pages on the fly. Changes to files and templates must be published out before they will be live on the server. The downside to this is that even a fairly minor edit, like changing contact information in the footer, may require your entire site to be republished. For a large site, this might take a significant amount of time.

Fortunately, there is a solution. We can move our boilerplate content to separate files, and instead configure Cascade to use PHP includes on the live site. I’d like to share my method for setting this up, using a site footer as an example.

Footer Include Setup Diagram

Diagram of the setup for PHP includes with Cascade. This is explained in detail below.

Include File Template

The first step is to create a template for files we’ll be including with PHP:

<include><system-region name="DEFAULT"/></include>

These files will just contain the content we attach to the DEFAULT region. The <include> is only there because valid XML requires a root node. We’ll be stripping it out later on.

Configuration Set and Content Type

Next, we’ll create an “Include File” configuration set with the following options:

  1. Template should be the template we just created
  2. XSLT Format should not be set
  3. Configuration can be published must be checked
  4. Output File Extension should be .php
  5. Type of Data should be XML
  6. Include XML Declaration in Published Files must be unchecked
  7. The DEFAULT region does not need a Block or Format set.

Screenshot of the Include Configuration Set

After that, create an “Include File” Content Type that uses this Configuration Set so we can apply it to pages.

Include Files

Next, in Cascade, create an includes directory in your web root (it’s possible to store the include files elsewhere, but note that it requires a minor edit to the _include file described below).

Then, create a new page that uses the “Include File” Content Type we just created, and name it footer.

Block and Format

Next, we need to setup our Block and Format. We will use the same Block and Format in two places:

  1. For the DEFAULT region of our include file.
  2. For the region of our standard pages where we want to use the include. (Probably FOOTER for this example).

The Block will consist of the HTML for the footer, wrapped in a <system-xml> tag (again, since valid XML requires a root node). The Text Block option is good for this purpose.

<system-xml><p>Copyright © 2012 — Curators of the <a href="http://www.umsystem.edu">University of Missouri</a>.
All rights reserved. <a href="http://missouri.edu/dmca/">DMCA</a> and <a href="http://missouri.edu/copyright.php">other copyright information</a>.
An <a href="http://missouri.edu/eeo-aa.php">equal opportunity/affirmative action</a> institution.</p></system-xml>

The Format will look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:import href="/_internal/stylesheets/_include"/>
    <xsl:output indent="yes" method="xml"/>

    <xsl:template match="/">
    	<xsl:call-template name="output-content">
    		<xsl:with-param name="filename">footer</xsl:with-param>
    		<xsl:with-param name="content">
    			<xsl:copy-of select="system-xml/node()"/>
    		</xsl:with-param>
    	</xsl:call-template>
    </xsl:template>
</xsl:stylesheet>

In this file, an XSL template is called, named output-content, that has two parameters: the filename, footer, and the actual content of the include, which is, in this case, selects everything in the Block in-between the <system-xml> tag.

It’s worth noting, that the block doesn’t necessarily have to be static HTML. A XML block can be used, and all you have to do is make sure that the result of your XSL transformation is placed in-between the <xsl:with-param name="content"> tag of the output-content template.

_include

Now, output-content is defined by the _include stylesheet we’ve brought in via xsl:import. Here’s the definition for that file. Note that, you may need to update the xsl:import statement to accurately reflect where you’re storing the _include stylesheet.

This file determines contextually whether or not to bring in one of the include files with PHP, or to simply output the content.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes" method="xml"/>

    <xsl:template name="output-content">
        <xsl:param name="filename"/>
        <xsl:param name="content"/>

        [system-view:internal]
            <xsl:copy-of select="$content"/>
        [/system-view:internal]

        [system-view:external]
            <xsl:processing-instruction name="php">
            # Location of includes directory
            # (set to just off the server root - change it if you're storing the includes elsewhere)
            $includeDirectory = $_SERVER["DOCUMENT_ROOT"] . '/' . 'includes/';

            # Filename parameter from XSL template
            $fileName = trim('<xsl:value-of select="$filename"/>');

            # Full path of the include file
            $includePath = $includeDirectory . $fileName . '.php';

            # Just output the content if
            #   1. The file that's executing this code *is* the include file
            #   2. or the $isInclude flag has been set to true (see the else block)
            if (($_SERVER["SCRIPT_FILENAME"] == $includePath) or ((isset($isInclude)) and ($isInclude === true)))
            {
                </xsl:processing-instruction>
                <xsl:copy-of select="$content"/>
                <xsl:processing-instruction name="php">
            }

            # Otherwise, bring in the contents of the include file
            else
            {
                if (file_exists($includePath))
                {
                    # Setting $isInclude to true forces the include file to output its content when it's brought in
                    $isInclude = true;

                    # Capture the content of the include
                    ob_start();
                    include $includePath;
                    $content = ob_get_contents();
                    ob_end_clean();

                    # Strip the "include" root tag and print the contents
                    preg_match_all('/&lt;include&gt;(.*)&lt;/include&gt;/s', $content, $matches);
                    print_r($matches[1][0]);

                    # Reset the $isInclude flag
                    $isInclude = false;
                }
            }
            </xsl:processing-instruction>
        [/system-view:external]
    </xsl:template>
</xsl:stylesheet>

That’s it! Now to make changes to the footer, all you have to do is edit the footer block we defined above, and then publish out /includes/footer.

For convenience, here’s a ZIP file containing all of the files discussed in this post: