/[drupal]/contributions/modules/pathauto/pathauto.module
ViewVC logotype

Contents of /contributions/modules/pathauto/pathauto.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.126 - (show annotations) (download) (as text)
Sat Oct 17 17:45:10 2009 UTC (5 weeks, 5 days ago) by greggles
Branch: MAIN
CVS Tags: HEAD
Changes since 1.125: +38 -17 lines
File MIME type: text/x-php
bug #369840 by Dave Reid: If a user changes the automatic path, try to remember that in the future
1 <?php
2 // $Id: pathauto.module,v 1.125 2009/09/25 16:05:39 greggles Exp $
3
4 /**
5 * @defgroup pathauto Pathauto: Automatically generates aliases for content
6 *
7 * The Pathauto module automatically generates path aliases for various kinds of
8 * content (nodes, categories, users) without requiring the user to manually
9 * specify the path alias. This allows you to get aliases like
10 * /category/my-node-title.html instead of /node/123. The aliases are based upon
11 * a "pattern" system which the administrator can control.
12 */
13
14 /**
15 * @file
16 * Main file for the Pathauto module, which automatically generates aliases for content.
17 *
18 * @ingroup pathauto
19 */
20
21 /**
22 * Implementation of hook_help().
23 */
24 function pathauto_help($path, $arg) {
25 switch ($path) {
26 case 'admin/help#pathauto':
27 $output = '<p>'. t('Provides a mechanism for modules to automatically generate aliases for the content they manage.') .'</p>';
28 $output .= '<h2>'. t('Settings') .'</h2>';
29 $output .= '<p>'. t('The <strong>maximum alias length</strong> and <strong>maximum component length</strong> values default to 100 and have a limit of 128 from Pathauto. This length is limited by the length of the "dst" column of the url_alias database table. The default database schema for this column is 128. If you set a length that is equal to that of the one set in the "dst" column it will cause problems in situations where the system needs to append additional words to the aliased URL. For example, URLs generated for feeds will have "/feed" added to the end. You should enter a value that is the length of the "dst" column minus the length of any strings that might get added to the end of the URL. The length of strings that might get added to the end of your URLs depends on which modules you have enabled and on your Pathauto settings. The recommended and default value is 100.') .'</p>';
30 $output .= '<p>'. t('<strong>Raw tokens</strong>: In Pathauto it is appropriate to use the -raw form of tokens. Paths are sent through a filtering system which ensures that raw user content is filtered. Failure to use -raw tokens can cause problems with the Pathauto punctuation filtering system.') .'</p>';
31 return $output;
32 }
33 }
34
35 /**
36 * Implementation of hook_perm().
37 */
38 function pathauto_perm() {
39 return array('administer pathauto', 'notify of path changes');
40 }
41
42 /**
43 * Implementation of hook_menu().
44 */
45 function pathauto_menu() {
46 $items['admin/build/path/pathauto'] = array(
47 'title' => 'Automated alias settings',
48 'page callback' => 'drupal_get_form',
49 'page arguments' => array('pathauto_admin_settings'),
50 'access callback' => 'user_access',
51 'access arguments' => array('administer pathauto'),
52 'type' => MENU_LOCAL_TASK,
53 'weight' => 10,
54 'file' => 'pathauto.admin.inc',
55 );
56
57 $items['admin/build/path/delete_bulk'] = array(
58 'title' => 'Delete aliases',
59 'page callback' => 'drupal_get_form',
60 'page arguments' => array('pathauto_admin_delete'),
61 'access arguments' => array('administer url aliases'),
62 'type' => MENU_LOCAL_TASK,
63 'file' => 'pathauto.admin.inc',
64 );
65
66 return $items;
67 }
68
69 /**
70 * Include all Pathauto include files.
71 */
72 function _pathauto_include() {
73 module_load_include('inc', 'pathauto');
74 module_load_include('inc', 'pathauto', 'pathauto_node');
75 module_load_include('inc', 'pathauto', 'pathauto_taxonomy');
76 module_load_include('inc', 'pathauto', 'pathauto_user');
77 }
78
79 /**
80 * Implementation of hook_token_values() for Pathauto specific tokens.
81 */
82 function pathauto_token_values($type, $object = NULL) {
83 if (module_exists('taxonomy')) {
84 if ($type == 'taxonomy' || $type == 'node' || $type == 'all') {
85 _pathauto_include();
86 switch ($type) {
87 case 'node':
88 // Get the bookpathalias token
89 $values['bookpathalias'] = '';
90 // We're on a node and it's a book and it has a parent? Get the book path alias.
91 if (module_exists('book') && !empty($object->book['menu_name'])) {
92 for ($i = 1; $i < 10; $i++) {
93 $second_child = $i + 2;
94 if ($object->book["p$second_child"] === 0) {
95 $parent_node = db_result(db_query('SELECT link_path FROM {menu_links} WHERE mlid = %d', $object->book["p$i"]));
96 break;
97 }
98 }
99 $values['bookpathalias'] = drupal_get_path_alias($parent_node);
100 }
101
102 // Get taxonomy related data.
103 $vid = db_result(db_query_range("SELECT t.vid FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.vid = %d ORDER BY v.weight, t.weight, t.name", $object->vid, 0, 1));
104 $category = db_fetch_object(db_query_range("SELECT t.tid, t.name FROM {term_data} t INNER JOIN {term_node} r ON r.tid = t.tid WHERE t.vid = %d AND r.nid = %d ORDER BY weight", $vid, $object->nid, 0, 1));
105 $category->vid = $vid;
106 // In the realm of nodes these are terms, in the realm of Taxonomy, cats
107 $label = 'term';
108
109 case 'taxonomy':
110 default:
111 if (!isset($category)) {
112 $category = $object;
113 }
114 if (!isset($label)) {
115 $label = 'cat';
116 }
117 if (isset($category->tid)) {
118 $separator = variable_get('pathauto_separator', '-');
119 $parents = taxonomy_get_parents_all($category->tid);
120 array_shift($parents);
121 $catpath = '';
122 $catpath_raw = '';
123 foreach ($parents as $parent) {
124 // Replace any / characters in individual terms which might create confusing URLs
125 $catpath = pathauto_cleanstring(check_plain(preg_replace('/\//', '', $parent->name))) .'/'. $catpath;
126 $catpath_raw = pathauto_cleanstring(preg_replace('/\//', '', $parent->name)) .'/'. $catpath_raw;
127 }
128 $values[$label .'path'] = $catpath .'/'. check_plain($category->name);
129 $values[$label .'path-raw'] = $catpath_raw .'/'. $category->name;
130 $values[$label .'alias'] = drupal_get_path_alias('taxonomy/term/'. $category->tid);
131 if (!strncasecmp($values[$label .'alias'], 'taxonomy', 8)) {
132 $values[$label .'alias'] = check_plain($category->name);
133 }
134 }
135 else { // Provide some defaults if they aren't set.
136 $values[$label .'path'] = '';
137 $values[$label .'path-raw'] = '';
138 $values[$label .'alias'] = '';
139 }
140 }
141 return $values;
142 }
143 }
144 }
145
146 /**
147 * Implementation of hook_token_list() for Pathauto specific tokens.
148 */
149 function pathauto_token_list($type = 'all') {
150 $tokens = array();
151 if (module_exists('taxonomy')) {
152 if ($type == 'taxonomy' || $type == 'all') {
153 $tokens['taxonomy']['catpath'] = t('As [cat], but including its supercategories separated by /.');
154 $tokens['taxonomy']['catpath-raw'] = t('As [cat-raw], but including its supercategories separated by /. WARNING - raw user input.');
155 $tokens['taxonomy']['catalias'] = t('URL alias for the term.');
156 }
157 if ($type == 'node' || $type == 'all') {
158 $tokens['node']['termpath'] = t('As [term], but including its supercategories separated by /.');
159 $tokens['node']['termpath-raw'] = t('As [term-raw], but including its supercategories separated by /. WARNING - raw user input.');
160 $tokens['node']['termalias'] = t('URL alias for the term.');
161 }
162 }
163 if (module_exists('book')) {
164 if ($type == 'node' || $type == 'all') {
165 $tokens['node']['bookpathalias'] = t('URL alias for the parent book.');
166 }
167 }
168 return $tokens;
169 }
170
171 /**
172 * Implementation of hook_path_alias_types().
173 *
174 * Used primarily by the bulk delete form.
175 */
176 function pathauto_path_alias_types() {
177 $objects = array('user/' => t('Users'), 'node/' => t('Content'));
178 if (module_exists('blog')) {
179 $objects['blog/'] = t('User blogs');
180 }
181 if (module_exists('taxonomy')) {
182 $objects['taxonomy/'] = t('Vocabularies and terms');
183 }
184 if (module_exists('taxonomy')) {
185 $objects['user/%/track'] = t('User trackers');
186 }
187 if (module_exists('forum')) {
188 $objects['forum/%'] = t('Forums');
189 }
190 return $objects;
191 }
192
193 //==============================================================================
194 // Some node related functions.
195
196 /**
197 * Implementation of hook_nodeapi().
198 */
199 function pathauto_nodeapi(&$node, $op, $teaser, $page) {
200 if (module_exists('path')) {
201 switch ($op) {
202 case 'presave':
203 // About to be saved (before insert/update)
204 if (!empty($node->pathauto_perform_alias) && isset($node->old_alias)
205 && $node->path == '' && $node->old_alias != '') {
206 /**
207 * There was an old alias, but when pathauto_perform_alias was checked
208 * the javascript disabled the textbox which led to an empty value being
209 * submitted. Restoring the old path-value here prevents the Path module
210 * from deleting any old alias before Pathauto gets control.
211 */
212 $node->path = $node->old_alias;
213 }
214 break;
215 case 'insert':
216 case 'update':
217 _pathauto_include();
218 // Get the specific pattern or the default
219 if (variable_get('language_content_type_'. $node->type, 0)) {
220 $pattern = trim(variable_get('pathauto_node_'. $node->type .'_'. $node->language .'_pattern', FALSE));
221 }
222 if (empty($pattern)) {
223 $pattern = trim(variable_get('pathauto_node_'. $node->type .'_pattern', FALSE));
224 if (empty($pattern)) {
225 $pattern = trim(variable_get('pathauto_node_pattern', FALSE));
226 }
227 }
228 // Only do work if there's a pattern
229 if ($pattern) {
230 // Only create an alias if the checkbox was not provided or if the checkbox was provided and is checked
231 if (!isset($node->pathauto_perform_alias) || $node->pathauto_perform_alias) {
232 $placeholders = pathauto_get_placeholders('node', $node);
233 $src = "node/$node->nid";
234 $alias = pathauto_create_alias('node', $op, $placeholders, $src, $node->nid, $node->type, $node->language);
235 }
236 }
237 break;
238 case 'delete':
239 path_set_alias('node/'. $node->nid);
240 path_set_alias('node/'. $node->nid .'/feed');
241 break;
242 default:
243 break;
244 }
245 }
246 }
247
248 /**
249 * Implementation of hook_form_alter().
250 *
251 * This allows alias creators to override Pathauto and specify their
252 * own aliases (Pathauto will be invisible to other users). Inserted
253 * into the path module's fieldset in the node form.
254 */
255 function pathauto_form_alter(&$form, $form_state, $form_id) {
256 // Process only node forms.
257 if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) {
258 $node = $form['#node'];
259 $pattern = FALSE;
260
261 // Find if there is an automatic alias pattern for this node type.
262 if (isset($form['language'])) {
263 $language = isset($form['language']['#value']) ? $form['language']['#value'] : $form['language']['#default_value'];
264 $pattern = trim(variable_get('pathauto_node_'. $form['type']['#value'] .'_'. $language .'_pattern', ''));
265 }
266 if (!$pattern) {
267 $pattern = trim(variable_get('pathauto_node_'. $form['type']['#value'] .'_pattern', ''));
268 if (!$pattern) {
269 $pattern = trim(variable_get('pathauto_node_pattern', ''));
270 }
271 }
272
273 // If there is a pattern, show the automatic alias checkbox.
274 if ($pattern) {
275 if (!isset($node->pathauto_perform_alias)) {
276 if (isset($node->nid)) {
277 // If this is not a new node, compare it's current alias to the
278 // alias that would be genereted by pathauto. If they are the same,
279 // then keep the automatic alias enabled.
280 _pathauto_include();
281 $placeholders = pathauto_get_placeholders('node', $node);
282 $pathauto_alias = pathauto_create_alias('node', 'return', $placeholders, "node/{$node->nid}", $node->nid, $node->type, $node->language);
283 $node->pathauto_perform_alias = isset($node->path) && $node->path == $pathauto_alias;
284 }
285 else {
286 // If this is a new node, enable the automatic alias.
287 $node->pathauto_perform_alias = TRUE;
288 }
289 }
290
291 // Add JavaScript that will disable the path textfield when the automatic
292 // alias checkbox is checked.
293 drupal_add_js(drupal_get_path('module', 'pathauto') .'/pathauto.js');
294
295 $form['path']['pathauto_perform_alias'] = array(
296 '#type' => 'checkbox',
297 '#title' => t('Automatic alias'),
298 '#default_value' => $node->pathauto_perform_alias,
299 '#description' => t('An alias will be generated for you. If you wish to create your own alias below, uncheck this option.'),
300 '#weight' => -1,
301 );
302
303 if (user_access('administer pathauto')) {
304 $form['path']['pathauto_perform_alias']['#description'] .= ' '. t('To control the format of the generated aliases, see the <a href="@pathauto">automated alias settings</a>.', array('@pathauto' => url('admin/build/path/pathauto')));
305 }
306
307 if ($node->pathauto_perform_alias && !empty($node->old_alias) && empty($node->path)) {
308 $form['path']['path']['#default_value'] = $node->old_alias;
309 $node->path = $node->old_alias;
310 }
311
312 // For Pathauto to remember the old alias and prevent the Path-module from deleteing it when Pathauto wants to preserve it
313 if (isset($node->path)) {
314 $form['path']['old_alias'] = array(
315 '#type' => 'value',
316 '#value' => $node->path,
317 );
318 }
319 }
320 }
321 }
322
323 /**
324 * Implementation of hook_node_operations().
325 */
326 function pathauto_node_operations() {
327 $operations = array(
328 'update_alias' => array(
329 'label' => t('Update path alias'),
330 'callback' => 'pathauto_node_operations_update',
331 ),
332 );
333 return $operations;
334 }
335
336 /**
337 * Callback function for updating node aliases.
338 *
339 * @param $nodes
340 * Array of node nid's.
341 */
342 function pathauto_node_operations_update($nodes) {
343 _pathauto_include();
344 foreach ($nodes as $nid) {
345 $node = node_load($nid);
346 $placeholders = pathauto_get_placeholders('node', $node);
347 pathauto_create_alias('node', 'bulkupdate', $placeholders, "node/$node->nid", $node->nid, $node->type);
348 }
349 }
350
351 //==============================================================================
352 // Taxonomy related functions.
353
354 /**
355 * Implementation of hook_taxonomy().
356 */
357 function pathauto_taxonomy($op, $type, $object = NULL) {
358 switch ($type) {
359 case 'term':
360 switch ($op) {
361 case 'insert':
362 case 'update':
363 _pathauto_include();
364 // Use the category info to automatically create an alias
365 $category = (object) $object;
366 if ($category->name) {
367 $count = _taxonomy_pathauto_alias($category, $op);
368 }
369
370 // For all children generate new alias (important if [catpath] used)
371 foreach (taxonomy_get_tree($category->vid, $category->tid) as $subcategory) {
372 $count = _taxonomy_pathauto_alias($subcategory, $op);
373 }
374
375 break;
376 case 'delete':
377 // If the category is deleted, remove the path aliases
378 $category = (object) $object;
379 path_set_alias('taxonomy/term/'. $category->tid);
380 path_set_alias(taxonomy_term_path($category));
381 path_set_alias('forum/'. $category->tid);
382 path_set_alias('taxonomy/term/'. $category->tid .'/0/feed');
383 break;
384 default:
385 break;
386 }
387 break;
388 default:
389 break;
390 }
391 }
392
393 //==============================================================================
394 // User related functions.
395
396 /**
397 * Implementation of hook_user() for users, trackers, and blogs.
398 */
399 function pathauto_user($op, &$edit, &$user, $category = FALSE) {
400 switch ($op) {
401 case 'insert':
402 case 'update':
403 _pathauto_include();
404 // Use the username to automatically create an alias
405 $pathauto_user = (object) array_merge((array) $user, $edit);
406 if ($user->name) {
407 $placeholders = pathauto_get_placeholders('user', $pathauto_user);
408 $src = 'user/'. $user->uid;
409 $alias = pathauto_create_alias('user', $op, $placeholders, $src, $user->uid);
410
411 if (module_exists('blog')) {
412 $new_user = drupal_clone($user);
413 if ($category == 'account') {
414 $new_user->roles = isset($edit['roles']) ? $edit['roles'] : array();
415 $new_user->roles[DRUPAL_AUTHENTICATED_RID] = t('authenticated user'); // Add this back
416 }
417 if (user_access('create blog entries', $new_user)) {
418 $src = 'blog/'. $user->uid;
419 $alias = pathauto_create_alias('blog', $op, $placeholders, $src, $user->uid);
420 }
421 else {
422 path_set_alias('blog/'. $user->uid);
423 path_set_alias('blog/'. $user->uid .'/feed');
424 }
425 }
426 if (module_exists('tracker')) {
427 $src = 'user/'. $user->uid .'/track';
428 $alias = pathauto_create_alias('tracker', $op, $placeholders, $src, $user->uid);
429 }
430 if (module_exists('contact')) {
431 $src = 'user/'. $user->uid .'/contact';
432 $alias = pathauto_create_alias('contact', $op, $placeholders, $src, $user->uid);
433 }
434 }
435 break;
436 case 'delete':
437 // If the user is deleted, remove the path aliases
438 $user = (object) $user;
439 path_set_alias('user/'. $user->uid);
440
441 // They may have enabled these modules and/or feeds when the user was created, so let's try to delete all of them
442 path_set_alias('blog/'. $user->uid);
443 path_set_alias('blog/'. $user->uid .'/feed');
444 path_set_alias('user/'. $user->uid .'/track');
445 path_set_alias('user/'. $user->uid .'/track/feed');
446 path_set_alias('user/'. $user->uid .'/contact');
447 break;
448 default:
449 break;
450 }
451 }

  ViewVC Help
Powered by ViewVC 1.1.2