You are here

simplemeta.module in Simple Meta 6.2

File

simplemeta.module
View source
<?php

/**
 * Implements hook_init()
 */
function simplemeta_init() {
  if (user_access('administer simplemeta') && arg(0) != 'admin') {
    $modulepath = drupal_get_path('module', 'simplemeta');
    drupal_add_css($modulepath . '/css/simplemeta.css', 'module', 'all', FALSE);
    drupal_add_js($modulepath . '/js/simplemeta.js', 'module', 'header', FALSE, TRUE, FALSE);
  }
}

/**
 * Implements hook_perm()
 */
function simplemeta_perm() {
  return array(
    'administer simplemeta',
  );
}

/**
 * Implements hook_menu()
 */
function simplemeta_menu() {
  $items = array();
  $items['admin/content/simplemeta'] = array(
    'title' => 'SimpleMeta',
    'page callback' => 'simplemeta_meta_list',
    'access arguments' => array(
      'administer simplemeta',
    ),
    'file' => 'simplemeta.admin.inc',
  );
  $items['admin/content/simplemeta/list'] = array(
    'title' => 'SimpleMeta List',
    'page callback' => 'simplemeta_meta_list',
    'access arguments' => array(
      'administer simplemeta',
    ),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'file' => 'simplemeta.admin.inc',
    'weight' => 0,
  );
  $items['admin/content/simplemeta/add'] = array(
    'title' => 'Add SimpleMeta',
    'page callback' => 'simplemeta_add',
    'page arguments' => array(),
    'access arguments' => array(
      'administer simplemeta',
    ),
    'type' => MENU_LOCAL_TASK,
    'file' => 'simplemeta.admin.inc',
    'weight' => 1,
  );
  $items['admin/content/simplemeta/%simplemeta_meta/edit'] = array(
    'title' => 'Add SimpleMeta',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'simplemeta_meta_form',
      3,
    ),
    'access arguments' => array(
      'administer simplemeta',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/content/simplemeta/%simplemeta_meta/delete'] = array(
    'title' => 'Delete SimpleMeta',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'simplemeta_meta_delete_confirm',
      3,
    ),
    'access arguments' => array(
      'administer simplemeta',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'simplemeta.admin.inc',
  );

  //  $items['admin/settings/simplemeta'] = array(
  //    'title' => 'SimpleMeta Settings',
  //    'page callback' => 'drupal_get_form',
  //    'page arguments' => array('simplemeta_settings_form'),
  //    'access arguments' => array('administer simplemeta'),
  //    'file' => 'simplemeta.admin.inc',
  //  );
  return $items;
}

/**
 * Implements hook_footer()
 */
function simplemeta_footer($main = 0) {
  if (user_access('administer simplemeta') && arg(0) != 'admin') {
    $meta = simplemeta_meta_load_by_path($_GET['q']);
    if (!$meta) {
      $meta = new stdClass();
      $meta->path = $_GET['q'];
      $meta->data = array();
      $meta->language = '';
    }
    return drupal_get_form('simplemeta_meta_form', $meta, TRUE);
  }
}

/**
 * Implements hook_flush_caches()
 */
function simplemeta_flush_caches() {
  return array(
    'cache_simplemeta',
  );
}

/**
 * Implements hook_theme()
 */
function simplemeta_theme() {
  return array(
    'simplemeta_meta_list' => array(
      'arguments' => array(
        'items' => array(),
      ),
      'file' => 'simplemeta.theme.inc',
    ),
    'simplemeta_meta_title' => array(
      'arguments' => array(
        'meta' => NULL,
      ),
      'file' => 'simplemeta.theme.inc',
    ),
    'simplemeta_meta_description' => array(
      'arguments' => array(
        'meta' => NULL,
      ),
      'file' => 'simplemeta.theme.inc',
    ),
    'simplemeta_meta_keywords' => array(
      'arguments' => array(
        'meta' => NULL,
      ),
      'file' => 'simplemeta.theme.inc',
    ),
  );
}

