Share » Learn » eZ Publish » Helper Child Nodes: User-Friendly...

Helper Child Nodes: User-Friendly Search Results and Preventing Full Node Views

Thursday 15 May 2008 4:11:00 am

  • Currently 5 out of 5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Although you can try to avoid any links to helper nodes, users can still guess the URL and type it directly. Therefore, the solution is to redirect the page to the parent node when a user accesses the full view of a helper child node. We have several options to do this and will start with a simple solution for the full view template:

<script type="text/javascript">
<!--
    location.pathname = {$node.parent.url|ezurl};
// -->
</script>
<p>You should be automatically redirected, if you are not, please click <a href={$node.parent.url|ezurl}>here</a>.</p>

The solution above uses JavaScript to redirect the user to the master parent node. If a user's browser does not support JavaScript, he / she will have to click a link to the parent node.

Meta refresh

Another solution exists to automatically redirect the user without using JavaScript: the meta refresh tag. Here, the <meta> tag in the HTML header instructs the browser to redirect to a page immediately or after a given number of seconds. This solution was originally developed by Netscape but is now supported in the majority of web browsers.

<html>
<head>
<meta http-equiv="Refresh"
      content="0; url=http://www.mysite.com/address/to/redirect" />
</head>
...

Note that the “0” in the “content” parameter means: “wait 0 seconds and then redirect”.

As this redirection must be done in the HTML header, we cannot do this all in the full view template. We can use persistent_variable, a variable that can be set in a full view template and will subsequently be available in the pagelayout, even if the view cache is used. persistent_variable will store the path of the node to which we want to redirect:

In the /node/view/full.tpl override:

{set scope="global" persistent_variable=hash( 'redirect', $node.parent.url )}

In pagelayout.tpl:

{* ... *}
 
<head>
 
{* ... *}
 
{if and( is_set( $module_result.content_info.persistent_variable.redirect ),
         $module_result.content_info.persistent_variable.redirect )}
<meta http-equiv="Refresh"
      content="0; url={$module_result.content_info.persistent_variable.redirect|ezurl( 'no', 'full' )}" />
{/if}
 
{* ... *}
 
</head>
 
{* ... *}

HTTP redirects

The solutions mentioned above suffer from a certain usability problem. After the user is redirected, if he / she clicks the browser's Back button, this will load the full view of the helper node again, which redirects the user immediately back to the parent node. Some modern browsers try to overcome the problem, but the resulting behavior or solution is different across browsers.

A better solution is to use HTTP redirects -- in other words, generating responses with status code 301 (permanent redirect) or 302 (temporary redirect). There is no template operator that can do this and thus we need to write our own.

We will create an extension called “redirect” (alternatively you can add the operator to an existing extension – in that case you will need to change the extension's name in the INI settings and alter paths in the PHP files) with the following files:

autoloads/eztemplateautoload.php:

<?php
 
$eZTemplateOperatorArray = array();
 
$eZTemplateOperatorArray[] = array(
    'script' => 'extension/redirect/autoloads/redirectoperator.php',
    'class' => 'RedirectOperator',
    'operator_names' => array( 'redirect' )
);
 
?>

autoloads/redirectoperator.php:

<?php
 
class RedirectOperator
{
    function RedirectOperator()
    {
        $this->Operators = array( 'redirect' );
    }
 
    function &operatorList()
    {
        return $this->Operators;
    }
 
    function namedParameterPerOperator()
    {
        return true;
    }
 
    function namedParameterList()
    {
        return array(
            'redirect' => array(
                'url' => array(
                    'type' => 'string',
                    'required' => true
                )
            )
        );
    }
 
    function modify( &$tpl, &$operatorName, &$operatorParameters, &$rootNamespace,
                     &$currentNamespace, &$operatorValue, &$namedParameters )
    {
        include_once( 'lib/ezutils/classes/ezsys.php' );
        include_once( 'lib/ezutils/classes/ezhttptool.php' );
        include_once( 'lib/ezutils/classes/ezexecution.php' );
 
        $redirectUri = $namedParameters['url'];
        // if $redirectUri is not starting with scheme://
        if ( !preg_match( '#^\w+://#', $redirectUri ) )
        {
            // path to eZ Publish index
            $indexDir = eZSys::indexDir();
 
            /* We need to make sure we have one
               and only one slash at the concatenation point
               between $indexDir and $redirectUri. */
            $redirectUri = rtrim( $indexDir, '/' ) . '/' . ltrim( $redirectUri, '/' );
        }
 
        // Redirect to $redirectUri by returning status code 301 and exit.
        eZHTTPTool::redirect( $redirectUri, array(), 301 );
        eZExecution::cleanExit();
    }
}
 
?>

settings/site.ini.append.php:

<?php /* #?ini charset="iso-8859-1"?
 
[TemplateSettings]
ExtensionAutoloadPath[]=redirect
 
*/ ?>

Do not forget to enable the extension. To use the new operator, simply call it in an override of node/view/full.tpl like this:

{redirect( $node.parent.url )}

Note that we do not need to switch off view caching (by setting the cache_ttl variable to “0”) because the redirect operator will terminate the processing of the request before the cache file can be saved.

To avoid fetching a helper node, its object and its parent node at every request, we can benefit from view caching, using persistent_variable again to remember to which page to redirect (in the node/view/full.tpl override):

{set scope="global" persistent_variable=hash( 'redirect', $node.parent.url )}

The redirection is then handled in pagelayout.tpl:

{if and( is_set( $module_result.content_info.persistent_variable.redirect ),
         $module_result.content_info.persistent_variable.redirect )}
{redirect( $module_result.content_info.persistent_variable.redirect )}
{/if}
 
{* Original pagelayout.tpl *}
{* ... *}

For more information on URL redirection, see http://en.wikipedia.org/wiki/URL_redirection.

36 542 Users on board!

Tutorial menu

Printable

Printer Friendly version of the full article on one page with plain styles

Author(s)