page_title.module 31.3 KB
Newer Older
1 2 3
<?php

/**
JohnAlbin's avatar
JohnAlbin committed
4 5 6
 * @file
 * Enhanced control over the page title (in the head tag).
 *
7
 * This module gives you control over the page title. It gives you the chance
8
 * to provide patterns for how the title should be structured, and on node
9 10 11 12
 * pages, gives you the chance to specify the page title rather than defaulting
 * to the node title.
 */

13

14 15 16
/**
 * Implementation of hook_help().
 */
17
function page_title_help($path, $arg) {
18
  $output = NULL;
19
  switch ($path) {
20 21 22
    case 'admin/settings/page-title':
      $output  = '<p>'. t('Page Title provides control over the <code>&lt;title></code> element on a page using token patterns and an optional textfield to override the title of the item (be it a node, term, user or other). The Token Scope column lets you know which tokens are available for this field (Global is always available). Please click on the <strong><em>more help&hellip;</em></strong> link below if you need further assistance.') .'</p>';
      $output .= '<p>'. l(t('More Help...'), 'admin/help/page_title') .'</p>';
23
      break;
24 25 26 27 28 29 30 31 32 33
    case 'admin/help#page_title':
      $output  = '<p>'. t('Drupal\'s default page title follows one of two patterns:') .'</p>';
      $items = array(
        t('<strong>Default Page</strong>: <samp><em>page title</em> | <em>site name</em></samp>'),
        t('<strong>Default Frontpage</strong>: <samp><em>site name</em> | <em>site slogan</em></samp>'),
      );
      $output .= theme('item_list', $items, NULL, 'ol');
      $output .= '<p>'. t('The <strong>Page Title</strong> module lets you change these defaults in two ways. First, you can adjust the patterns below using the placeholders given. This will change the way the default page titles are created. Second, on enabled forms (curently node, term & user editing forms) you have the option of specifying a title that is different to the title of the item. This field only appears if the <em>Show Field</em> box is checked for the item. If a value is provided it will be used to generate the <samp>[page-title]</samp> placeholder however if it is left blank the <samp>[page-title]</samp> token will inherit the item\'s own title.') .'</p>';
      $output .= '<p>'. t('The <samp>[page-title]</samp> token will default to the value returned from <samp>drupal_get_title</samp> if there is no value specified or no available page title field.') .'</p>';
      $output .= '<p>'. t('Certain types of page title pattern have access to special tokens which others do not, depending on their <em>scope</em>. All patterns have access to the <strong>Global</strong> scope. Content type patterns have access to the <strong>Node</strong> tokens, vocabulary patterns have access to the <strong>Taxonomy</strong> tokens and finally the user patterns have access to the <strong>User</strong> tokens.') .'</p>';
34
      break;
35 36 37 38
  }
  return $output;
}

39

40 41 42 43 44 45
/**
 * Implementation of hook_requirements().
 */
function page_title_requirements($phase) {
  $requirements = array();
  if ($phase == 'runtime') {
46 47
    // Are we on an old version?
    if (!page_title_is_up_to_date()) {
48 49 50 51 52
      $requirements['page_title_version'] = array(
        'title' => t('Page title version'),
        'value' => t('Out of date'),
        'description' => t('The Page Title module must be updated. You should run the !link immediately.', array('!link' => l(t('database update script'), 'update.php'))),
        'severity' => REQUIREMENT_ERROR,
53 54
      );
    }
55
    // Nope - we're on the latest version
56
    else {
57
      // Does the old table exist (it is left after the upgrade in case an admin wants to check the upgrade went ok)
58 59 60 61 62 63 64 65 66 67 68
      if (db_table_exists('page_title_old')) {
        $requirements['upgrade_table'] = array(
          'title' => t('Page Title upgrade table present'),
          'value' => '',
          'description' => t('The Page Title upgrade table (<code>page_title_old</code>) is present. You can remove it !link', array(
            '!link' => l(t('using this script'), 'admin/settings/page-title/drop-old-table'),
          )),
          'severity' => REQUIREMENT_WARNING,
        );
      }

69 70 71 72 73 74 75 76 77
      // If the page title module exists, check it has the right columns - there are reports of upgrade issues.
      // If the table doesn't exists, reinstall the module!
      if (!db_table_exists('page_title') || db_column_exists('page_title', 'nid')) {
        $requirements['page_title_version'] = array(
          'title' => t('Page title version'),
          'value' => t('Incorrect Schema'),
          'description' => t('It appears Drupal thinks the module is up to date, however the database schema is incorrect. Please uninstall and reinstall the module.'),
          'severity' => REQUIREMENT_ERROR,
        );
78 79
      }
      else {
80 81
        // Everything seems ok...
        $rows = db_result(db_query('SELECT COUNT(*) FROM {page_title}'));
82

83 84 85 86 87
        $requirements['page_title_version'] = array(
          'title' => t('Page title version'),
          'value' => t('Enabled (<code>page_title</code> table contains !rows)', array('!rows' => format_plural($rows, '1 row', '@count rows'))),
          'severity' => REQUIREMENT_OK,
        );
88 89
      }
    }
90 91 92 93 94
  }

  return $requirements;
}