/**
 * Implements $module_preprocess_$hook()
 */
function simplemeta_preprocess_page(&$vars) {
  if ($meta = simplemeta_get_page_meta()) {

    // set page title
    if (!empty($meta->data['title'])) {
      $vars['head_title'] = check_plain($meta->data['title']);
    }
    foreach ($meta->view as $item) {
      drupal_set_html_head($item);
    }
    $vars['head'] = drupal_get_html_head();
  }
}

/**
 * Implements hook_simplemeta_info()
 */
function simplemeta_simplemeta_info() {
  $info = array();
  $info['title'] = array(
    'title' => t('Title'),
    'form' => 'simplemeta_form_title',
    'theme' => 'simplemeta_meta_title',
  );
  $info['description'] = array(
    'title' => t('Description'),
    'form' => 'simplemeta_form_description',
    'theme' => 'simplemeta_meta_description',
  );
  $info['keywords'] = array(
    'title' => t('Keywords'),
    'form' => 'simplemeta_form_keywords',
    'theme' => 'simplemeta_meta_keywords',
  );
  return $info;
}
function simplemeta_form_title($meta) {
  $form = array(
    '#type' => 'textfield',
    '#title' => t('Title'),
    '#default_value' => isset($meta->data['title']) ? $meta->data['title'] : '',
  );
  return $form;
}
function simplemeta_form_description($meta) {
  $form = array(
    '#type' => 'textarea',
    '#title' => t('Description'),
    '#default_value' => isset($meta->data['description']) ? $meta->data['description'] : '',
  );
  return $form;
}
function simplemeta_form_keywords($meta) {
  $form = array(
    '#type' => 'textfield',
    '#title' => t('Keywords'),
    '#default_value' => isset($meta->data['keywords']) ? $meta->data['keywords'] : '',
  );
  return $form;
}

/**
 * Save meta data
 */
function simplemeta_meta_save($meta) {
  $is_new = !isset($meta->sid) && !simplemeta_meta_load_by_path($meta->path, $meta->language);
  $meta->fit = _simplemeta_meta_calculate_fit($meta->path);
  $record = drupal_clone($meta);
  $record->data = serialize($record->data);
  if ($is_new) {
    $result = drupal_write_record('simplemeta', $record);
    if (!empty($record->sid)) {
      $meta->sid = $record->sid;
    }
    module_invoke_all('simplemeta', $meta, 'insert');
  }
  else {
    $result = drupal_write_record('simplemeta', $record, array(
      'path',
    ));
    module_invoke_all('simplemeta', $meta, 'update');
  }
  return $result;
}

/**
 * Load meta data
 * @param string $sid Simplemeta data id
 * 
 * @return mixed
 * object representing metadata or FALSE on failure
 */
function simplemeta_meta_load($sid) {
  $query = "SELECT * FROM {simplemeta} WHERE sid = %d";
  if ($meta = db_fetch_object(db_query($query, $sid))) {
    $meta->data = unserialize($meta->data);
    return $meta;
  }
  return FALSE;
}

/**
 * Load meta data
 * @param string $path 
 * @param string $language
 * 
 * @return mixed
 * object representing metadata or FALSE on failure
 */
