|
Drupal中使用URL别名在SEO以及网站用户体验方面非常重要,通常我们使用如下几个模块, - path(核心模块)
- pathauto
- path_redirect
- global_redirect
一般情况下,给一个URL设置一个别名,全站的所有URL都会更新用这个别名来代替原来的URL。 比如: /user/1 —> /robbin-zhao
这样设置的URL会被保存在url_alias表中。 这里有两个术语: 1. outbound URL 输出URL,或者显示/打印的URL。 2. inbound URL 请求URL,可以理解为进来的URL。 了解了术语之后,我们理解一下Drupal处理URL别名的方式,
1). 输出别名 在输出URL的时候,核心函数是URL function url($path = NULL, $options = array()) {
7 G5 m. ?% E* |; O' l- T( Y // Merge in defaults.9 F6 b" ^- [2 }% X: M
$options += array(
- @/ B2 M# L% E- j; k( q7 l+ `' k 'fragment' => '',$ R5 C O2 a2 _0 J# z9 @, ]2 H
'query' => '',& Y7 \- f* J% g9 J9 v/ L, ?1 @2 M9 p
'absolute' => FALSE,& |6 i) H, v5 J) w. |5 \' K; Y
'alias' => FALSE,
% J- R% f8 B- f 'prefix' => '',) A- j% A( e1 y& B& a
);
# G6 s n7 |& V- l W! z8 I: m# r
/ X3 q4 o3 E3 R3 u% u4 C ...' `2 Y2 D" a: l1 Z+ u1 C( i
+ y% C8 }) B; E( E) E& r% U elseif (!empty($path) && !$options['alias']) {
7 e0 g' {8 y1 g r3 v/ Y( U $path = drupal_get_path_alias($path, isset($options['language']) ? $options['language']->language : '');
7 y; w8 \5 y- ~! a% {0 ]% H7 Q }
7 \/ `" C% s) @- y
7 A5 T" g' x+ R2 S" ?1 f if (function_exists('custom_url_rewrite_outbound')) {
( F* ~9 d8 M# V9 W" |& J // Modules may alter outbound links by reference.
4 W2 G/ [' @/ F' ^1 u% j4 | custom_url_rewrite_outbound($path, $options, $original_path);" r5 E, I9 W7 F( j8 b
}我们重点看下面的两个调用 drupal_get_path_alias 和 custom_url_rewrite_outbound。Drupal通过查询url_alias表,把要显示的URL更新为对应的alias就实现了别名的替换。 2). 处理别名的HTTP请求 Drupal在启动所有模块之前,先初始化URL,调用如下函数: function drupal_init_path() {
: B/ u/ y' R$ x5 M @; q if (!empty($_GET['q'])) {
0 ^6 w3 z6 l( P2 d! v8 _$ s $_GET['q'] = drupal_get_normal_path(trim($_GET['q'], '/'));
, V6 V, v- `! z5 N }
1 U4 ], x/ N' A4 F else {$ ?8 d1 M$ A3 l) v
$_GET['q'] = drupal_get_normal_path(variable_get('site_frontpage', 'node'));
* n2 E) L y# ]/ `5 z9 ]3 ]3 M0 c }2 r+ U2 k/ @7 v& ~' Q/ C" ^: O
}# X4 B7 W5 G8 Q0 }( `2 I8 V
4 ]: K- Q5 T- ]8 p9 @4 G4 U0 Kfunction drupal_get_normal_path($path, $path_language = '') {& V6 N* B1 B ~
$result = $path;
( e7 b! ~+ M; O; \ if ($src = drupal_lookup_path('source', $path, $path_language)) {
& E' @( @) N2 f/ ` $result = $src;
# {+ A9 t9 B: {, j6 P+ r }
; ~$ w: f$ I5 F if (function_exists('custom_url_rewrite_inbound')) {8 B8 G9 O- B4 ^! z- I5 F% L. a1 [
// Modules may alter the inbound request path by reference.6 l# k/ m% ~/ Q2 \* o
custom_url_rewrite_inbound($result, $path, $path_language); M& q- V! U4 y) P! E
}. M8 k& ]. W" v# R& R
return $result;
0 P, n+ Y4 l7 J6 D$ R}函数 drupal_get_normal_path 主要是查询url_alias表,得到当前URL的实际地址,比如 user/1, 然后把这个URL赋给 $_GET['q']来实现具体的URL重写功能。 在有些情况下,我们需要批量修改一些URL的别名,如果我们用drupal默认的url_alias, 但又有一些问题,首先,更新所有的URL脚本比较繁琐,数据量大的情况需要batch,操作数据不方便。其次,如果用户量大,会产生严重的Drupal性能问题,因此,可以考虑到不用url_alias,举个例子,比如我们希望更新user下面的所有tab url, 如:user/1/info, user/1/blog, user/1/message,user/1/mail … 每个用户有多个URL需要更新,如果有1百万用户,那么就会有上百万、千万的alias数据,对于维护、性能都是很大问题。 自定义函数实现URL重写 通过查看Drupal的URL流程,可以发现,Drupal在处理输出URL的时候,会调用一个自定义函数:custom_url_rewrite_outbound,在处理HTTP请求的URL时, 也会调用一个自定义函数:custom_url_rewrite_inbound,所以我们可以实现这两个函数来实现URL重写。 注意,由于这是单个函数而不是hook,如果每个函数都实现,很容易相互冲突,比如fb模块(facebook),url_alter(用于自定义代码来实现URL重写,主要实现了上面的两个函数)。但是由于这两个函数容易冲突(不是hook),其次,url_alter对inbound URL处理有问题,因为Drupal在调用custom_url_rewrite_inbound这个自定义函数的时候,是在加载所有模块之前,所以把这个函数写在module文件里面,根本掉用不到,这里提供一个目前较为合理的解决方案: - 写一个inc文件,放到(任意)自定义模块下面,比如 my-core/my-core.rewrite.inc
- 修改settings文件,include这个文件。比如 include “sites/all/modules/custom/my-core/my-core.rewrite.inc”;
- 在该文件中加入inbound和outbound这两个函数。
具体代码如下: /**4 c+ O$ N$ f3 g$ S% M0 K
* Define custom_url_rewrite_inbound()+ l x6 L4 s% o* D
* @author robbin+ C0 x% O$ t% G) E9 e2 p6 z+ {
*/
0 z. [+ j( y+ g, ]% R# h fif (!function_exists('custom_url_rewrite_inbound')) {: d+ u* P- T/ F- s% C L$ x
function custom_url_rewrite_inbound(&$result, $path, $path_language) {
& m& G. [0 q! C+ M {fun_1}_url_inbound_alter($result, $path, $path_language);* Q9 _# {# Z0 a- o, ]1 w" N2 @+ w' c
}
* ]' h" M0 q4 @0 u \: O}
8 @5 L5 \. [( l" A$ T 8 u R/ c, p0 l( S- {5 Y
/**! j+ d# P( i% L: f4 {# R
* Define custom_url_rewrite_outbound()! P8 l1 j$ \+ W- c
* @author robbin
8 V3 ]" t8 F- Y$ L/ S0 e+ e */
; w5 \) f z) E- S7 X( A1 @if (!function_exists('custom_url_rewrite_outbound')) {- }5 a. f% k. L- U1 i+ f
function custom_url_rewrite_outbound(&$path, &$options, $original_path) {* w+ R+ W% L; `5 H6 P
{fun_1}_url_outbound_alter($path, $options, $original_path);6 P! I: X1 `2 v8 K" k g
}: ], p8 u c5 G( j" E
}其中 {fun_1}_url_inbound_alter、{fun_1}_url_outbound_alter 表示一组处理inbound/outbound的函数,命名规则最好按照如上方式,因为一些第三方模块以及hook都是这个规则,容易理解。 可以添加多个函数,比如{fun_2}_url_inbound_alter等等,每添加一个,在上面的位置调用函数,以做到每组不通功能的函数分开。如果第三方模块,也需要实现重写,一般情况下,这些模块会实现类似 {module}_url_inbound_alter这样的函数,直接把这个函数加到上面对应的位置来调用即可,比如(facebook模块的fb_url_inbound_alter等)。这里给出函数的简要说明: //修改result的值为最终实际的URL $result是引用传值 hook_url_inbound_alter(&$result, $path, $path_language); //修改$path的值为想要的别名的URL $path是引用传值 hook_url_outbound_alter(&$path, $options, $original_path);
最后,还有一点要注意,自定义inbound函数,有时可能会和global_redirect冲突,(没用这个模块,写了类似的函数,也会冲突),因为redirect模块会检查当前的真是url(从outbound中获取)和当前请求的URL不一样,比如真实url是user/1,而当前的请求是 robbin-zhao,它会自动跳转,导致一个无限循环跳转的bug。 解决办法就是在inbound函数里面设置一个全局变量,阻止继续调转。设置 $_REQUEST['q'] = $result; 的值为最终实际URL的值,而不是别名。 示例代码 function my_redirect_url_inbound_alter (&$result, $path, $path_language) {
( m8 B( s9 D/ n( } `* S
# j$ \. {. |" M+ f2 t $arg0 = arg(0); //should be user-name9 U9 Y) G' g4 o
$arg1 = arg(1); //should be connections/media/...) |; ?2 K0 \% x- F5 N' X
5 k0 J2 i* F- \( R U8 w
if ($arg1) {
" v* i7 Y0 r4 j $user_url = drupal_lookup_path('source', $arg0);& b& ~7 O8 ]1 i2 g2 L
if ($user_url != $arg0 && preg_match('{user/(\d+)}i', $user_url, $matches)) {+ `' W% c0 ~; v) J: U3 ~4 Z
$user_id = $matches[1];
7 x% }. O/ L2 c* Q; r5 p1 H $result = "user/$user_id/$arg1";
) Y& h% i. q) u* m
+ o. W+ C, M) W8 o0 g+ K1 Q& c //add this to tell global_redirect not to redirect this url again5 H; F: l5 a. d0 Z6 L: D9 }& ]
$_REQUEST['q'] = $result;
9 ]% z- n. N" W% |4 {7 S5 ~ }
5 ~; P, y& X' l) a }1 r7 }! |& v- h" b& q
}
/ P, O. L4 W) Y0 h
5 A9 S% g) W: F4 H* nfunction my_redirect_url_outbound_alter (&$path, $options, $original_path) {
, f* o% ^9 p3 y$ { //rewrite user's sub tab url to seo-friendly url
& \% s* @1 `9 ^" s" m! o //such as, user/1/media --> robbin-zhao/media/ n% L7 @8 v# l' }7 h D, P9 z
if (preg_match('{user/(\d+)/(\w+)}i', $path, $matches)) {4 ]7 O6 q( t$ B5 Y
$uid = $matches[1];
8 a1 y' r- J* q* b $tab = $matches[2];* T9 L; a3 X, M
' D& ^* I7 y# z. t! ? $alias = drupal_lookup_path('alias', "user/$uid");
$ {3 ]6 e$ ]9 o' A, O
/ G0 s8 t7 S# m9 m( j% f- a! h if ($alias != $path) {
8 v- l7 w; D4 z/ L $path = "$alias/$tab";
2 o. \4 u8 x# d }
. Y0 C" {$ f- c //$path = ''8 j L, s$ h; v1 X% Q$ [* n; v1 m' g9 y
}
& H! @+ a9 O/ S9 B5 \+ Y3 y+ f} 优化过的代码已经提交到Drupal官方网站,并且已经是一个第三方模块,大家可以下载使用。 模块地址:http://drupal.org/project/rewrite_sub_link
声明: 本站所有文章欢迎转载,所有文章未说明,均属于原创,转载均请注明出处。 本文有效链接: http://www.drupal001.com/2011/12/drupal-custom-url-alias/ 版权所有: Drupal与高性能网站架构 http://www.drupal001.com |