95

96 97 98 99
/**
 * Implementation of hook_perm().
 */
function page_title_perm() {
100
  return array('set page title', 'administer page titles');
101 102
}

103

104

105 106 107
/**
 * Implementation of hook_menu().
 */
108
function page_title_menu() {
109 110
  $items = array();

111 112 113
  $items['admin/settings/page-title'] = array(
    'title' => 'Page title',
    'description' => 'Configure the page titles for your site (the title in the &lt;head&gt; tag).',
114 115 116 117 118
    'page callback' => 'drupal_get_form',
    'page arguments' => array('page_title_admin_settings'),
    'access callback' => 'user_access',
    'access arguments' => array('administer page titles'),
    'type' => MENU_NORMAL_ITEM,
119
    'file' => 'page_title.admin.inc',
120 121
  );

122 123 124 125 126 127 128 129 130 131 132
  if (db_table_exists('page_title_old')) {
    $items['admin/settings/page-title/drop-old-table'] = array(
      'title' => 'Drop Old Page Title Table?',
      'page callback' => 'drupal_get_form',
      'page arguments' => array('page_title_drop_old_table_form'),
      'access arguments' => array('administer site configuration'),
      'type' => MENU_CALLBACK,
      'file' => 'page_title.legacy.inc',
    );
  }

133 134 135
  return $items;
}

136 137

/**
138
 * Implementation of hook_theme().
139 140 141 142
 */
function page_title_theme() {
  return array(
    'page_title_admin_settings' => array(
143
      'template' => 'page_title-admin-settings-form',
144 145
      'arguments' => array('form' => NULL),
    ),
146 147 148 149

    'page_title_preprocess_page' => array(
      'arguments' => array('vars' => NULL),
    ),
150 151 152 153
  );
}


154 155 156 157 158 159
/**
 * Implementation of hook_node_type().
 *
 * Updates settings after a node type change.
 */
function page_title_node_type($op, $info) {
160 161
  // Handle a content type rename
  if ($op == 'update' && !empty($info->old_type) && $info->type != $info->old_type) {
162 163
    // Load the old node type settings.
    $temp = variable_get('page_title_type_'. $info->old_type, '');
164

165 166 167
    // If the settings aren't empty, then save them into the new type
    if (!empty($temp)) {
      variable_set('page_title_type_'. $info->type, $temp);
168
    }
169

170
    // Delete the old setting
171
    variable_del('page_title_type_'. $info->old_type);
172

173 174 175 176
    // Essentially, do the same as above but with the _showfield suffix for the node type
    $temp = variable_get('page_title_type_'. $info->old_type .'_showfield', 0);
    if ($temp) {
      variable_set('page_title_type_'. $info->type .'_showfield', $temp);
177
    }
178 179 180 181 182 183 184 185
    variable_del('page_title_type_'. $info->old_type .'_showfield');

  }

  // If deleted, remove the variables
  if ($op == 'delete') {
    variable_del('page_title_type_'. $info->type);
    variable_del('page_title_type_'. $info->type .'_showfield');
186 187 188
  }
}

189

190 191 192
/**
 * Implementation of hook_form_alter().
 */
