Mugo Web main content.

Cross-siteaccess internal links in eZ Publish

By: Peter Keung | July 27, 2010 | eZ Publish development tips

Among the many advantages of hosting multiple sites on the same eZ Publish installation is the ability to create internal links. eznode:// and ezobject:// links preserve the accuracy of the generated URL links even when content is moved around or renamed within any of the sites. (Of course, you can also use such links even when you host only one site.) However, out of the box, eZ Publish is not siteaccess-aware when generating cross-siteaccess links. For example, if your site sitea.com is contained within the subtree /sitea and your site siteb.com is contained within the subtree /siteb, internal links from sitea.com to siteb.com would end up linking to "sitea.com/siteb/article" instead of "siteb.com/article". While the user can be redirected with rewrite rules, it still creates a confusing user experience. Here's a simple solution jointly developed with another eZ Partner Granite Horizon that results in generated links that are siteaccess-aware.

In this solution, we will create a custom template operator called prefixurl, which will convert cross-siteaccess links to include their correct domain names, before final processing with the ezurl() operator.

First you'll have to override the default link.tpl template (look in templates/content/datatype/view/ezxmltags in the standard design), which is used for links in eZ XML blocks and looks a bit like this:

<a href={$href|ezurl}[...]

Force the link to be passed through the prefixurl first, which will handle any cross-siteaccess links:

<a href={$href|prefixurl()|ezurl()}

Before looking at the prefixurl operator, let's look at some helper INI settings that will help the operator map the full domain names where relevant.

In settings/override/site.ini.append.php, we have our path prefix mapping:

[SiteSettings]
PathPrefixURLMap[]
PathPrefixURLMap[sitea]=http://www.sitea.com
PathPrefixURLMap[siteb]=http://www.siteb.com

And now the important part of the template operator prefixurl (for a basic intro to developing template operators, see this article):

switch ( $operatorName )
{
    case 'prefixurl':
    {
        $siteINI = eZINI::instance();
        $pathPrefixURLMap = $siteINI->variable( 'SiteSettings', 'PathPrefixURLMap' );
        $pathPrefix = $siteINI->variable( 'SiteAccessSettings', 'PathPrefix' );

        // Do not match the siteaccess you are currently in
        unset( $pathPrefixURLMap[ $pathPrefix ] ); 

        foreach( $pathPrefixURLMap as $prefix => $pathURL )
        {
            if ( 0 == strncmp( $prefix, $operatorValue, strlen( $prefix ) ) )
            {
                $operatorValue = str_replace( $prefix, $pathURL, $operatorValue );
                break;
            }
        }
    }
    break;
}

And that's it!

Since the PathPrefixURLMap keys and values are likely to already exist in each of your siteaccesses' PathPrefix and SiteURL settings, you could write an alternative template operator solution that loops through each siteaccess's settings and that doesn't require extra INI settings. However, this means quite a bit of extra code and processing. Therefore, for sites with less than, say, a dozen siteaccesses, the work of adding and maintaining the redundant INI settings is probably worth it.

Got a solution that is more efficient? Let us know in the comments!