class FacetapiWidgetLinks in Facet API 7
Same name and namespace in other branches
- 6.3 plugins/facetapi/widget_links.inc \FacetapiWidgetLinks
- 7.2 plugins/facetapi/widget_links.inc \FacetapiWidgetLinks
Widget that renders facets as a list of clickable links.
Links make it easy for users to narrow down their search results by clicking on them. The render arrays use theme_item_list() to generate the HTML markup.
Hierarchy
- class \FacetapiWidget
- class \FacetapiWidgetLinks
Expanded class hierarchy of FacetapiWidgetLinks
2 string references to 'FacetapiWidgetLinks'
- facetapi_facetapi_widgets in ./
facetapi.facetapi.inc - Implements hook_facetapi_widgets().
- hook_facetapi_widgets in ./
facetapi.api.php - Define all widget plugins provided by the module.
File
- plugins/
facetapi/ widget_links.inc, line 14 - The facetapi_links and facetapi_checkbox_links widget plugin classes.
View source
class FacetapiWidgetLinks extends FacetapiWidget {
/**
* Overrides FacetapiWidget::__construct().
*
* For links, it is better to use the machine name of the facet as opposed to
* the alias for the key. Alias are usually, but not necessarily, unique. It
* doesn't make sense to group links in the same element as they are usually
* rendered in blocks with are separate from one another.
*/
public function __construct($id, array $realm, FacetapiFacet $facet, stdClass $settings) {
parent::__construct($id, $realm, $facet, $settings);
$this->jsSettings['limit'] = $this->settings->settings['soft_limit'];
$this->key = $facet['name'];
}
/**
* Implements FacetapiWidget::execute().
*
* Transforms the render array into something that can be themed by
* theme_item_list().
*
* @see FacetapiWidgetLinks::setThemeHooks()
* @see FacetapiWidgetLinks::buildListItems()
*/
public function execute() {
$element =& $this->build[$this->facet['field alias']];
// Sets each item's theme hook, builds item list.
$this
->setThemeHooks($element);
$element = array(
'#theme' => 'item_list',
'#items' => $this
->buildListItems($element),
'#attributes' => $this->build['#attributes'],
);
}
/**
* Recursive function that sets each item's theme hook.
*
* The individual items will be rendered by different theme hooks depending on
* whether or not they are active.
*
* @param array &$build
* A render array containing the facet items.
*
* @return FacetapiWidget
* An instance of this class.
*
* @see theme_facetapi_link_active()
* @see theme_facetapi_link_inactive()
*/
protected function setThemeHooks(array &$build) {
foreach ($build as $value => &$item) {
$item['#theme'] = $item['#active'] ? 'facetapi_link_active' : 'facetapi_link_inactive';
if (!empty($item['#item_children'])) {
$this
->setThemeHooks($item['#item_children']);
}
}
return $this;
}
/**
* Transforms the render array for use with theme_item_list().
*
* The recursion allows this function to act on the various levels of a
* hierarchical data set.
*
* @param array $build
* The items in the facet's render array being transformed.
*
* @return array
* The "items" parameter for theme_item_list().
*/
function buildListItems($build) {
$settings = $this->settings->settings;
$attributes_init = array(
'class' => $this
->getItemClasses(),
);
// Builds rows.
$items = array();
foreach ($build as $value => $item) {
// Reset attributes for each item, combining potential custom ones and the
// default "class" attribute. The item's "#attributes" property can be
// used to e.g. set rel="nofollow" for individual items.
$attributes = isset($item['#attributes']) ? $item['#attributes'] + $attributes_init : $attributes_init;
$row = array(
'class' => array(),
);
// Allow adding classes via altering.
if (isset($item['#class'])) {
$attributes['class'] = array_merge($attributes['class'], $item['#class']);
}
// Initializes variables passed to theme hook.
$variables = array(
'text' => $item['#markup'],
'path' => $item['#path'],
'count' => $settings['display_count'] ? $item['#count'] : NULL,
'options' => array(
'attributes' => $attributes,
),
);
// Adds the facetapi-zero-results class to items that have no results.
if (!$item['#count']) {
$variables['options']['attributes']['class'][] = 'facetapi-zero-results';
}
else {
// We need nofollow only for items with non zero results.
if ($settings['nofollow']) {
// Check if rel="nofollow" should be added to links.
switch ($settings['nofollow']) {
// Always add nofollow.
case 1:
$variables['options']['attributes']['rel'] = 'nofollow';
break;
// Add nofollow if there is already an active item of this facet.
case 2:
if ($this->facet
->getAdapter()
->getActiveItems(array(
'name' => $this->key,
))) {
$variables['options']['attributes']['rel'] = 'nofollow';
}
break;
// Add nofollow if there is already an active item of any facet.
case 3:
if ($this->facet
->getAdapter()
->getAllActiveItems()) {
$variables['options']['attributes']['rel'] = 'nofollow';
}
break;
}
}
}
// Add an ID to identify this link.
$variables['options']['attributes']['id'] = drupal_html_id('facetapi-link');
$variables['options'] += array(
'html' => $item['#html'],
'query' => $item['#query'],
);
// If the item is active, the li is active
if ($item['#active']) {
$row['class'][] = 'active';
}
// If the item has no children, it is a leaf.
if (empty($item['#item_children'])) {
$row['class'][] = 'leaf';
}
else {
// If the item is active or the "show_expanded" setting is selected,
// show this item as expanded so we see its children.
if ($item['#active'] || !empty($settings['show_expanded'])) {
$row['class'][] = 'expanded';
$row['children'] = $this
->buildListItems($item['#item_children']);
}
else {
$row['class'][] = 'collapsed';
}
}
// Gets theme hook, adds last minute classes.
$class = $item['#active'] ? 'facetapi-active' : 'facetapi-inactive';
$variables['options']['attributes']['class'][] = $class;
// Themes the link, adds row to items.
$row['data'] = theme($item['#theme'], $variables);
$items[] = $row;
}
return $items;
}
/**
* Gets the base class array for a facet item.
*
* Classes that extend FacetapiWidgetLinks will often override this method to
* alter the link displays via CSS without having to touch the render array.
*
* @return array
* An array of classes.
*/
function getItemClasses() {
return array();
}
/**
* Overrides FacetapiWidget::settingsForm().
*/
function settingsForm(&$form, &$form_state) {
// @see http://drupal.org/node/735528 for supporting multiple values in the
// FAPI #states. The following hack adds multiple form elements and uses CSS
// and JavaScript to ensure only one is displayed at a time. Only the last
// form element actually passes the value.
$form['widget']['widget_settings']['links'][$this->id]['soft_limit'] = array(
'#type' => 'select',
'#title' => t('Soft limit'),
'#default_value' => $this->settings->settings['soft_limit'],
'#options' => array(
0 => t('No limit'),
) + drupal_map_assoc(array(
50,
40,
30,
20,
15,
10,
5,
3,
)),
'#description' => t('Limits the number of displayed facets via JavaScript.'),
'#states' => array(
'visible' => array(
'select[name="widget"]' => array(
'value' => $this->id,
),
),
),
);
// @see http://drupal.org/node/1370342
$form['widget']['widget_settings']['links'][$this->id]['nofollow'] = array(
'#type' => 'select',
'#title' => t('Prevent crawlers from following facet links'),
'#default_value' => empty($this->settings->settings['nofollow']) ? 0 : $this->settings->settings['nofollow'],
'#description' => t('Add the <code>rel="nofollow"</code> attribute to facet links to maximize SEO by preventing crawlers from indexing duplicate content and getting stuck in loops.'),
'#options' => array(
0 => t('never'),
1 => t('always'),
2 => t('only for links that select multiple items of the same facet'),
3 => t('if there is already a selected item from any facet'),
),
'#states' => array(
'visible' => array(
'select[name="widget"]' => array(
'value' => $this->id,
),
),
),
);
// @see http://drupal.org/node/735528
if ($this->facet['hierarchy callback']) {
$form['widget']['widget_settings']['links'][$this->id]['show_expanded'] = array(
'#type' => 'checkbox',
'#title' => t('Expand hierarchy'),
'#default_value' => !empty($this->settings->settings['show_expanded']),
'#description' => t('Show the entire tree regardless of whether the parent items are active.'),
'#states' => array(
'visible' => array(
'select[name="widget"]' => array(
'value' => $this->id,
),
),
),
);
}
// Hides all but the last element. The #states system will override this,
// however it is necessary if JavaScript is disabled so multiple elements
// aren't displayed to the user.
$last = end($form['widget']['widget_settings']['links']);
foreach ($form['widget']['widget_settings']['links'] as $id => $element) {
if ($last != $element) {
$form['widget']['widget_settings']['links'][$id]['#attributes']['style'] = 'display: none;';
}
}
}
/**
* Overrides FacetapiWidget::getDefaultSettings().
*/
function getDefaultSettings() {
return array(
'soft_limit' => 20,
'nofollow' => 1,
'show_expanded' => 0,
);
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
FacetapiWidget:: |
protected | property | The render that alterations are being applied to. | |
FacetapiWidget:: |
protected | property | The facet object containing the facet definition and required contexts. | |
FacetapiWidget:: |
protected | property | The machine name of the plugin associated with this instance. | |
FacetapiWidget:: |
protected | property | The widget's JavaScript settings that are passed to drupal_add_js(). | |
FacetapiWidget:: |
protected | property | The key of the facet's render array added to the realm's render array. | |
FacetapiWidget:: |
protected | property | The realm definition as returned by facetapi_realm_load(). | |
FacetapiWidget:: |
protected | property | An array of facet settings. | |
FacetapiWidget:: |
protected | function | Applies the sorts to the facet items recursively. | |
FacetapiWidget:: |
public | function | Returns the altered render array acted on by FacetapiWidget::execute(). | |
FacetapiWidget:: |
public | function | Gets the machine name of the plugin. | |
FacetapiWidget:: |
public | function | Returns the JavaScript settings that are passed to drupal_add_js(). | |
FacetapiWidget:: |
public | function | Gets key used to append FacetapiWidget::build to the realm's render array. | |
FacetapiWidget:: |
public | function | Initializes the build, must be invoked prior to executing this widget. | 1 |
FacetapiWidget:: |
protected | function | Applies sort information via the callback in the sort definition. | |
FacetapiWidget:: |
function | Applies sorting algorithms to the items in the facet's render array. | ||
FacetapiWidgetLinks:: |
function | Transforms the render array for use with theme_item_list(). | ||
FacetapiWidgetLinks:: |
public | function |
Implements FacetapiWidget::execute(). Overrides FacetapiWidget:: |
|
FacetapiWidgetLinks:: |
function |
Overrides FacetapiWidget::getDefaultSettings(). Overrides FacetapiWidget:: |
||
FacetapiWidgetLinks:: |
function | Gets the base class array for a facet item. | 1 | |
FacetapiWidgetLinks:: |
protected | function | Recursive function that sets each item's theme hook. | |
FacetapiWidgetLinks:: |
function |
Overrides FacetapiWidget::settingsForm(). Overrides FacetapiWidget:: |
||
FacetapiWidgetLinks:: |
public | function |
Overrides FacetapiWidget::__construct(). Overrides FacetapiWidget:: |