193
function page_title_form_alter(&$form, $form_state, $form_id) {
194
  // If we dont have permission to set the title then we need to abort this alter now!
195
  if (!user_access('set page title')) return;
196

197 198 199 200
  // Check we're editing a node and also check that the node type's 'show field' is enabled
  if ($form['#id'] == 'node-form') {
    $key = 'page_title_type_'. $form['type']['#value'] .'_showfield';
    if (variable_get($key, 0)) {
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
      $page_title = isset($form['#node']->page_title) ? $form['#node']->page_title : NULL;

      // If we have vertical tabs installed, we need to render the form element slightly differently
      $show_vertical_tabs = FALSE;
      if (module_exists('vertical_tabs')) {
        if (arg(0) == 'admin') {
          // If its an admin page, we must render it as a fieldset - the vertical tabs allows per-fieldset disabling. We have to render a fieldset to allow the option to disable it.
          $show_vertical_tabs = TRUE;
        }
        else {
          // This isn't an admin page, we should decide whether to render the page title fieldset depending on if the setting is set.
          $show_vertical_tabs = ($vt_conf = vertical_tabs_get_config($form_id)) && ($vt_conf['page_title'] !== 0);
        }
      }

      // If we have decided to show vertical tabs, render the page_title element into a fieldset, otherwise just a textfield with a weight putting it at the top.
      if ($show_vertical_tabs) {
        $form['page_title'] = array(
          '#type' => 'fieldset',
          '#title' => t('Page Title settings'),
          '#collapsible' => TRUE,
          '#collapsed' => empty($page_title),
          '#group' => 'additional_settings',
          '#weight' => 35,
          '#attached' => array(
            'js' => array(
              'vertical-tabs' => drupal_get_path('module', 'page_title') . '/page_title.js',
            ),
          ),
        );
        $form['page_title']['page_title'] = array(
          '#type' => 'textfield',
          '#title' => t('Page title'),
          '#description' => t('Provide a description of this node to appear in the &lt;title&gt; tag which search engines can use in search result listings (optional). It is generally accepted this field should be less than 70 characters.'),
          '#default_value' => $page_title,
          '#size' => 60,
          '#maxlength' => 255,
        );
      }
      else {
        $form['page_title'] = array(
          '#type' => 'textfield',
          '#title' => t('Page title'),
          '#description' => t('Provide a description of this node to appear in the &lt;title&gt; tag which search engines can use in search result listings (optional). It is generally accepted this field should be less than 70 characters.'),
          '#default_value' => $page_title,
          '#size' => 60,
          '#maxlength' => 255,
          '#weight' => -4,
        );
      }
251
      drupal_add_js(drupal_get_path('module', 'page_title') . '/page_title.js', 'module', 'header', FALSE, TRUE, FALSE);
252 253
    }
  }
254 255 256 257 258 259 260
}


/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function page_title_form_taxonomy_form_term_alter(&$form, &$form_state) {
261
  // Check we're editing a taxonomy term and also check that the terms vocabulary's 'show field' is enabled
262 263 264 265 266 267
  $key = 'page_title_vocab_'. $form['vid']['#value'] .'_showfield';
  if (variable_get($key, 0)) {
    $form['advanced']['page_title'] = array(
      '#type' => 'textfield',
      '#title' => t('Page title'),
      '#description' => t('Provide a description of this term to appear in the &lt;title&gt; tag which search engines can use in search result listings (optional). It is generally accepted this field should be less than 70 characters.'),
268
      '#default_value' => isset($form['tid']['#value']) ? page_title_load_title($form['tid']['#value'], 'term') : '',
269 270 271 272
      '#size' => 60,
      '#maxlength' => 255,
      '#weight' => -20,
    );
273
    drupal_add_js(drupal_get_path('module', 'page_title') . '/page_title.js', 'module', 'header', FALSE, TRUE, FALSE);
274
  }
275 276 277 278 279 280 281
}


/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function page_title_form_forum_form_forum_alter(&$form, &$form_state) {
282
  // Check we're editing a forum container or forum "forum" and also check that the terms vocabulary's 'show field' is enabled
283 284
  $key = 'page_title_vocab_'. $form['vid']['#value'] .'_showfield';
  if (variable_get($key, 0)) {
285
    $form['page_title'] = array(
286 287 288 289 290 291 292
      '#type' => 'textfield',
      '#title' => t('Page title'),
      '#description' => t('Provide a description of this forum to appear in the &lt;title&gt; tag which search engines can use in search result listings (optional). It is generally accepted this field should be less than 70 characters.'),
      '#default_value' => isset($form['tid']['#value']) ? page_title_load_title($form['tid']['#value'], 'term') : '',
      '#size' => 60,
      '#maxlength' => 255,
      '#weight' => -20,
293
    );
294
    drupal_add_js(drupal_get_path('module', 'page_title') . '/page_title.js', 'module', 'header', FALSE, TRUE, FALSE);
295 296 297 298 299 300 301 302 303 304 305
  }
}


