Hướng dẫn rewrite URL trong Yii Framework
SEO (Search Engine Optimization): tối ưu trang web trên công cụ tìm kiếm là kỹ thuật cải tiến hệ thống trang web để phù hợp với những tiêu chí của các công cụ tìm kiếm đề ra (tiêu đề trang, thẻ meta,…). URL đẹp là một trong những yếu tố ảnh hưởng đến SEO. Tôi thích nhìn một url đẹp, mô tả được nội dung cần tìm khi sử dụng các Search Engine.
Với Yii Framework, để có một đường dẫn đẹp (Friendly URL) bạn thực hiện theo các bước sau. Có vẻ sẽ hơi rắc rối, nhưng đây là tất cả những gì tôi biết :D, hy vọng giúp bạn được phần nào khi sử dụng Yii Framework.
Chúng ta sẽ thay đỗi nội dung file main.php trong thư mục protected/config
// uncomment the following to enable URLs in path-format
'urlManager'=>array(
'urlFormat'=>'path',
'showScriptName'=>false,
'rules'=>array(
'dang-ky'=>array('user/register', 'caseSensitive'=>false),
'dang-nhap'=>array('site/login', 'caseSensitive'=>false),
'bai-viet/trang-<page:\d+>'=>array('article/index'),
'bai-viet'=>array('article/index'),
'tags/<tag:.*?>'=>array('article/tag'),
'rss'=>array('article/feed', 'caseSensitive'=>false, 'urlSuffix'=>'.xml'),
'yii-framework/cai-dat-cau-hinh'=>array('article/type', 'defaultParams'=>array('type'=>'cai-dat-cau-hinh'), 'caseSensitive'=>false),
'yii-framework/cai-dat-cau-hinh/<alias:.*?>'=>array('article/view', 'defaultParams'=>array('type'=>'cai-dat-cau-hinh'), 'caseSensitive'=>false, 'urlSuffix'=>'.html'),
'<type:.*?>/<alias:.*?>'=>array('article/view', 'caseSensitive'=>false, 'urlSuffix'=>'.html'),
'<type:.*?>'=>'article/type',
'<controller:\w+>/<action:\w+>/page/<page:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
),
'showScriptName'=>false,
Dòng này quan trọng đấy, nó khai báo cho Yii biết sẽ ẩn đi index.php trong URL
'dang-ky'=>array('user/register', 'caseSensitive'=>false),
'dang-nhap'=>array('site/login', 'caseSensitive'=>false),
Từ khóa caseSensitive khai báo cho Yii có phân biệt URL viết hoa-thường hay không.
Chuyển các URL controller/action đặc biệt (các link tĩnh) sang dạng đẹp hơn.
'bai-viet/trang-<page:\d+>'=>array('article/index'),
Rewrite các url khi phân trang về dạng http://trumcode.com/bai-viet/trang-2, bỏ đi các ký hiệu chứa tham số &.
Bạn cần thực hiện thêm 1 số thao tác để đạt được kết quả này:
- Trong controller, chỗ $dataProvider bạn thêm giá trị 'pageVar'=>'page' cho mảng pagination báo cho Yii biết sẽ sử dụng tham số page trong url thay cho tham số mặc định
$dataProvider=new CActiveDataProvider('Article', array(
'criteria'=>$criteria,
'pagination'=>array(
'pageSize'=>Yii::app()->params['limitPageSizeView'],
'pageVar'=>'page'),
));
- Trong view, bạn thêm thuộc tính 'ajaxUpdate'=>false cho CListView loại bỏ tính năng phân trang bằng ajax mặc định. Điều này giúp google tìm được các bài viết hiển thị trong các trang tiếp theo, thay vì dùng ajax sẽ chỉ index được trang đầu tiên
$this->widget('zii.widgets.CListView', array(
'dataProvider'=>$dataProvider,
'itemView'=>'_view',
'ajaxUpdate'=>false,
'pager'=>array(
'cssFile'=>false,
'class'=>'CLinkPager',
'header'=>'',
'firstPageLabel'=>'<<',
'prevPageLabel'=>'<',
'nextPageLabel'=>'>',
'lastPageLabel'=>'>>',
),
'template'=>"{items}\n{pager}",
));
'rss'=>array('article/feed', 'caseSensitive'=>false, 'urlSuffix'=>'.xml'),
'urlSuffix'=>'.xml' cho phép thêm phần mở rộng cho url. Theo cá nhân tôi, bạn chỉ nên thêm suffix cho bài viết chi tiết.
'yii-framework/cai-dat-cau-hinh'=>array('article/type', 'defaultParams'=>array('type'=>'cai-dat-cau-hinh'), 'caseSensitive'=>false),
'yii-framework/cai-dat-cau-hinh/<alias:.*?>'=>array('article/view', 'defaultParams'=>array('type'=>'cai-dat-cau-hinh'), 'caseSensitive'=>false, 'urlSuffix'=>'.html'),
defaultParams cho phép bạn chỉ định giá trị mặc định cho url theo phương thức GET, nhưng nó sẽ không hiện trên url. Cách này thích hợp với các chủ đề được phân cấp theo dạng Parent-Child. Trong ví dụ này tôi có yii-framework là chủ đề cha, và một trong những nhánh con của nó là cai-dat-cau-hinh.
Theo cách này của tôi sẽ tạo được ra các url như ý. Tuy nhiên nó không linh động khi bạn thường xuyên thay đỗi danh mục chủ đề.
'<type:.*?>/<alias:.*?>'=>array('article/view', 'caseSensitive'=>false, 'urlSuffix'=>'.html'),
'<type:.*?>'=>'article/type',
Hai dòng này sẽ rewrite tất cả các tham số cho actionType còn lại của ActicleController. actionType của tôi tương tự như actionIndex tạo mặc định bởi gii. Chắc có bạn sẽ thắc mắc với cùng một chức năng tại sao tôi lại dùng 2 tên action khác nhau; điều này giúp tôi thuận tiện hơn khi cấu hình UrlManager. Khi thực hiện rewrite trong Yii đôi khi bạn sẽ gặp vài vấn đề rewrite không được mà không biết tại sao? Bạn hãy thử copy action đặt nó dưới 1 tên khác. Đây là kinh nghiệm thực tế của tôi (có vẻ hơi chuối :D)
'<controller:\w+>/<action:\w+>/page/<page:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<id:\d+>'=>'<controller>/view',
'<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
4 dòng cuối cùng sẽ tự động thực hiện rewrite tất cả các url còn lại.
Như vậy, bạn đã hoàn tất cấu hình URL trong Yii. Bước tiếp theo bạn thêm 1 file .htaccess trong thư mục gốc của dự án. File .htaccess của tôi sẽ thực hiện các công việc sau:
- Bật chế độ Rewrite
- Rewrite sẽ được áp dụng tại thư mục gốc
- Rewrite từ url dạng có www sang non-www (tránh mất traffic vì google sẽ hiểu đây là 2 site khác nhau)
- Bỏ đuôi .php hoặc .html sau url, rất hữu ích khi login. Ví dụ khi bạn đăng nhập Yii sẽ chuyển bạn về địa chỉ trumcode.com thay vì trumcode.com/index.php không đẹp tí nào.
- Cho phép truy cập trực tiếp vào tập tin hoặc thư mục nếu nó tồn tại. Ngược lại tất cả các yêu cầu khác đều được xử lý thông qua file index.php (bootstrap file)
Nội dung file .htaccess:
RewriteEngine on
# Specify the folder in which the application resides.
# Use / if the application is in the root.
RewriteBase /
# Rewrite to correct domain to avoid canonicalization problems
RewriteCond %{HTTPS} off
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ http://%1/$1 [R=301,L]
RewriteCond %{HTTPS} on
RewriteCond %{HTTP_HOST} ^www\.(.*)$ [NC]
RewriteRule ^(.*)$ https://%1/$1 [R=301,L]
# Rewrite URLs ending in /index.php or /index.html to /
RewriteCond %{THE_REQUEST} ^GET\ .*/index\.(php|html?)\ HTTP
RewriteRule ^(.*)index\.(php|html?)$ $1 [R=301,L]
# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
# otherwise forward it to index.php
RewriteRule ^.*$ index.php [L]
Chú ý:
- Thứ tự đặt các dòng này rất quan trọng.
- Ưu tiên các url cụ thể trước, tổng quát sau (xem ví vụ trên bạn sẽ hiểu)
Vấn đề tồn tại:
- Chưa tối ưu việc rewrite cho các site đa ngôn ngữ
- Chưa tự động thực hiện rewrite các url dạng Parent-Child