You are here

facetapi_pretty_paths.module in Facet API Pretty Paths 7

Same filename and directory in other branches
  1. 6.3 facetapi_pretty_paths.module

The FacetAPI Pretty Paths module.

File

facetapi_pretty_paths.module
View source
<?php

/**
 * @file
 * The FacetAPI Pretty Paths module.
 */

/**
 * Implements hook_facetapi_url_processors().
 */
function facetapi_pretty_paths_facetapi_url_processors() {
  return array(
    'pretty_paths' => array(
      'handler' => array(
        'label' => t('Pretty paths'),
        'class' => 'FacetapiUrlProcessorPrettyPaths',
      ),
    ),
  );
}

/**
 * Allows for alterations to the searcher definitions.
 *
 * @param array &$searcher_info
 *   The return values of hook_facetapi_searcher_info() implementations.
 *
 * Implements hook_facetapi_searcher_info().
 */
function facetapi_pretty_paths_facetapi_searcher_info_alter(array &$searcher_info) {
  foreach ($searcher_info as &$info) {

    // Activate pretty paths optionally per searcher, as configured.
    $id = 'facetapi_pretty_paths_searcher_' . $info['name'];
    $info['url processor'] = variable_get($id) ? 'pretty_paths' : 'standard';
    $info['facetapi pretty paths coder'] = 'default';
  }
}

/**
 * Add pretty path settings to facet configuration.
 *
 * Implements hook_form_BASE_FORM_ID_alter().
 */
function facetapi_pretty_paths_form_facetapi_facet_display_form_alter(&$form, &$form_state, $form_id) {
  if (!user_access('administer facetapi pretty paths')) {
    return;
  }

  // Get global facet settings.
  $adapter = $form['#facetapi']['adapter'];
  $processor = new FacetapiUrlProcessorPrettyPaths($adapter);
  $facet = $form['#facetapi']['facet'];
  $pretty_paths_alias = $processor
    ->getFacetPrettyPathsAlias($facet);

  // Add pretty paths alias option to global facet settings.
  $form['global']['pretty_paths_alias'] = array(
    '#type' => 'textfield',
    '#title' => t('Pretty path alias'),
    '#default_value' => $pretty_paths_alias,
    '#description' => t('Pretty paths will be generated as "search/url/segment1/segment2/".') . '<br/>' . t('By default, a segment will look like: "@default_segment".', array(
      '@default_segment' => '<alias>/<value>',
    )) . '<br/>' . t('For taxonomy terms it outputs the id as well: "@taxonomy_segment".', array(
      '@taxonomy_segment' => '<alias>/<term-name>-<term-id>',
    )),
  );

  // Taxonomy Pathauto Coder settings.
  // 1. Check if pathauto is enabled.
  // 2. Check for Apache Solr taxonomy term fields.
  // 3. Check for Search API taxonomy term fields.
  if (module_exists('pathauto') && (!empty($facet['map options']['module_name']) && $facet['map options']['module_name'] == 'Taxonomy' || !empty($facet['field type']) && $facet['field type'] == 'taxonomy_term')) {
    $facet_settings = $adapter
      ->getFacetSettingsGlobal($facet);
    $form['global']['pretty_paths_taxonomy_pathauto'] = array(
      '#type' => 'checkbox',
      '#title' => t('Reuse term aliases'),
      '#default_value' => !empty($facet_settings->settings['pretty_paths_taxonomy_pathauto']) ? TRUE : FALSE,
      '#description' => t('If set, the term alias from the pathauto settings will be reused, which avoids term ids in the facet aliases. This setting only works if the default taxonomy path pattern \'[term:vocabulary]/[term:name]\' is used.'),
    );
    $options = array();
    foreach (taxonomy_get_vocabularies() as $voc) {
      $options[$voc->machine_name] = $voc->name;
    }
    $vocabulary = facetapi_pretty_paths_taxonomy_facet_get_vocabulary($facet);
    $default_voc_name = $vocabulary ? $vocabulary->machine_name : array();
    $form['global']['pretty_paths_taxonomy_pathauto_vocabulary'] = array(
      '#type' => 'select',
      '#title' => t('Vocabulary for pathauto'),
      '#options' => $options,
      '#default_value' => !empty($facet_settings->settings['pretty_paths_taxonomy_pathauto_vocabulary']) ? $facet_settings->settings['pretty_paths_taxonomy_pathauto_vocabulary'] : $default_voc_name,
      '#description' => t('Select the appropriate vocabulary for this facet. In case the facet values come from a taxonomy field, the appropriate vocabulary is calculated.'),
      '#disabled' => !empty($default_voc_name),
      '#states' => array(
        'visible' => array(
          ':input[name="global[pretty_paths_taxonomy_pathauto]"]' => array(
            'checked' => TRUE,
          ),
        ),
      ),
    );
  }
  $form['#submit'][] = 'facetapi_pretty_paths_facetapi_facet_display_form_submit';
}