/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function page_title_form_forum_form_container_alter(&$form, &$form_state) {
  // Check we're editing a forum container or forum "forum" and also check that the terms vocabulary's 'show field' is enabled
  page_title_form_forum_form_forum_alter($form, $form_state);
}
306 307


308 309 310 311 312 313 314
/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function page_title_form_user_profile_form_alter(&$form, &$form_state) {
  // Check we're editing a user profile and also check that the user settings's have 'show field' enabled
  if (variable_get('page_title_user_showfield', 0)) {
    $form['account']['page_title'] = array(
315
      '#type' => 'textfield',
316 317 318 319 320 321
      '#title' => t('Page title'),
      '#description' => t('Provide a description of this user to appear in the &lt;title&gt; tag which search engines can use in search result listings (optional). It is generally accepted this field should be less than 70 characters.'),
      '#default_value' => page_title_load_title($form['_account']['#value']->uid, 'user'),
      '#size' => 60,
      '#maxlength' => 255,
      '#weight' => 20,
322
    );
323
    drupal_add_js(drupal_get_path('module', 'page_title') . '/page_title.js', 'module', 'header', FALSE, TRUE, FALSE);
324
  }
325 326 327
}


328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
/**
 * Implementation of hook_form_FORM_ID_alter().
 */
function page_title_form_node_type_form_alter(&$form, &$form_state) {
  // Alter the node type form - allows easy access to the per-content type page title settings
  $form['page_title'] = array(
    '#type' => 'fieldset',
    '#title' => t('Page Title Settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#tree' => TRUE,
  );

  $form['page_title']['show_field'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Page Title Field'),
    '#description' => t('If checked, the <em>Page Title</em> field will appear on the node edit form for those who have permission to set the title.'),
    '#options' => array(
      'show_field' => t('Show field'),
    ),
    '#default_value' => variable_get('page_title_type_'. $form['#node_type']->type .'_showfield', 0) ? array('show_field') : array(),
  );

  $form['page_title']['pattern'] = array(
    '#type' => 'textfield',
    '#title' => t('Page Title Pattern'),
    '#default_value' => variable_get('page_title_type_'. $form['#node_type']->type, ''),
355
    '#description' => t('Enter the <em>Page Title</em> pattern you want to use for this node type. For more information, please use the !link settings page', array('!link' => l('Page Title', 'admin/settings/page-title'))),
356
    '#maxlength' => 255,
357 358 359 360 361 362
  );

  $form['#submit'][] = 'page_title_node_type_form_submit';
}


363
/**
364
 * Submit handler for the node_type_form element added in the hook_form_alter() above.
365 366 367 368 369
 */
function page_title_node_type_form_submit($form, &$form_state) {
  $show_field = $form_state['values']['page_title']['show_field']['show_field'] ? 1 : 0;
  variable_set('page_title_type_'. $form_state['values']['type'] .'_showfield', $show_field);
  variable_set('page_title_type_'. $form_state['values']['type'], $form_state['values']['page_title']['pattern']);
370 371 372

  // For some reason the node module adds the fieldset as a separate entry in the variables table... we dont want this!
  variable_del('page_title_'. $form_state['values']['type']);
373 374 375

  // Flush the settings on update/insert.
  page_title_get_settings(TRUE);
376 377
}

378

379 380 381
/**
 * Implementation of hook_nodeapi().
 */
382 383 384
function page_title_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
  switch ($op) {
    case 'update':
385
      if (isset($node->page_title) && user_access('set page title')) {
386
        db_query("DELETE FROM {page_title} WHERE type = 'node' AND id = %d", $node->nid);
387
      }
388
      // fallthrough to insert intentional!
389
    case 'insert':
390
      if (isset($node->page_title) && drupal_strlen(trim($node->page_title)) > 0 && user_access('set page title')) {
391
        db_query("INSERT INTO {page_title} VALUES ('node', %d, '%s')", $node->nid, $node->page_title);
392 393 394 395
      }
      break;

    case 'delete':
396
      db_query("DELETE FROM {page_title} WHERE type = 'node' AND id = %d", $node->nid);
397 398 399
      break;

    case 'load':
400 401
      $enabled = (bool)variable_get('page_title_type_'. $node->type .'_showfield', FALSE);
      return array('page_title' => ($enabled ? page_title_load_title($node->nid, 'node') : ''));
402 403 404 405 406 407 408 409
  }
}


