| How to write a plugin for sh404SEF |
|
sh404SEF native plugins documentation
(c) Yannick Gaultier - July 2007
Version : 1.0 - July 10, 2007 Foreword :All information below pertains to Joomla! 1.0.x version. It is not suited for use together with the 1.5 version of Joomla. A - Backgroundsh40SEF builds and manages SEF URL for the Joomla! CMS. It uses a plugin system to adapt to various components. sh404SEF is used in two ways : to "create" URL and to "revert" URL. 1 - Creating URLCreating a SEF URL is the process of finding a SEF counterpart to one of Joomla! classical non-sef URL. As an example : non-sef URL = index.php?option=com_content&task=view&id=24&Itemid=3 SEF URL = /News-section/Fun-category/what-is-the-difference-between-a-pigeon.html It is up to each component to trigger this process, as it not automatic. Before using any URL, a component should call Joomla! sefRelToAbs() function, passing the non-sef URL as a parameter. The returned value is the SEF URL calculated for the non-sef value passed. However, Joomla! built in sefRelToAbs() function is effective but limited. It produces URL similar to : /option,xxx/task,zzz.... sh404SEF role is to build up a more significative URL, starting from the same initial data : the non-sef URL. As said before, sh404SEF uses a plugin system. It provides a framework for handling the URL themselves, storing them in DB, retrieving them upon request, but depending on the com_xxxx part of the non-sef URL, it calls upon a dedicated php file to work out the details of building the SEF URL. These "plugins" can be either "native" or "foreign": Native plugins have been designed and written specifically for sh404SEF, and take full advantage of its features. Native plugins either comes with sh404SEF (Joomla! core such as com_content, com_newsfeeds, com_search, com_poll,..., popular components such as Docman, Fireboard, Virtuemart, Community Builder,...), or can be packaged with their components by components authors. Foreign plugins have been designed for popular SEF components such as OpenSEF and SEF Advanced. They usually come with the components itself (components such as Sobi2, Alphacontent, ... come with these plugins). They are stored in the component own directory, and usually take the form of a single file : sef_ext.php. Usually, sh404SEF can use these plugins automatically and transparently, even though some compatibility issues may arise on some occasions. If both a native and a foreign plugin exist for a given component, sh404SEF backend parameters allow you to decide which one should be used ("Override own sef_ext"). After being calculated, each SEF URL is stored in Joomla! database, together with its non-sef counterpart, in order to avoid this time consuming process next time the same URL is requested. Note : in addition to writing the URL to the database, sh404SEF has a cache system to speed up the retrieval process. Both writing to the database and to the cache is part of sh404SEF framework, and therefore component developers willing to write a sh404SEF native plugin can focus only on building up the URL as they wish. Writing native plugins is the main topic of the remaining of this document. 2 - Reverting URLWhen Joomla! receives a request to serve a page, it passes on the requested URL to sh404SEF, which looks up the database to try find a record that matches the request. If a SEF match is found, then sh404SEF returns the non-sef (index.php?option=com_xxx&task=zzz...) part of the record URL for further processing. This process is called "reverting" the URL. It is needed because Joomla! does not know anything about SEF URL, and can only process non-sef URL. Reverting URL is totally automatic with sh404SEF. In other words, and contrary to foreign plugins, there is no code to write in order to "decode" the SEF URL and turn it back into a non-sef URL. B - Directory layout and namesIt follows from paragraph A that 3 types of plugins can co-exists. They can be in 3 locations : - foreign plugins are located in /components/com_component_name - native plugins delivered with sh404SEF are in /components/com_sef/sef_ext/ - individual native plugins can be in /components/com_component_name/sef_ext Native plugins have the same name as the component they work for. For instance, assuming that we have written a nice component called HeyJoe, and that we have also produced a sh404SEF native plugin for com_HeyJoe, then main plugin file will be : /components/com_HeyJoe/sef_ext/com_HeyJoe.php You can make use of any other file you like, like languages files for instance, but it is up to the component author to manage these additional files. Note: it may happen than sh404SEF does have a native plugin for a component, but this component also comes with a plugin for sh404SEF. In such event, then the component plugin will be used instead of sh404SEF own plugin. C - Writing a sh404SEF plugin1 - Plugin anatomyAs said before, a native plugin has a main file called com_component_name.php. A sample plugin file is supplied with sh404SEF. It is named "sample_com_plugin.php", and resides in the /components/com_sef directory. It is made up of 3 main parts : a - Initialization sectionThis part simply calls a sh404SEF initialization function, and also set or reset some variables. It should not be modified, unless you know what you are doing. The initiliazation code is : // ------------------ standard plugin initialize function - don't change --------------------------- global $sh_LANG, $sefConfig; $shLangName = '';; $shLangIso = ''; $title = array(); $shItemidString = ''; $dosef = shInitializePlugin( $lang, $shLangName, $shLangIso, $option); // ------------------ standard plugin initialize function - don't change --------------------------- You may not be using different languages in your component. However, sh404SEF has been designed from start with handling multi-lingual sites in mind. Specifically, this part "discovers" the non-sef URL language, taking into account the Translate URL and InsertLanguageCode parameters that can be set in sh404SEF backend. b - main URL build upThis part is what a component author has to write, defining how URL should be build according to the inner working of its component. This is done by filling up an array called $title. Each element of the URL is simply added to the array, in the same order it should appear in the final URL. Later on sh404SEF will process this array to produce the final URL. Additionnaly, sh404SEF provides a mechanism by which you can decide to leave some URL variables (GET params) as part of the "query string" instead. For instance, let's look at this non-sef URL : http://mydomain.com/index.php?option=myComponent&task=viewUserDetails &userId=2456&Itemid=23 You can either decide to turn it into fully SEF urls such as: htpp://mydomain.com/This-is-my-User-name/View-user-details.html or instead have a partially SEF URL such as : htpp://mydomain.com/View-user-details.html?userId=2456 This is a good solution in cases where having all URL turned fully SEF-ied would generate large quantities of records in the database, without adding value in terms of search engine optimisation. A few examples are : * a component handling users. There might be a link to view details, to update user record, to delete user, to print, export, etc for each individual users. That's fine with a few tens of users, maybe with a few hundreds, but if you plan on having several thousands users, then it is probably better to leave user identification as a GET variable instead of turning the id into a user name * limit and limitstart variables are used by Joomla! to handling multipage. Again, with a large number of articles or items to show (hundreds, thousands), this may generate excessive space consumption in the database * if you have a search feature using GET variables, then it is better to leave the search word out of the SEF url, or else any word searched by a user will generate a unique URL record in the database. * Generally speaking, it is suggested that parameters not conveying any meaning be left out of the text part of the URL, at least if a large number of them is expected. Make sure you don't take any risk there. It is important to decide early on what your SEF URL will look. A good thing is also to provide users with the ability to change the URL format, according to their specific need, site size, etc. At the moment, sh404SEF does not provide a facility to integrate parameters for plugins other than those supplied with sh404SEF. So if you add user defined parameters, you have to do so in your own control panel. c - Finalization sectionThis part calls a sh404SEF function. Again you should not change it, unless you want to do something specific. You may for instance do something special in case $dosef is false, that is you have decided for some reason no to build a real SEF URL. The finalization code is : // ------------------ standard plugin finalize function - don't change --------------------------- if ($dosef){ $string = shFinalizePlugin( $string, $title, $shAppendString, $shItemidString, (isset($limit) ? @$limit : null), (isset($limitstart) ? @$limitstart : null), (isset($shLangName) ? @$shLangName : null)); } // ------------------ standard plugin finalize function - don't change --------------------------- 2 - Building up the SEF URL
$task may or may not exists, according to your component operation $shCurrentItemid is always available. It is set by sh404SEF and contains the current page Itemid. Just remember that your plugin is being called upon normally, as part of sefRelToaAbs(), when Joomla! is preparing the content of a page and needs to SEF-y all links on this page. $shCurrentItemid is this page Itemid. You don't have to use shCurrentItemid as, due to the way your component operates, you may already one what is the Itemid of the menu element you want to use. Just replace $shCurrentItemid by your own Itemid.
3 - Working with multiple languagesURL in sh404SEF sites have two parts: some URL elements are constant, and some are variables. Constant elements are things like : .../view-products-details or /Delete-product Variable elements are things like : .../pet-mammoth-clothing "Delete-product" is a fixed text string that describe an action for instance, whereas "pet-mammoth-clothing" is fetched from the database. It can be a product name in Virtuemart, or a content title. Constant elements are translated through a set of language strings that should be supplied with the plugin, either inside the plugin, or as a separate text file. Beware that all translation strings must be available at anytime, as a single web page may have URL in several languages at the same time. Plugins delivered with sh404SEF use a global variable called $sh_LANG. It is a two-dimensionnal array, indexed on language iso code and string ID. For instance : $sh_LANG['fr']['_SH404SEF_FB_SHOW_USER_PROFILE'] = 'Voir vos informations utilisateur'; $sh_LANG['en']['_SH404SEF_FB_SHOW_USER_PROFILE'] = 'View user information'; When using such an array, you can make use of two variables, which are initialized with the appropriate values in the initialization section of the plugin : $shLangName : contains the URL language name ("french", "english", "spanish") $shLangIso : contains the URL language short iso code ("fr", "en", "es") So you would use : $title[] = $sh_LANG[$shLangIso]['_SH404SEF_FB_SHOW_USER_PROFILE'] Variable elements are translated using Joomfish. Because URL translation can be switched on or off, on a component by component basis by the user, it is recommanded to use the following code whenever fetching any data that can be translated from the database : if (shTranslateUrl($option, $shLangName)) $database->loadObject( $sectionTitle); else $database->loadObject( $sectionTitle, false); shTranslateUrl() will return true if URL for the component "$option" should be translated, and false otherwise. shTranslateUrl() reads the user set backend parameters to decide about this. It will also always return false if Joomfish is not installed, therefore this syntax will work in any situation. When Joomfish is installed, each classical Joomla! database object function can be called with a second parameter to force translation on or off. Warning : for Joomfish to operate and perform translation, you MUST include the table id in the select clause of your query! For instance : "SELECT name FROM #__contents WHERE id=3" will NEVER be translated. To allow translation, query has to be : "SELECT id, name FROM #__contents WHERE id=3" With this last query : $database->loadObject( $sectionTitle); will return the translated value of 'name' $database->loadObject( $sectionTitle, false); will return the original value of 'name' (ie its value in the site default language) Note : remember to explicitly remove the $lang variable from the URL (using shRemoveFromGETVarsList('lang')), otherwise it will show up in the final URL as a query string bit (...&lang=xx...) |