function simplemeta_meta_load_by_path($path, $language = '') {
  $query = "SELECT * FROM {simplemeta} WHERE path = '%s' AND language = '%s'";
  if ($meta = db_fetch_object(db_query($query, $path, $language))) {
    $meta->data = unserialize($meta->data);
    return $meta;
  }
  return FALSE;
}
function simplemeta_get_page_meta($path = NULL, $language = '', $reset = FALSE) {
  static $meta = array();
  if (!isset($path)) {
    $path = $_GET['q'];
  }
  if (!isset($meta[$path]) || $reset) {
    $meta[$path] = FALSE;
    $cid = $path . ':' . $language;
    if ($cache = cache_get($cid, 'cache_simplemeta')) {
      $meta[$path] = $cache->data;
    }
    else {
      $row = NULL;
      $original_map = arg(NULL, $path);
      $parts = array_slice($original_map, 0, MENU_MAX_PARTS);
      list($ancestors, $placeholders) = menu_get_ancestors($parts);
      $row = db_fetch_object(db_query_range("SELECT * FROM {simplemeta} WHERE path IN (" . implode(',', $placeholders) . ") AND language = '%s' ORDER BY fit DESC", array_merge($ancestors, array(
        $language,
      )), 0, 1));

      // if there is no language-specific meta, try to load language-neutral
      if (!$row && $language) {
        $row = db_fetch_object(db_query_range("SELECT * FROM {simplemeta} WHERE path IN (" . implode(',', $placeholders) . ") AND language = '%s' ORDER BY fit DESC", array_merge($ancestors, array(
          '',
        )), 0, 1));
      }
      if ($row) {
        $row->data = unserialize($row->data);
        $row->view = array();
        $info = simplemeta_get_info();
        foreach ($info as $key => $definition) {
          $themed = theme($definition['theme'], $row);
          if ($themed) {
            $row->view[$key] = $themed;
          }
        }
        cache_set($cid, $row, 'cache_simplemeta');
        $meta[$path] = $row;
      }
    }
  }
  return $meta[$path];
}

/**
 * Delete meta
 */
function simplemeta_meta_delete($sid) {
  $meta = simplemeta_meta_load($sid);
  if ($meta) {
    db_query("DELETE FROM {simplemeta} WHERE sid = %d", $sid);
    module_invoke_all('simplemeta', $meta, 'delete');
  }
}
function simplemeta_meta_form(&$form_state, $meta, $ajax = FALSE) {
  $form = array();

  // let's use _ as prefix to not conflict with other elements
  $form['_meta'] = array(
    '#type' => 'value',
    '#value' => $meta,
  );
  $form['_ajax'] = array(
    '#type' => 'value',
    '#value' => $ajax,
  );
  if (!isset($meta->path)) {
    $form['_path'] = array(
      '#type' => 'textfield',
      '#title' => t('Path'),
      // '#description' => t(''),
      '#required' => TRUE,
    );
  }
  else {
    $form['_path'] = array(
      '#type' => 'value',
      '#value' => $meta->path,
    );
  }
  $form += simplemeta_get_form_elements($meta);
  $form['_buttons'] = array();
  $form['_buttons']['save'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
    '#validate' => array(
      'simplemeta_meta_form_validate_save',
    ),
    '#submit' => array(
      'simplemeta_meta_form_submit_save',
    ),
    '#attributes' => array(
      'class' => 'button-save',
    ),
  );
  $form['_buttons']['delete'] = array(
    '#type' => 'submit',
    '#value' => t('Delete'),
    '#submit' => array(
      'simplemeta_meta_form_submit_delete',
    ),
    '#access' => !empty($meta->sid),
    '#attributes' => array(
      'class' => 'button-delete',
    ),
  );
  if ($ajax) {
    $form['#attributes']['class'] = 'simplemeta-meta-form-ajax';
  }
  return $form;
}
function simplemeta_meta_form_validate_save($form, &$form_state) {
  $values = $form_state['values'];
  $meta = $values['_meta'];
  $path = $values['_path'];
  $normal_path = drupal_get_normal_path($path);
  if ($path != $normal_path) {

    // drupal_set_message(t('The menu system stores system paths only, but will use the URL alias for display. %link_path has been stored as %normal_path', array('%link_path' => $item['link_path'], '%normal_path' => $normal_path)));
    $path = $normal_path;
  }
  if (!menu_path_is_external($path)) {
    $parsed_link = parse_url($path);
    if ($path != $parsed_link['path']) {
      $path = $parsed_link['path'];
    }

    // @todo do we need to check the access?
    // @see menu_edit_item_validate()
    if (!trim($path)) {
      form_set_error('_path', t('Path is invalid'));
    }
    $form_state['values']['_path'] = $path;
  }
  else {
    form_set_error('_path', t('Path can be only internal'));
  }
  if (isset($meta->sid) && !simplemeta_meta_load($meta->sid)) {
    form_set_error('_meta', t("Meta #%sid doesn't exist anymore", array(
      '%id' => $meta->sid,
    )));
  }
  elseif (!isset($meta->sid) && simplemeta_meta_load_by_path($path, $meta->language)) {
    form_set_error('_meta', t("Meta for this page in this language already exists"));
  }
  $info = simplemeta_get_info();
  foreach ($info as $key => $definition) {
    if (isset($definition['validate']) && function_exists($definition['validate'])) {
      $function = $definition['validate'];
      $function($form, $form_state);
    }
  }
}
function simplemeta_meta_form_submit_save($form, &$form_state) {
  $values = $form_state['values'];
  $meta = $values['_meta'];
  $meta->path = $values['_path'];
  $meta->data = array_intersect_key($values, simplemeta_get_form_elements());
  $info = simplemeta_get_info();
  foreach ($info as $key => $definition) {
    if (isset($definition['submit']) && function_exists($definition['submit'])) {
      $function = $definition['submit'];

      // @todo should we pass the $form? Think about
      $function($meta, $form_state);
    }
  }
  simplemeta_meta_save($meta);
  cache_clear_all('*', 'cache_simplemeta', TRUE);
  drupal_set_message(t('Meta has been saved'));
  if (!$form_state['values']['_ajax']) {
    $form_state['redirect'] = 'admin/content/simplemeta/list';
  }
}
function simplemeta_meta_form_submit_delete($form, &$form_state) {
  if (!$form_state['values']['_ajax']) {
    $form_state['redirect'] = 'admin/content/simplemeta/' . $form_state['values']['_meta']->sid . '/delete';
  }
  else {
    simplemeta_meta_delete($form_state['values']['_meta']->sid);
    cache_clear_all('*', 'cache_simplemeta', TRUE);
    drupal_set_message(t('Meta has been deleted'));
  }
}