/**
 * Implementation of hook_taxonomy().
 */
function page_title_taxonomy($op, $type, $edit) {
410 411
  if ($type == 'vocabulary') {
    switch ($op) {
412
      case 'delete' :
413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
      case 'update' :
      case 'insert' :
        // Flush the settings on update/insert.
        page_title_get_settings(TRUE);
        break;
    }
  }
  elseif ($type == 'term') {
    switch ($op) {
      case 'update':
        if (isset($edit['page_title']) && user_access('set page title')) {
          db_query("DELETE FROM {page_title} WHERE type = 'term' AND id = %d", $edit['tid']);
        }
        // Fallthrough to insert is intentional!
      case 'insert':
        if (isset($edit['page_title']) && drupal_strlen(trim($edit['page_title'])) > 0 && user_access('set page title')) {
          db_query("INSERT INTO {page_title} VALUES('term', %d, '%s')", $edit['tid'], $edit['page_title']);
        }
        break;
432

433
      case 'delete':
434
        db_query("DELETE FROM {page_title} WHERE type = 'term' AND id = %d", $edit['tid']);
435 436
        break;
    }
437 438 439 440 441 442 443 444 445 446
  }
}


/**
 * Implementation of hook_user().
 */
function page_title_user($op, &$edit, &$account) {
  switch ($op) {
    case 'update':
447
      if (isset($edit['page_title']) && user_access('set page title')) {
448
        db_query("DELETE FROM {page_title} WHERE type = 'user' AND id = %d", $account->uid);
449 450 451 452
      }
      // Fallthrough to insert is intentional!
    case 'insert':
      if (isset($edit['page_title']) && drupal_strlen(trim($edit['page_title'])) > 0 && user_access('set page title')) {
453
        db_query("INSERT INTO {page_title} VALUES('user', %d, '%s')", $account->uid, $edit['page_title']);
454 455 456 457
      }
      break;

    case 'delete':
458
      db_query("DELETE FROM {page_title} WHERE type = 'user' AND id = %d", $account->uid);
459
      break;
460 461 462 463
  }
}


464 465 466
/**
 * Simple wrapper function to get the currently set title for a page
 *
467 468 469
 * @param $raw
 *   Optional parameter. If TRUE, the result will not be parsed with filter_xss.
 *
470 471
 * @return
 *   string the title for the current page
472
 */
473 474
function page_title_get_title($raw = FALSE, $flush = FALSE) {
  static $title = NULL;
475

476
  // This is used to internally "cache" the title in case we call the function more than once (which we shouldn't).
477
  if ($flush || is_null($title)) {
478 479
    // Give other modules the oppertunity to use hook_page_title_alter().
    drupal_alter('page_title', $title);
480
  }
481

482
  // Return the title in a safe form (any tags removed (such as emphasised or strong tags) and eny entiied encoded)
483
  return $raw ? $title : filter_xss($title, array());
484
}
485

486 487

/**
488 489 490 491 492 493
 * Gets the page title for a type & id.
 *
 * @param $id
 *   int The objects id.
 * @param $type
 *   string What is the scope (usually 'node', 'term' or 'user').
494
 *
495
 * @return
496 497 498
 *   string the page title for the given type & id.
 */
function page_title_load_title($id, $type) {
499
  return db_result(db_query("SELECT page_title FROM {page_title} WHERE type = '%s' AND id = %d", $type, $id));
500 501 502 503 504 505
}


/**
 * Wrapper for old function...
 * NOTE: This has been depricated in favor of page_title_load_title().
506 507
 */
function page_title_node_get_title($nid) {
508
  return page_title_load_title($nid, 'node');
509 510
}

511