/**
 * Additional form submission handler for 'facetapi_facet_display_form'.
 */
function facetapi_pretty_paths_facetapi_facet_display_form_submit($form, &$form_state) {

  // Clear the facet api cache as the settings for the pretty paths might have
  // changed.
  cache_clear_all('facetapi:facet_info:', 'cache', TRUE);
}

/**
 * Helper function that returns the vocabulary for a taxonomy facet.
 */
function facetapi_pretty_paths_taxonomy_facet_get_vocabulary($facet_info) {
  if (isset($facet_info['field'])) {
    $facet_field_name = $facet_info['field'];

    // The Search API chains properties with ':'. The last taxonomy field in
    // this chain is the key for the vocabulary.
    // The Apache Solr module only contains Field API names. In this case
    // the explode function returns the whole string in the first array
    // value.
    $exploded = explode(':', $facet_field_name);
    foreach (array_reverse($exploded) as $property_name) {
      $field_info = field_info_field($property_name);
      if ($field_info && isset($field_info['settings']['allowed_values'][0]['vocabulary'])) {
        $voc = taxonomy_vocabulary_machine_name_load($field_info['settings']['allowed_values'][0]['vocabulary']);
        if ($voc) {
          return $voc;
        }
      }
    }
  }
  return FALSE;
}

/**
 * Implements hook_menu().
 */
