Follow up on this thread -
@seyya commissioned me to implement the custom URLs required by his site and very kindly consented to share the solution with the community (Thanks, @seyya!).
Being the kind of lazy coder that I am, I am simply copy/pasting below verbatim the solution I delivered in a hope that this would come in handy to others too.
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Problem statement:
- Code: Select all
We have a 'nested-pages' template and we want to change the default URLs used by its cloned-pages e.g. this -
https://taxcoach.pl/en/offer-details/accounting-and-human-resources-for-polish-entities/accounting-for-uber-bolt-free-now-drivers/
into this where the offer name appears immediately after the domain name without the template name and without parent category -
https://taxcoach.pl/en/accounting-for-uber-bolt-free-now-drivers
In the first URL above, note that the '/en/offer-details/' part is the template name (en/offer-details.php) but since the requirement is to have a URL that does not have the template name we cannot use the routes addon with the en/offer-details.php.
The solution is to use routes with another template that yields the desired URL structure (in this case this would be 'en/index.php').
And when the matching route is found in that shadow template, we use <cms:pages> to fetch in the actual page from the actual template (en/offer-details.php in this case) and show it with the correct HTML markup.NOTE:
Before we get to the actual solution, I made a little change to your existing setup to make things easier in later steps.
I edited your 'offer-details.php' template and moved all its HTML part into a snippet named 'offers/views/offer-details.html' which I embedded into the template.
The net result is exactly the same as before but we now have the HTML markup as snippet which we'll use reuse in a following step.
Coming to the solution -
It comprises of three steps explained below.
1. Adding routing to 'en/index.php'We'll follow the steps shown in the docs for routing at
https://www.couchcms.com/docs/custom-routes/This non-clonable template 'en/index.php' already existed so we begin by making the template routable by making the following two changes to it -
- Code: Select all
<cms:template routable='1' >
..
..
..
<?php COUCH::invoke( K_IGNORE_CONTEXT ); ?>
Next we add the required routes definitions to it.
I have placed these definitions in a separate snippet ('offers/define_offer_routes.html') which we embed in the 'en/index.php' template -
- Code: Select all
<cms:template routable='1'>
<!-- define offer routes -->
<cms:embed 'offers/define_offer_routes.html' />
..
..
This is then followed by placing right *after* the closing </cms:template> tag the code that finds the matched route and takes appropriate actions.
Again this code has been placed in a snippet so we embed it as follows -
- Code: Select all
..
..
</cms:template>
<!-- show offer page -->
<cms:embed 'offers/show_offer_page.html' offer_masterpage='en/offer-details.php' offer_view='offers/views/offer-details.html' ></cms:embed>
..
..
Please note that, to make the snippet reusable across other templates that might require this routing solution, I have made it to accept two parameters -
'offer_masterpage' - specifies the actual template to fetch the page from
'offer_view' - specifies a snippet that would be used to render the page fetched above. (You'll recall that in this case it is the snippet we culled out of your 'offer-details.php' template)
You may take look at these snippets to see what is going on.
One last step and we'll be done with making this template routable.
After making the mandatory visit to the modified template as super-admin, please use 'gen_htaccess.php' utility (
https://docs.couchcms.com/concepts/pretty-urls.html) to regenarate the .htaccess file used by your site.
This is important because making the template routable will now require a different set of htaccess rules.
OK, at this point our routing is working and you can try inputting the new format of URL into the browser and see that it loads pages fetched from the other template.
We'd, however, want the links of 'en/offer-details.php' as shown on the frontend to show these new URLs -
2. Fix links in 'en/offer-details.php'Two ways of doing this.
a. We can generate these links directly by using <cms:route_link /> tag providing it with the name of the route (and values for the params) we defined for accessing these pages. Note we are getting links from 'en/index.php'.
- Code: Select all
<cms:route_link 'page_view' masterpage='en/index.php' rt_page_name=k_nestedpage_name rt_slash='' />/
So edit all places where the original links were used (e.g. offer.php) and replace code like the following -
- Code: Select all
<a href="<cms:show k_nestedpage_link />">
to make it as follows -
- Code: Select all
<a href="<cms:route_link 'page_view' masterpage='en/index.php' rt_page_name=k_nestedpage_name rt_slash='' />/">
b. To make it even easier, I have placed an event handler in your addons/kfunctions.php file which sets a variable named 'my_offer_link' for pages that belong to the offer templates.
- Code: Select all
/// get offer links
$FUNCS->add_event_listener( 'alter_page_set_context', function(&$vars, &$pg){
global $FUNCS, $CTX, $KROUTES;
// set your template names here
$my_offer_tpls = array(
'en/offer-details.php' => 'en/index.php',
'xyz.php' => 'index.php',
);
$offer_link = '';
if( array_key_exists($pg->tpl_name, $my_offer_tpls) ){
// get link from route object
$masterpage = $my_offer_tpls[$pg->tpl_name];
$route = &$KROUTES->get_routes( $masterpage )['page_view'];
if( $route ){
$values = array('page_name'=>$pg->page_name, 'slash'=>'');
$q = $route->generate( $values );
if( K_PRETTY_URLS ){
$offer_link = K_SITE_URL . $FUNCS->get_pretty_template_link( $masterpage ) . $q .'/';
}
else{
$offer_link = K_SITE_URL . $masterpage;
if( strlen($q) ){ $offer_link .= '?q=' . $q; }
}
}
}
$CTX->set( 'my_offer_link', $offer_link );
});
Please note that in the code above you can set the names of the templates that are involved in this new URLs strategy along with their counterpart 'shadow' templates.
Couch will then automatically set a new variable named 'my_offer_link' at all places where you usually use 'k_page_link' or 'k_nestedpage_link'.
Following are some example usages of this new variable -
Orig:
- Code: Select all
<cms:pages masterpage="en/offer-details.php">
<cms:show k_page_title />: <cms:show k_page_link /> <br>
</cms:pages>
Mod:
- Code: Select all
<cms:pages masterpage="en/offer-details.php">
<cms:show k_page_title />: <cms:if my_offer_link><cms:show my_offer_link /><cms:else /><cms:show k_page_link /></cms:if> <br>
</cms:pages>
With <cms:nested_pages> make sure to set the 'include_custom_fields' param to '1' as shown below -
Orig:
- Code: Select all
<cms:nested_pages masterpage="en/offer-details.php" include_custom_fields='1'>
<cms:show k_nestedpage_title />: <cms:show k_nestedpage_link /> <br>
</cms:nested_pages>
Mod:
- Code: Select all
<cms:nested_pages masterpage="en/offer-details.php" include_custom_fields='1'>
<cms:show k_nestedpage_title />: <cms:if my_offer_link><cms:show my_offer_link /><cms:else /><cms:show k_nestedpage_link /></cms:if> <br>
</cms:nested_pages>
So this now shows the new URLs on the site.
However, if someone accesses the older URLs they'll still work too.
So as the final step we redirect the older URLs to their new counterparts -
3. Redirecting the original URLsThe most straightforward way of doing this is by placing
- Code: Select all
RewriteCond %{REQUEST_FILENAME} -d [OR]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule . - [L]
######### custom rules for offers #######
RewriteRule ^en/offer-details/[^\.]*?([^/\.]*)/?$ en/$1/ [R=301,L,QSA]
########################################
NOTE:
The template we are working with is contained in a folder ('en/') and hence is known as 'en/offer-details.php'.
Had it been in the site's root it would be known simply as 'offer-details.php' and the shadow template to place routes in would have been 'index.php' also in the site's root.
In this case the rule to put into .htaccess file would be this -
- Code: Select all
RewriteRule ^offer-details/[^\.]*?([^/\.]*)/?$ $1/ [R=301,L,QSA]
And with this our solution is complete.
Hope this helps.