/**
 * Get info about meta elements from modules
 * Basically, invokes all implementations of hook_simplemeta_info()
 * Caches info in the {cache} table
 * 
 * @param boolean $reset indicates whether use cache or get info from implementations directly
 * @return array info
 */
function simplemeta_get_info($reset = FALSE) {
  $cid = 'simplemeta:info';
  if (!$reset && ($cache = cache_get($cid, 'cache'))) {
    return $cache->data;
  }
  $info = array();
  foreach (module_implements('simplemeta_info') as $module) {
    $function = $module . '_simplemeta_info';
    $result = $function();

    //    foreach ($result as &$item) {
    //      $item['module'] = $module;
    //    }
    $info = array_merge($info, $result);
  }
  cache_set($cid, $info, 'cache');
  return $info;
}
function simplemeta_get_form_elements($meta = NULL, $reset = FALSE) {
  $info = simplemeta_get_info($reset);
  $form = array();
  foreach ($info as $key => $definition) {
    $function = $definition['form'];
    if (function_exists($function)) {
      $form[$key] = $function($meta);
    }
  }
  return $form;
}

/**
 * @param string $path
 * @return int a numeric representation of how specific the path is 
 */
function _simplemeta_meta_calculate_fit($path) {
  $fit = 0;
  $parts = explode('/', $path, MENU_MAX_PARTS);
  $number_parts = count($parts);
  $slashes = $number_parts - 1;
  foreach ($parts as $k => $part) {
    if ($part != '%') {
      $fit |= 1 << $slashes - $k;
    }
  }
  return $fit;
}