I am using cakephp 2.0 for an application...
everything is fine but I am getting some problem with custom URL or SEO friendly URL.
Here are Route rules that I am using
Router::parseExtensions('html', 'rss', 'xml','json');
Router::connect('/:language/:controller/:action/*',array(),array('language' => 'eng|chi'));
Router::connect('/', array('controller' => 'homes', 'action' => 'index'),array('language' => 'eng|chi'));
Router::connect('/backend/*', array('controller' => 'users', 'action' => 'login', 'lab' => true));
Router::connect('/about-us/*', array('controller' => 'homes', 'action' => 'about_us'));
Router::connect('/contact/*', array('controller' => 'homes', 'action' => 'contact'));
Router::connect('/:slug', array('controller' => 'homes', 'action' => 'page'), array('pass' => array('slug'), 'slug'=>'[a-zA-Z0-9-]*'));
Here for "about-us", 'contact-us' and 3rd and main one is ":slug" ( dynamic )
Two problems:
When I try to change language, url is showing lang/controller/action ( abc.com/eng/homes/about_us ) instead of abc.com/eng/about-us.html or abc.com/chi/about-us.html
for other dynamic url eg. abc.com/page-1.html, abc.com/page-2.html, abc.com/page-3.html so on... how to use abc.com/lang/slug with .html ( abc.com/eng/page-1.html or abc.com/chi/page-1.html)
For this I am using the
Router::connect('/:slug', array('controller' => 'homes', 'action' => 'page'), array('pass' => array('slug'), 'slug'=>'[a-zA-Z0-9-]*'))
rule.
When i try to change language, url is showing lang/controller/action ( abc.com/eng/homes/about_us )
The route definitions in the question have this first:
Router::connect(
'/:language/:controller/:action/*',
array(),
array('language' => 'eng|chi')
);
Routes are tested in the order they are declared - this route will match any url which has the language eng or chi passed to it, as all urls have a controller and an action this route will always match.
instead of abc.com/eng/about-us.html or abc.com/chi/about-us.html
If there needs to be a route match for /:lang/:slug - then there has to be a route defined matching that pattern - currently there isn't.
for other dynamic url eg abc.com/page-1.html, abc.com/page-2.html, abc.com/page-3.html so on ... how to use abc.com/lang/slug with .html ( abc.com/eng/page-1.html or abc.com/chi/page-1.html)
I don't fully understand the question but the answer is probably to ensure that all routes exist with a prefix and are defined before the routes without a prefix. e.g.:
Router::parseExtensions('html', 'rss', 'xml','json');
// Define Chinese language routes first as they have a prefix
Router::connect('/chi/', ['controller' => 'homes', 'action' => 'index'],['language' => 'chi']);
Router::connect('/chi/backend/*', ['controller' => 'users', 'action' => 'login', 'lab' => true],['language' => 'chi']);
Router::connect('/chi/about-us/*', ['controller' => 'homes', 'action' => 'about_us'],['language' => 'chi']);
Router::connect('/chi/contact/*', ['controller' => 'homes', 'action' => 'contact'],['language' => 'chi']);
Router::connect('/chi/:slug', ['controller' => 'homes', 'action' => 'page'], ['pass' => ['slug'], 'slug'=>'[a-zA-Z0-9-]*'],['language' => 'chi']);
Router::connect('/chi/:controller/:action/*',[],['language' => 'chi']);
// Define English language routes last as they don't have a prefix
Router::connect('/', ['controller' => 'homes', 'action' => 'index'],['language' => 'eng']);
Router::connect('/backend/*', ['controller' => 'users', 'action' => 'login', 'lab' => true],['language' => 'eng']);
Router::connect('/about-us/*', ['controller' => 'homes', 'action' => 'about_us'],['language' => 'eng']);
Router::connect('/contact/*', ['controller' => 'homes', 'action' => 'contact'],['language' => 'eng']);
Router::connect('/:slug', ['controller' => 'homes', 'action' => 'page'], ['pass' => ['slug'], 'slug'=>'[a-zA-Z0-9-]*'],['language' => 'eng']);
Router::connect('/:controller/:action/*',[],['language' => 'eng']);
In this way all routes can be parsed unambiguously, and generated unambiguously too - assuming language is always passed when generating a url; the persist parameter can help with that.
I'm trying to rewrite cakephp default url that currently is:
http://localhost/cakephpproject/property/view/1
into this URL
http://localhost/cakephpproject/country/state/locality/id
So first i have to remove property/view from URL.
So far what i have done is this:
in routes.php file i have:
Router::connect(
'/:language/property/:country/:state_province/:locality/:id',
array(
'admin'=> false,
'user'=> false,
'language'=>null,
'controller' => 'properties',
'action' => 'view'
),
array(
'pass' => array('country', 'state_province', 'locality', 'id'),
'persist'=>array('language'),
'language' => '[a-z]{2}',
'id'=>'[0-9]+',
)
);
Router::connect(
'/property/:country/:state_province/:locality/:id',
array(
'admin'=> false,
'user'=> false,
'controller' => 'properties',
'action' => 'view'
),
array(
'pass' => array('country' , 'state_province' , 'locality' , 'id'),
'id' => '[0-9]+'
)
);
PS: I have it twice because i have a miltilingual site.
The link is this:
<?php
echo $this->Html->link(
__('View more'),
array(
'admin' => false,
'user' => false,
'controller' => 'properties',
'action' => 'view',
'country' => Inflector::slug($country,'-'),
'state_province' => Inflector::slug($state_province,'-'),
'locality'=> Inflector::slug($locality,'-'),
'id' => $id
),
array(
'escape' => false
)
);
?>
And this link generate this URL which is not the URL that i want:
http://localhost/biriola/properties/view/country:United-Kingdom/state_province:unknown/locality:London/id:18
The URL that should be generated is this:
http://localhost/biriola/United-Kingdom/unknown/London/18
I modified a bit the generated link to:
<?php
echo $this->Html->link(
__('View more'),
array(
'admin' => false,
'user' => false,
'controller' => 'properties',
'action' => 'view',
Inflector::slug($country,'-'),
Inflector::slug($state_province,'-'),
Inflector::slug($locality,'-'),
$id
),
array(
'escape' => false
)
);
?>
And this generate the following URL:
http://localhost/biriola/properties/view/United-Kingdom/unknown/London/18
which is somehow the URL that i want but i have to remove the properties/view/ from URL, so i don't know how to do this.
My exact CakePHP verision is: 2.5.6
This is the full routes.php file:
<?php
/**
* Routes configuration
*
* In this file, you set up routes to your controllers and their actions.
* Routes are very important mechanism that allows you to freely connect
* different URLs to chosen controllers and their actions (functions).
*
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
*
* Licensed under The MIT License
* For full copyright and license information, please see the LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* #copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
* #link http://cakephp.org CakePHP(tm) Project
* #package app.Config
* #since CakePHP(tm) v 0.2.9
* #license http://www.opensource.org/licenses/mit-license.php MIT License
*/
/**
* Here, we are connecting '/' (base path) to controller called 'Pages',
* its action called 'display', and we pass a param to select the view file
* to use (in this case, /app/View/Pages/home.ctp)...
*/
$languageCodes = array('language' => 'en|it|de|es|fr|ru|zh|pt');
Router::connect('/:language', array('controller' => 'properties', 'action' => 'index'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/', array('controller' => 'properties', 'action' => 'index'));
Router::connect('/:language/login', array('admin'=>false, 'user'=>false, 'controller' => 'users', 'action' => 'login'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/login', array('admin'=>false, 'user'=>false, 'controller' => 'users', 'action' => 'login'));
Router::connect('/:language/logout', array('admin'=>false, 'user'=>false, 'controller' => 'users', 'action' => 'logout'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/logout', array('admin'=>false, 'user'=>false, 'controller' => 'users', 'action' => 'logout'));
Router::connect('/:language/register', array('controller' => 'users', 'action' => 'add'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/register', array('controller' => 'users', 'action' => 'add'));
Router::connect('/:language/faq', array('controller' => 'faqs', 'action' => 'index'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/faq', array('controller' => 'faqs', 'action' => 'index'));
Router::connect('/:language/faq/question', array('controller' => 'faqs', 'action' => 'add'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/faq/question', array('controller' => 'faqs', 'action' => 'add'));
Router::connect('/googlelogin', array('controller' => 'users', 'action' => 'googlelogin'));
Router::connect('/google_login', array('controller' => 'users', 'action' => 'google_login'));
Router::connect('/fb_login', array('controller' => 'users', 'action' => 'fb_login'));
Router::connect('/fblogin', array('controller' => 'users', 'action' => 'fblogin'));
/* paypal rout connect */
Router::connect('/:language/paymentOk', array('admin'=>false, 'user'=>false, 'controller' => 'properties', 'action' => 'paymentOk'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/paymentOk', array('admin'=>false, 'user'=>false, 'controller' => 'properties', 'action' => 'paymentOk'));
Router::connect('/:language/paymentEditOk', array('admin'=>false, 'user'=>false, 'controller' => 'properties', 'action' => 'paymentEditOk'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/paymentEditOk', array('admin'=>false, 'user'=>false, 'controller' => 'properties', 'action' => 'paymentEditOk'));
Router::connect('/:language/paymentCancel', array('admin'=>false, 'user'=>false, 'controller' => 'properties', 'action' => 'paymentCancel'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/paymentCancel', array('admin'=>false, 'user'=>false, 'controller' => 'properties', 'action' => 'paymentCancel'));
/*** Admin Routing URL-s */
Router::connect('/:language/admin', array('language'=>null,'admin' => true, 'controller' => 'users', 'action' => 'dashboard'),array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/admin', array('admin' => true, 'controller' => 'users', 'action' => 'dashboard'));
Router::connect('/:language/admin/:controller', array('language'=>null,'admin' => true, 'controller' => 'pages','action' => 'index', 'prefix' => 'admin'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/admin/:controller',array('admin' => true,'controller' => 'pages', 'action' => 'index', 'prefix' => 'admin'));
Router::connect('/:language/admin/:controller/:action/*', array('language'=>null,'admin' => true, 'controller' => 'pages','action' => null, 'prefix' => 'admin'),array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/admin/:controller/:action/*',array('admin' => true, 'controller' => 'pages','action' => null, 'prefix' => 'admin'));
/*** User Routing URL-s */
Router::connect('/:language/user', array('language'=>null,'user' => true, 'controller' => 'users', 'action' => 'dashboard', 'prefix' => 'user'),array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/user', array('user' => true, 'controller' => 'users', 'action' => 'dashboard','prefix' => 'user'));
Router::connect('/:language/user/:controller', array('language'=>null,'user' => true, 'controller' => 'pages','action' => 'index', 'prefix' => 'user'),array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/user/:controller', array('user' => true, 'controller' => 'pages','action' => 'index', 'prefix' => 'user'));
Router::connect('/:language/user/:controller/:action/*', array('language'=>null,'user' => true, 'controller' => 'pages','action' => null, 'prefix' => 'user'),array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/user/:controller/:action/*', array('user' => true, 'controller' => 'pages','action' => null, 'prefix' => 'user'));
/* sitemap */
Router::connect('/:language/sitemap.xml', array('language'=>null,'controller' => 'properties', 'action' => 'sitemap','admin'=>false, 'user'=>false), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/sitemap.xml', array('controller' => 'properties', 'action' => 'sitemap','admin'=>false, 'user'=>false));
/*** Languages */
Router::connect('/:language/:controller',array('language'=>null,'controller' => 'pages','action' => 'index'),array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/:controller',array('controller' => 'pages','action' => 'index'));
Router::connect('/:language/:controller/:action/*', array('language'=>null,'controller' => 'pages','action' => null), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/:controller/:action/*', array('controller' => 'pages','action' => null));
/* property view url rewriting */
Router::connect(
'/:language/:country/:state_province/:locality/:id',
array(
'admin'=> false,
'user'=> false,
'language'=>null,
'controller' => 'properties',
'action' => 'view'
),
array(
'pass' => array('country', 'state_province', 'locality', 'id'),
'persist'=>array('language'),
'language' => '[a-z]{2}',
'id'=>'[0-9]+',
)
);
Router::connect(
'/:country/:state_province/:locality/:id',
array(
'admin'=> false,
'user'=> false,
'controller' => 'properties',
'action' => 'view'
),
array(
'pass' => array('country' , 'state_province' , 'locality' , 'id'),
'id' => '[0-9]+'
)
);
/**
* ...and connect the rest of 'Pages' controller's URLs.
*/
Router::connect('/:language/pages/*', array('language'=>null,'controller' => 'pages', 'action' => 'display'), array('language' => '[a-z]{2}','persist'=>array('language')));
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
/**
* Load all plugin routes. See the CakePlugin documentation on
* how to customize the loading of plugin routes.
*/
CakePlugin::routes();
/**
* Load the CakePHP default routes. Only remove this if you do not want to use
* the built-in default routes.
*/
require CAKE . 'Config' . DS . 'routes.php';
Thanks in Advance
Order matters
The
Router::connect('/:controller/:action/*', array('controller' => 'pages','action' => null));
route is a catch-all for all URLs in /abc/xyz/* format, and since order matters (top to bottom) when matching/reverse-routing, it steals your reverse routing attempts, and thus spits out such a URL with named (key:value) elements, as the catching route doesn't have any of these parameters defined.
So, move your new routes above that one, and then use the first link() call variant, that's the correct one.
Redundant default values, they are just confusing
Also note that routes like this doesn't make much sense, this will never result in a URL like /controller/action/xyz being routed to the Pages controller, unless the controller name in the URL is pages, and for reverse routing it will only match for the pages controller, resulting in URLs like /pages/action/xyz, making the use of the :controller placeholder redundant.
The default values are redundant and confusing.
I'd suggest that you carefully study the docs on routing, then check your routes and remove the redundant default values.
See http://book.cakephp.org/2.0/en/development/routing.html
I have a link with Html helper in a admin_add.ctp view inside the cakeDC users plugin. My problem is the action is not used and the controller value is used for the action instead and 'users' is used as the controller.
I think it may be because routes is interfering. Not sure though.
The link I am getting is
/admin/users/books
The link I am looking for
/admin/books/index
Controller is books and the action is admin_index
echo $this->Html->link('List Books <i class="fa fa-chevron-right"></i>',
array('controller' => 'books',
'action' => 'index',
'plugin' => false,),
array('escape' => false));
routes.php
Router::connect('/', array('controller' => 'books', 'action' => 'index', 'home'));
Router::connect('/admin', array('controller' => 'books', 'action' => 'index', 'admin' => true));
CakePlugin::routes();
Router::parseExtensions('json', 'xml');
Router::connect('/users', array('plugin' => 'users', 'controller' => 'users'));
Router::connect('/users/index/*', array('plugin' => 'users', 'controller' => 'users'));
Router::connect('/admin/users/:action/*', array('plugin' => 'users', 'controller' => 'users', 'prefix' => 'admin', 'admin' => true));
Router::connect('/users/:action/*', array('plugin' => 'users', 'controller' => 'users'));
Router::connect('/users/users/:action/*', array('plugin' => 'users', 'controller' => 'users'));
Router::connect('/login', array('plugin' => 'users', 'controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('plugin' => 'users', 'controller' => 'users', 'action' => 'logout'));
Router::connect('/register', array('plugin' => 'users', 'controller' => 'users', 'action' => 'add'));
Try
'plugin' => null
instead of
'plugin' => false
and add
'admin' => true
if you'not already on an admin page.
Firstly, I understand there have been many questions and solutions about this but none I've found fix my issue.
In summary, the Html helper is not reverse routing correctly and instead of URLs like this:
http://website.com/user_of_website/slug_name
I get URLs like this:
http://website.com/things/view/username:user_of_website/slug:a_thing
Here is my router setup:
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
/**
* ...and connect the rest of 'Pages' controller's urls.
*/
Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
//User routes
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
Router::connect('/register', array('controller' => 'users', 'action' => 'add'));
Router::connect('/users/:action/*', array('controller' => 'users'));
Router::connect('/things/:action/*', array('controller' => 'things'));
Router::connect(
'/:username/:slug',
array(
'controller' => 'things',
'action' => 'view'
),array(
'username' => '[a-zA-Z0-9_]+',
'slug' => '[a-zA-Z0-9_]+',
'pass'=>array(
'username',
'slug'
)
)
);
Router::connect('/:userName', array('controller' => 'things', 'action' => 'user'),array('pass'=>array('userName')));
And my Html helper:
echo $this->Html->link('View', array(
'controller' => 'things',
'action' => 'view',
'username' => 'user_of_website',
'slug' => 'a_thing'
),array(
'class' => 'text-warning'
));
I really can't see what I'm doing wrong. Any help greatly appreciated.
NB, I'm using CakePHP 2.3
Have you tried if it works if you disable the 'regular' routes for things? E.g. /things/:action/*.
My guess is that, because of the wildcard, this route will match the URL as well, and, because it is defined before your custom route, will be matched in stead.
If that resolves the problem, you may try to move that route below your 'custom' route