512 513
/**
 * Legacy page title setting function...
514
 * NOTE: This has been deprecated in favour of hook_page_title_alter().
515 516 517 518 519 520 521 522 523 524 525
 */
function page_title_set_title($title = NULL) {
  static $stored_title;

  if (isset($title)) {
    $stored_title = $title;
  }
  return $stored_title;
}


526
/**
527 528 529 530 531
 * Determines what title should be sent to the page template.
 *
 * Call this function from the page hook of function _phptemplate_variables in
 * template.php.
 *
532 533 534
 * @param $raw
 *   Optional parameter to allow the function to return a raw (unfiltered) result. This should be used with caution...
 *
535 536
 * @return
 *   string The page's title.
537
 */
538
function page_title_page_get_title($raw = FALSE) {
JohnAlbin's avatar
JohnAlbin committed
539
  static $title = NULL;
540

JohnAlbin's avatar
JohnAlbin committed
541
  if (is_null($title)) {
542 543 544
    // Initialize some variables we need
    $page_title_pattern = '';
    $types = array('global' => NULL);
545

546

547 548 549 550 551
    // Allow hook_page_title_pattern_alter() to modify the pattern - we cant use drupal_alter as it only supports single arguments (or arrays). We need to pass 2 variables.
    $data = array(&$page_title_pattern, &$types);
    foreach (module_implements('page_title_pattern_alter') as $module) {
      $function = $module .'_page_title_pattern_alter';
      call_user_func_array($function, $data);
JohnAlbin's avatar
JohnAlbin committed
552
    }
553

554 555
    // If pattern is emtpy (either if the type is not overridable or simply not set) fallback to the default pattern)
    if (empty($page_title_pattern)) {
556 557
      $settings = page_title_get_settings();
      $page_title_pattern = variable_get('page_title_default', $settings['page_title_default']['default']);
558
    }
559

560 561
    // Append the pattern for pages with a pager on them
    $page_title_pattern .= isset($_REQUEST['page']) ? variable_get('page_title_pager_pattern', '') : '';
562

563 564 565
    // Apply token patterns by resetting the token cache first and then using token_replace_multiple to insert token values
    token_get_values('global', NULL, TRUE);
    $title = token_replace_multiple($page_title_pattern, $types);
566
  }
567

568
  // Trim trailing whitespace from the title
569 570
  $title = trim($title);

571
  // Use filter_xss to remove any tags and to entity encode content.
572
  return $raw ? $title : filter_xss($title, array());
573
}
574

575

576
/**
577
 * Implementation of hook_token_values().
578 579 580
 *
 * @param
 *   string The type of token being generated
581
 *
582 583 584 585 586
 * @return
 *   array An array of Token ID and Token Value pairs
 */
function page_title_token_values($type) {
  $values = array();
587

588 589
  if ($type == 'global') {
    $values['page-title'] = page_title_get_title();
590
    $values['page-title-raw'] = page_title_get_title(TRUE);
591
  }
592

593 594 595
  return $values;
}

596

597
/**
598
 * Implementation of hook_token_list().
599 600 601
 *
 * @param
 *   string Which type of token list are we generating?
602
 *
603 604 605 606 607 608 609 610
 * @return
 *   array Nested array of Token ID and Token Name pairs.
 */
function page_title_token_list($type = 'all') {
  $tokens = array();

  if ($type == 'global' || $type == 'all') {
    $tokens['global']['page-title'] = t("The page title.");
611
    $tokens['global']['page-title-raw'] = t("The page title. WARNING - raw user input");
612
  }
613

614 615
  return $tokens;
}
616 617 618


/**
619
 * Implementation of hook_preprocess_page().
620 621
 */
function page_title_preprocess_page(&$vars) {
622
  $vars['head_title'] = page_title_page_get_title();
623
}
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643


/**
 * Implementation of hook_content_extra_fields().
 *
 * This allows CCK to control the weight of the Page Title element as a "non-cck field"
 */
function page_title_content_extra_fields($type_name) {
  $extra = array();

  if (variable_get('page_title_type_'. $type_name .'_showfield', 0)) {
    $extra['page_title'] = array(
      'label' => t('Page Title'),
      'description' => t('Page Title form.'),
      'weight' => -4
    );
  }

  return $extra;
}
644

645 646

