אחת הדרכים הנוחות ביותר ליצירת url אוטומטי בדרופל הוא המודול הנהדר pathauto, אבל בחלק מהמקרים אי אפשר להשתמש בו – כאשר אנחנו רוצים פונקציונליות שאין ב-pathauto, או כאשר אנו צריכים תמיכה יותר טובה באתרים בינלאומיים. באחד המקרים, הייתי צריך ליצור מודול שמבצע יצירה אוטומטית של url_alias לפי פרמטרים שלא היה ניתן לבצע ב-pathauto.
איך עושים את זה? קודם כל יוצרים מודול (אני מניח שאופן יצירת מודולים בדרופל מוכר לכם, אם לא – הכנסו למאמר המסביר על בניית מודול בדרופל 6/7). אחרי כן אנו ניצור hook שיתחבר ל-node בשלב ה-presave, קצת לפני שהוא נכנס למסד הנתונים. אחרי כן, אנו ניקח את הכותרת של ה-node שלנו, נמיר אותה לפורמט URL מוכר ונחבר אליה תחילית. התחילית מורכבת מהאבא של ה-taxonomy (שהוא לא Multiple select). לבסוף, נוודא שאין url_alias כזה כבר. במידה ויש, ניצור אחד חדש ובמידה ולא, נוסיף את ה-url_alias החדש ל-node החדש שלנו.
הגדרת ה-vocabulary
ראשית נגדיר ידנית את מספר ה-vocabulary לפי ה-vocabulary שאנו רוצים לעבוד לפיו.
define("VID", 5);
אחרי כן נשתמש ב-hook_nodeapi על מנת לתפוס את ה-node בשלב ה-presave, לפני שהוא נכנס למסד הנתונים.
/**
*
* Implementation of hook_nodeapi
* @param $node
* @param $op
* @param $a3
* @param $a4
*/
function generate_url_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
if($op == 'presave') {
if(!$node->path || $node->path == '') { //Insert path if non existing. based on title and Topics taxonomy.
$title = clean_my_url(get_term_ancestor($node->taxonomy[VID]));
$title .= '/'.clean_my_url($node->title);
$node->path = prevent_double_url($title);
}
}
}
במידה ואין לנו url_alias, אנו נתחיל ביצירה שלו. ראשית, אנו רוצים לקבל את תגית האב – וזה העבודה העיקרית במודול הזה. יצירתי פונקציה בשם get_term_ancestor שמקבלת תגית כלשהי ומחזירה את תגית האב:
/**
*
* Returning the term ancestor name from tid
* @param integer $tid
*/
function get_term_ancestor($tid) {
return end(taxonomy_get_parents_all($tid))->name;
}
taxonomy_get_parents_all מחזירה לי מערך של כל תגיות ההורים (במידה ויש כמה) לפי סדר היררכי. האבר האחרון של המערך הוא תגית האב. עם פונקצית end אני מחלץ את האבר הזה ומחזיר את שמו.
פונקצית clean_my_url מנקה כל string כדי שיתאים ל-URL:
/**
*
* take string and making from it nice string for URL. ie dashes and not spaces,
* without ? and other non URL charactars.
* @param unknown_type $string
*/
function clean_my_url($string) {
$cleanUrl = str_replace(' ', '-',strtolower(trim($string))); //removing blanks and replacing those with -
$cleanUrl = preg_replace('/[\?\.\/,:\(\)]/', '', $cleanUrl); //remove bad charactars for URL
return $cleanUrl;
}
כלומר, כל תו לא מתאים ינוקה. אחרי זה כל מה שנותר לנו לעשות זה להוסיף את ה-node->title ולהעביר גם אותו ניקיון. יש לי url! עכשיו כל מה שנותר זה להעביר אותו בפונקצית prevent_double_url שתוודא שאין עוד URL כזה ובמידה וכן – תוסיף מספר רנדומלי ל-URL ותבדוק שוב.
/**
*
* Check if there is duplicate URL and if there is, run recursively to generate another one
* @param string $url
*/
function prevent_double_url($url) {
$sql = sprintf("SELECT dst
FROM url_alias
WHERE dst = '%s'
LIMIT 1
", $url);
$rawResults = db_query($sql);
$results = db_fetch_object($rawResults)->dst;
$i = rand(0,9);
if($results) { //If there is another URL in that name - enter into recursive
$url .= $i;
return prevent_double_url($url);
}
else {
return $url;
}
}
ה-URL המתקבל מהפונקציה הזו הוא חד חד ערכי וניתן לשמור אותו ב-node->path.
כמובן שאפשר לשנות את פונקצית generate_url_nodeapi לפי הצורך ולא להשתמש ב-Taxonomy אלא בכל פרמטר אחר שרוצים.
התאמה לדרופל 7
בדרופל 7 אין hook_nodeapi שיש בו פרמטר op אלא לכל op יש hook משלו. לפיכך hook_nodeapi עם op=save משתנה ל-hook_node_presave:
/**
*
* Implementation of hook_node_presave
* @param $node
*/
function generate_url_node_presave(&$node, $op, $a3 = NULL, $a4 = NULL) {
if(!$node->path || $node->path == '') { //Insert path if non existing. based on title and Topics taxonomy.
$title = clean_my_url(get_term_ancestor($node->taxonomy[VID]));
$title .= '/'.clean_my_url($node->title);
$node->path = prevent_double_url($title);
}
}
מעבר לכך אין שינויים בדרופל 7