Search-engine-friendly URL’s using the Jake bridge

A few months ago I posted my experience using the Jake bridge between CakePHP and Joomla. Overall it’s pretty slick, but with one annoyance: the URL’s are not search-engine-friendly. Moreover they broadcast your frameworks of choice which is not a good from a security viewpoint.

So after much research into the Joomla component routing and how the framework parses SEF URL’s, I came up with the following upgrade to Jake, which allows much prettier URLs.

This presumes that you have your Cake app installed in a subdirectory of your Joomla webroot (assume it’s “/webapp”). Secondly, decide upon the SEF base you want to use – it must be different from the former since you want to force it to route the request through Joomla and that requires a path that doesn’t correspond to a physical directory (I chose “/app” to be nondescript).

  1. Update your /.htaccess file to add a rewrite rule, before the core SEF section, for this new SEF base path:
    ...
    RewriteBase /
     
    # For Jake: redirect everything that starts with app/
    # See http://www.phpbb-seo.com/en/apache-mod-rewrite/article3226.html for more details
    RewriteRule	^app\/(.*)$	/index.php?option=com_jake&jrun=/$1		[QSA,L]
     
    ########## Begin - Joomla! core SEF Section
    #
    ...
  2. In /components/lib/cake_embedded_dispatcher_class.php:597, replace _changeUrl() with the following:
             /**
    	* Base for SEF URI's
    	*
    	* @since 1.1
    	* @var string
    	*/
    	var $sefCakeApplicationBase = null;
     
    	/**
    	 * Set base path to CakePHP application, using SEF URL's.
    	 *
    	 * @param string $base	Base path to Cake application in SEF URI
    	 *
    	 * @access public
    	 * @since 1.1
    	 */
    	function setSefCakeApplicationBase($base)
    	{
    		$this->sefCakeApplicationBase = $base;
    	}
     
    	function _changeUrl($start, $p1, $url, $p3, $ending, $startUrl='href="', $endUrl='"', $useComponent = true, $clean = false)
    	{
    		if (isset($this->sefCakeApplicationBase))
    		{
    			$newUrl = $this->sefCakeApplicationBase . $url;
    		}
    		else
    		{
    			// Patterns to match URLs that should not pass through the component
     
    			$passThroughLinksMatching = array('/\.jpg$/i', '/\.png$/i', '/\.gif$/i', '/\.pdf$/i', '/\.rss$/i');
     
    			if ($useComponent && isset($passThroughLinksMatching))
    			{
    				foreach($passThroughLinksMatching as $element)
    				{
    					if (preg_match($element, $url))
    					{
    						$useComponent = false;
    						break;
    					}
    				}
    			}
     
    			if ($useComponent)
    			{
    				$newUrl = str_replace('$CAKE_ACTION', urlencode($url), $this->component);
     
    				if (!empty($this->cakeUrlAddParameters))
    				{
    					$newUrl .= '&' . $this->cakeUrlAddParameters;
    				}
     
    				if ($clean)
    				{
    					$newUrl .= '&' . $this->cleanOutputParameter;
    				}
    			}
    			else
    			{
    				$newUrl = $this->cakeUrlBase . $url;
    			}
    		}
     
    		$newUrl = str_replace('&', '&', $newUrl);
     
    		$result = $start . $p1;
    		$result .= $startUrl . $newUrl . $endUrl;
    		$result .= $p3 . $ending;
     
    		$result = stripslashes($result);
     
    		return $result;
    	}
  3. In /components/lib/jake.class.php:160, add this new method to be used in place of getUrl():
             **
    	 * Gets the SEF URL to execute the specified CakePHP action with Jake
    	 *
    	 * @param string $action	CakePHP URL. (leave empty for default cake action)
    	 *
    	 * @return string	A valid Jake URL
    	 *
    	 * @access public
    	 * @since 1.1
    	 */
    	function getSefUrl($action = '', $sefCakeApplicationBase = '')
    	{
    		return $this->joomlaUrl . $sefCakeApplicationBase . $action;
    	}
  4. In /components/com_jake/jake_front_component_class.php:89, add these lines:
    		// Set the SEF URL to match the rewrite rule in /.htaccess
    		$cakeDispatcher->setSefCakeApplicationBase('/app');
  5. And finally, in your app_controller.php, you can “Jakeify” an ordinary CakePHP URL to the new SEF base, with the simple function:
    	function jakeify($url)
    	{
    		if (defined('JAKE'))
    		{
    			// set this to the same SEF base defined in /.htaccess
    			$url = $this->jake->getSefUrl($url, '/app');
    		}
    		return $url;
    	}

Once you do this, your CakePHP URIs, running through Joomla, become the much friendlier /app/controllername/actionname instead of /components/jake/?jrun=controllername/actionname. You can still access the CakePHP URI’s directly via /webapp/controllername/actionname, just as before.

1 comment

Leave a comment

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