/**
647
 * Internal function for generating a key for a given view and display. Argument Page Title settings are not stored as variables.
648 649
 * TODO: Should probably clean these up before making the key (so the return value is [a-z0-9\-])
 */
650 651
function _page_title_build_views_keys($view_name, $display_id) {
  return 'page_title-'. implode('-', array_filter(array($view_name, $display_id)));
652 653
}

654

655 656 657
/**
 * Form Alter handler for the views ui config form (used for filters and args)
 */
658 659
function page_title_form_views_ui_config_item_form_alter(&$form, &$form_state) {
  // Don't bother altering non-argument forms
660
  if ($form_state['type'] != 'argument') return;
661

662 663 664
  $view = &$form_state['view'];
  $display_handler = &$view->display_handler;

665
  // Check the display handler is a page - if not, dont bother altering.
666
  if ($display_handler->display->display_plugin != 'page_with_page_title') return;
667

668 669
  // Now check the display has arguments. This ensures we are on an overidden Argument configuration.
  if (!isset($display_handler->options['arguments']) || empty($display_handler->options['arguments'])) return;
670 671

  // Build a page title options fieldset wrapper
672
  $temp_form['page_title_pattern'] = array(
673 674 675 676 677
    '#type' => 'fieldset',
    '#title' => t('Page Title'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
678

679
  // Add the Page Title field
680
  $temp_form['page_title_pattern']['page_title_pattern'] = array(
681 682 683
    '#type' => 'textfield',
    '#title' => t('Page Title Pattern'),
    '#description' => t('Optionally enter a Page Title Pattern for this argument. This will override the main view Page Title Pattern. You can also use the tokens below.'),
684 685
    '#default_value' => $form_state['handler']->options['page_title_pattern'],
    '#parents' => array('options', 'page_title_pattern'),
686
  );
687

688
  // Add the token help to a collapsed fieldset at the end of the configuration page.
689
  $temp_form['page_title_pattern']['token_help'] = array(
690 691 692 693 694
    '#type' => 'fieldset',
    '#title' => t('Available Tokens List'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
695
  $temp_form['page_title_pattern']['token_help']['content'] = array(
696 697 698 699 700 701 702 703 704 705 706 707
    '#type' => 'markup',
    '#value' => theme('token_help', 'global'),
  );

  // Splice the temp form into the main form. We do this because there are no weights in the views form meaning Page Title can either be top or bottom (-1 or 1).
  $offset = array_search('title', array_keys($form['options']));
  $spliced_form = array_splice($form['options'], 0, $offset);
  $form['options'] = array_merge($spliced_form, $temp_form, $form['options']);
}


/**
708
 * Implementation of hook_views_api().
709
 */
710 711 712 713
function page_title_views_api() {
  return array(
    'api' => 2,
  );
714 715 716 717
}


/**
718
 * Implementation of hook_views_plugins().
719
 */
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
function page_title_views_plugins() {
  return array(
    'module' => 'page_title',
    'display' => array(
      'page_with_page_title' => array(
        'title' => t('Page (with Page Title)'),
        'help' => t('Same as a normal Page, but also includes the Page Title control.'),
        'parent' => 'page',
        'uses hook menu' => TRUE,
        'use ajax' => FALSE,
        'use pager' => TRUE,
        'accept attachments' => TRUE,
        'admin' => t('Page with Page Title'),
        'module' => 'page_title',
        'path' => drupal_get_path('module', 'page_title') .'/views/plugins',
        'file' => 'page_title_plugin_display_page_with_page_title.inc',
        'handler' => 'page_title_plugin_display_page_with_page_title',
        'theme' => 'views_view',
        'theme path' => drupal_get_path('module', 'views') .'/theme',
        'theme file' => 'theme.inc',
      ),
    ),
  );
743
}
744 745


746 747 748
/**
 * Get the Page Title settings
 */
749 750 751 752 753 754
function page_title_get_settings($flush = FALSE) {
  static $settings = NULL;

  // Flush the settings, if set.
  if ($flush) {
    $settings = NULL;
755
    cache_clear_all('page_title:settings', 'cache');
756 757 758 759 760 761 762 763
  }

  // If we have it statically cached, return it.
  if (!empty($settings)) {
    return $settings;
  }

  // Get from Cache
764
  if ($cache = cache_get('page_title:settings')) {
765
    $settings = $cache->data;
766 767 768
    return $cache->data;
  }

769 770 771 772
  // Ensure that the page title inc files are included before invoking
  // This helps avoid the issues in #1567790
  page_title_include_api_files();

773 774
  // Get the settings from hook_page_title_settings().
  $settings = module_invoke_all('page_title_settings');
775

776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
  // For each setting, apply a "default" mask (this makes it easier to use
  // later as we can assume presence)
  foreach ($settings as $k => $v) {
    $settings[$k] = (array) $v + array(
      'label' => '',
      'label arguments' => array(),
      'required' => FALSE,
      'show field' => FALSE,
      'description' => '',
      'description arguments' => array(),
      'weight' => 0,
      'default' => '',
    );
  }

  // Now sort
  uasort($settings, '_page_title_settings_sort');

  // Cache this so we dont have to do this EVERY time
  cache_set('page_title:settings', $settings);

  return $settings;
}


/**
 * Internal function for sorting the page title settings array.
 */
function _page_title_settings_sort($a, $b) {
805
  // Sort by weight and, failing that, label alphabetical.
806 807 808 809
  return $a['weight'] < $b['weight'] ? -1 : ($a['weight'] > $b['weight'] ? 1 : ($a['label'] < $b['label'] ? -1 : 1));
}


810
/**
811
 * Implementation of hook_init().
812
 */
813
function page_title_init() {
814
  // Include the admin CSS for the report page - TODO: Is there a better way?
815 816 817
  if (arg(0) == 'admin' && arg(1) == 'reports' && arg(2) == 'page-title') {
    drupal_add_css(drupal_get_path('module', 'page_title') .'/page_title.admin.css');
  }
818

819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
  page_title_include_api_files();
}


/**
 * Function to ensure API files are included.
 * We use a static variable so we can use include, which is faster than include_one
 */
function page_title_include_api_files() {
  // Using $runonce, we can ensure the include code below only gets run once.
  static $runonce = FALSE;
  if ($runonce) return;

  // Include relevant page_title.inc's. We cannot use drupal_load() here due to the folder structure.
  // We also avoice using include_once due to its performance hit on the Filesystem
834
  foreach (page_title_get_module_apis() as $module => $info) {
835 836 837
    $path = "./{$info['path']}/{$module}.page_title.inc";
    if (file_exists($path)) {
      include $path;
838 839
    }
  }
840 841

  $runonce = TRUE;
842 843 844 845
}


/**
Nicholas Thompson's avatar
Nicholas Thompson committed
846
 * Get a list of modules that support the current Page Title API.
847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
 */
function page_title_get_module_apis() {
  static $cache = NULL;
  if (!isset($cache)) {
    $cache = array();
    foreach (module_implements('page_title_api') as $module) {
      $function = $module . '_page_title_api';
      $info = $function();
      if (isset($info['api']) && $info['api'] == 1.000) {
        if (!isset($info['path'])) {
          $info['path'] = drupal_get_path('module', $module);
        }
        $cache[$module] = $info;
      }
    }
  }

  return $cache;
865
}
866 867


868 869 870
/**
 * Implementation of hook_page_title_api().
 */
871 872 873 874 875 876 877
function page_title_page_title_api() {
  return array(
    'api' => 1,
    'path' => drupal_get_path('module', 'page_title') .'/modules',
  );
}

878 879 880
/**
 * Core implementations of hook_page_title_api().
 */
881
function blog_page_title_api() { return page_title_page_title_api(); }
882 883 884 885 886 887
function taxonomy_page_title_api() { return page_title_page_title_api(); }
function node_page_title_api() { return page_title_page_title_api(); }
function comment_page_title_api() { return page_title_page_title_api(); }
function forum_page_title_api() { return page_title_page_title_api(); }
function user_page_title_api() { return page_title_page_title_api(); }
function views_page_title_api() { return page_title_page_title_api(); }
888
function uc_catalog_page_title_api() { return page_title_page_title_api(); }
889 890 891 892 893


/**
 * Internal function for checking if Page Title is ok to run
 */
894 895
function page_title_is_up_to_date() {
  return drupal_get_installed_schema_version('page_title') >= max(drupal_get_schema_versions('page_title'));
896
}