function facetapi_pretty_paths_menu() {
  $items = array();
  $items['admin/config/search/facetapi_pretty_paths'] = array(
    'title' => 'FacetAPI Pretty Paths',
    'description' => 'Configure pretty paths settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'facetapi_pretty_paths_admin_form',
    ),
    'access arguments' => array(
      'administer facetapi pretty paths',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

/**
 * Implements hook_permission().
 */
function facetapi_pretty_paths_permission() {
  return array(
    'administer facetapi pretty paths' => array(
      'title' => t('Administer Facet API Pretty Paths'),
    ),
  );
}

/**
 * Administration form.
 */
function facetapi_pretty_paths_admin_form($form, &$form_state) {

  // Include necessary ctools inc files.
  ctools_include('plugins');

  // Allow to enable / disable pretty paths per searcher.
  $searcher_info = facetapi_get_searcher_info();
  $form['searcher'] = array(
    '#type' => 'fieldset',
    '#title' => t('Enable pretty paths per searcher'),
    '#type' => 'fieldset',
  );
  foreach (facetapi_get_searcher_info() as $info) {
    $id = 'facetapi_pretty_paths_searcher_' . $info['name'];

    // Add a checkbox to enable pretty paths per searcher.
    $form['searcher'][$id] = array(
      '#type' => 'checkbox',
      '#title' => t('@searcher', array(
        '@searcher' => $info['name'],
      )),
      '#default_value' => variable_get($id, $info['url processor'] == 'pretty_paths'),
      '#description' => t("Use pretty paths for the @searcher_label", array(
        "@searcher_label" => $info['label'],
      )),
    );

    // An additional fieldset provides additional options per searcher.
    $options = variable_get($id . '_options');
    $form['searcher'][$id . '_options'] = array(
      '#type' => 'fieldset',
      '#title' => t('Options for @searcher', array(
        '@searcher' => $info['name'],
      )),
      '#tree' => TRUE,
      '#states' => array(
        'visible' => array(
          ':input[name="' . $id . '"]' => array(
            'checked' => TRUE,
          ),
        ),
      ),
    );
    $form['searcher'][$id . '_options']['sort_path_segments'] = array(
      '#type' => 'checkbox',
      '#title' => t('Make paths unique by sorting them.'),
      '#default_value' => isset($options['sort_path_segments']) ? $options['sort_path_segments'] : FALSE,
      '#description' => t("Sorted paths lead to unique, canonical urls. Keep in mind that this will replace the order in which user clicked the facets."),
    );

    // Allow to select a base path provider plugin.
    $base_path_providers = ctools_get_plugins('facetapi_pretty_paths', 'base_path_provider');
    $base_path_providers_form_item = array(
      '#type' => 'radios',
      '#title' => t('Base path provider'),
      '#options' => array(),
      '#default_value' => isset($options['base_path_provider']) ? $options['base_path_provider'] : 'default',
      '#description' => t("Select a base path provider or implement your own using <em>hook_facetapi_pretty_paths_base_path_provider</em>."),
    );
    foreach ($base_path_providers as $key => $base_path_provider) {
      $base_path_providers_form_item['#options'][$key] = $base_path_provider['handler']['label'];
      $base_path_providers_form_item[$key]['#description'] = $base_path_provider['handler']['description'];
    }
    $form['searcher'][$id . '_options']['base_path_provider'] = $base_path_providers_form_item;
  }
  return system_settings_form($form);
}

/**
 * Implements hook_ctools_plugin_type().
 */
function facetapi_pretty_paths_ctools_plugin_type() {
  $plugins['base_path_provider'] = array(
    'use hooks' => TRUE,
  );
  $plugins['coders'] = array(
    'use hooks' => TRUE,
  );
  return $plugins;
}

/**
 * Implements hook_facetapi_pretty_paths_base_path_provider().
 */
function facetapi_pretty_paths_facetapi_pretty_paths_base_path_provider() {
  $base_path_providers = array(
    'default' => array(
      'handler' => array(
        'label' => t('Default base path provider'),
        'class' => 'FacetApiPrettyPathsDefaultBasePathProvider',
        'description' => 'Calculates the base path by subtracting facet path segments from the current url.',
      ),
    ),
    'adapter' => array(
      'handler' => array(
        'label' => t('Adapter base path provider'),
        'class' => 'FacetApiPrettyPathsAdapterBasePathProvider',
        'description' => 'Relies on the FacetapiAdapter::getSearchPath() method to generate the base path. This one is likely overridden by SearchApiFacetapiAdapter::getSearchPath() or ApacheSolrFacetapiAdapter::getSearchPath().',
      ),
    ),
  );

  // Allow other modules to alter the base path provider definitions.
  drupal_alter('facetapi_pretty_paths_base_path_provider', $base_path_providers);
  return $base_path_providers;
}

/**
 * Implements hook_facetapi_pretty_paths_coders().
 */
function facetapi_pretty_paths_facetapi_pretty_paths_coders() {
  $coders = array(
    'default' => array(
      'handler' => array(
        'label' => t('Default pretty paths coder'),
        'class' => 'FacetApiPrettyPathsCoderDefault',
      ),
    ),
    'taxonomy' => array(
      'handler' => array(
        'label' => t('Taxonomy specific pretty paths coder'),
        'class' => 'FacetApiPrettyPathsCoderTaxonomy',
      ),
    ),
    'taxonomy_pathauto' => array(
      'handler' => array(
        'label' => t('Taxonomy specific pathauto coder'),
        'class' => 'FacetApiPrettyPathsCoderTaxonomyPathauto',
      ),
    ),
  );

  // Allow other modules to alter the coder definitions.
  drupal_alter('facetapi_pretty_paths_coders', $coders);

  // @todo Remove deprecated 7.x-1.x hook in next major version.
  drupal_alter('facetapi_pretty_paths_facetapi_pretty_paths_coders', $coders);
  return $coders;
}

/**
 * Implements hook_facetapi_facet_info_alter().
 */
function facetapi_pretty_paths_facetapi_facet_info_alter(array &$facet_info, array $searcher_info) {

  /*
   * In order to get settings for a facet normally we would need to
   * load the adapter for a given searcher. However doing so with
   * facetapi_adapter_load() causes the adapter class in context
   * to be instantiated which in the case of this module results
   * in the fetchParams method of the FacetapiUrlProcessorPrettyPaths
   * class being called which results in active facets in the URL
   * being processed before the logic below can alter the facet
   * settings.
   *
   * The normal way to get facet settings would be via the adapter
   * class using getFacetSettings() and/or getFacetSettingsGlobal().
   * Instead we have to use the raw settings getter function below.
   */
  $searcher_settings = facetapi_get_searcher_settings($searcher_info['name']);
  foreach ($facet_info as &$facet) {
    $taxonomy_coder = 'taxonomy';
    $facet_settings_key = $searcher_info['name'] . '::' . $facet['field'];
    if (isset($searcher_settings[$facet_settings_key]) && isset($searcher_settings[$facet_settings_key]->settings)) {
      $facet_settings = $searcher_settings[$facet_settings_key];
      if (module_exists('pathauto') && !empty($facet_settings->settings['pretty_paths_taxonomy_pathauto'])) {
        $taxonomy_coder = 'taxonomy_pathauto';
      }
    }

    // Check for Apache Solr Taxonomy Term fields.
    if (!empty($facet['map options']['module_name']) && $facet['map options']['module_name'] == 'Taxonomy') {
      $facet['facetapi pretty paths coder'] = $taxonomy_coder;
    }
    else {
      if (!empty($facet['field type']) && $facet['field type'] == 'taxonomy_term') {
        $facet['facetapi pretty paths coder'] = $taxonomy_coder;
      }
    }
  }
  drupal_static_reset('facetapi_get_enabled_facets');
}

/**
 * Helper function for calling coder callbacks.
 */
function facetapi_pretty_paths_coder_callback($callback, $args) {
  $id = 'default';
  if (isset($args['facet']) && isset($args['facet']['facetapi pretty paths coder'])) {
    $id = $args['facet']['facetapi pretty paths coder'];
  }
  if ($class = ctools_plugin_load_class('facetapi_pretty_paths', 'coders', $id, 'handler')) {
    $args = func_get_args();

    // Remove $callback from the arguments.
    unset($args[0]);
    $instance = new $class();
    return call_user_func_array(array(
      $instance,
      $callback,
    ), $args);
  }
}

Functions

Namesort descending Description
facetapi_pretty_paths_admin_form Administration form.
facetapi_pretty_paths_coder_callback Helper function for calling coder callbacks.
facetapi_pretty_paths_ctools_plugin_type Implements hook_ctools_plugin_type().
facetapi_pretty_paths_facetapi_facet_display_form_submit Additional form submission handler for 'facetapi_facet_display_form'.
facetapi_pretty_paths_facetapi_facet_info_alter Implements hook_facetapi_facet_info_alter().
facetapi_pretty_paths_facetapi_pretty_paths_base_path_provider Implements hook_facetapi_pretty_paths_base_path_provider().
facetapi_pretty_paths_facetapi_pretty_paths_coders Implements hook_facetapi_pretty_paths_coders().
facetapi_pretty_paths_facetapi_searcher_info_alter Allows for alterations to the searcher definitions.
facetapi_pretty_paths_facetapi_url_processors Implements hook_facetapi_url_processors().
facetapi_pretty_paths_form_facetapi_facet_display_form_alter Add pretty path settings to facet configuration.
facetapi_pretty_paths_menu Implements hook_menu().
facetapi_pretty_paths_permission Implements hook_permission().
facetapi_pretty_paths_taxonomy_facet_get_vocabulary Helper function that returns the vocabulary for a taxonomy facet.