facetapi.api.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. <?php
  2. /**
  3. * @file
  4. * Hooks provided by the Facet API module.
  5. */
  6. /**
  7. * @addtogroup hooks
  8. * @{
  9. */
  10. /**
  11. * Define all searchers provided by the module.
  12. *
  13. * Searchers are synonymous with search pages, or environments. Multiple
  14. * searchers can share the same adapter class, but each searcher will spawn a
  15. * separate instance of the adapter. Each searcher must be unique, so it is
  16. * common practice to prefix the name with the module implementing the hook,
  17. * such as "apachesolr@searcher-x", "search_api@searcher-y", etc.
  18. *
  19. * @return array
  20. * An associative array keyed by unique name of the searcher. Each searcher is
  21. * an associative array containing:
  22. * - label: The human readable name of the searcher displayed in the admin UI.
  23. * - adapter: The adapter plugin ID associated with the searcher.
  24. * - url processor: (optional) The URL processor plugin ID associated with the
  25. * searcher. Defaults to "standard".
  26. * - types: (optional) An array containing the types of content indexed by the
  27. * searcher. A type is usually an entity such as 'node', but it can contain
  28. * non-entities as well. Defaults to array('node').
  29. * - path: (optional) The MENU_DEFAULT_LOCAL_TASK item which the admin UI page
  30. * is added to as a MENU_LOCAL_TASK. An empty string if the backend manages
  31. * the admin UI menu items internally. Defaults to an empty string meaning
  32. * the backend is responsible for adding the admin UI menu items.
  33. * - supports facet missing: (optional) TRUE if the searcher supports
  34. * "missing" facets. Defaults to FALSE.
  35. * - supports facet mincount: (optional) TRUE if the searcher supports the
  36. * minimum facet count setting. Defaults to FALSE.
  37. * - include default facets: (optional) TRUE if the searcher should include
  38. * the facets defined in facetapi_facetapi_facet_info() when indexing node
  39. * content, FALSE if they should be skipped.
  40. *
  41. * @see FacetapiAdapter
  42. */
  43. function hook_facetapi_searcher_info() {
  44. return array(
  45. 'search' => array(
  46. 'label' => t('Search'),
  47. 'adapter' => 'search',
  48. 'url processor' => 'standard',
  49. 'types' => array('node'),
  50. 'path' => 'admin/config/search/settings',
  51. 'supports facet missing' => TRUE,
  52. 'supports facet mincount' => TRUE,
  53. 'include default facets' => TRUE,
  54. ),
  55. );
  56. }
  57. /**
  58. * Allows for alterations to the searcher definitions.
  59. *
  60. * @param array &$searcher_info
  61. * The return values of hook_facetapi_searcher_info() implementations.
  62. *
  63. * @see hook_facetapi_searcher_info()
  64. */
  65. function hook_facetapi_searcher_info_alter(array &$searcher_info) {
  66. $searcher_info['search']['label'] = t('Core search module');
  67. }
  68. /**
  69. * Define all realms provided by the module.
  70. *
  71. * A realm is a group of facets that are rendered in a similar fashion. For
  72. * example, the "block" realm displays each facet in a separate block, whereas
  73. * the "fieldset" realm displays facets as form elements in a fieldset under the
  74. * search form.
  75. *
  76. * @return array
  77. * An associative array keyed by unique name of the realm. Each realm is an
  78. * associative array containing:
  79. * - label: The human readable name of the realm displayed in the admin UI.
  80. * - description: The description of the realm displayed in the admin UI.
  81. * - element type: The type of element facets are rendered as, such as "links"
  82. * or "form elements".
  83. * - default widget: The default widget plugin id for facets.
  84. * - settings callback: (optional) A callback that alters the realm settings
  85. * form, defaults to FALSE meaning no callback is defined.
  86. * - sortable: (optional) Whether the facets can be sorted via the admin UI,
  87. * defaults to TRUE.
  88. * - weight: (optional) The weight of the realm's menu item in comparison to
  89. * the others, defaults to 0.
  90. */
  91. function hook_facetapi_realm_info() {
  92. return array(
  93. 'block' => array(
  94. 'label' => t('Blocks'),
  95. 'sortable' => FALSE,
  96. 'weight' => -10,
  97. 'default widget' => 'facetapi_links',
  98. 'element type' => 'links',
  99. 'settings callback' => 'facetapi_block_realm_settings',
  100. 'description' => t(
  101. 'The <em>Blocks</em> realm displays each facet in a separate <a href="@block-page">block</a>. Users are able to refine their searches in a drill-down fashion.',
  102. array('@block-page' => url('admin/structure/block', array('query' => array('destination' => current_path()))))
  103. ),
  104. ),
  105. );
  106. }
  107. /**
  108. * Allows for alterations to the realm definitions.
  109. *
  110. * @param array &$realm_info
  111. * The return values of hook_facetapi_realm_info() implementations.
  112. *
  113. * @see hook_facetapi_realm_info()
  114. */
  115. function hook_facetapi_realm_info_alter(array &$realm_info) {
  116. $realm_info['block']['weight'] = 5;
  117. }
  118. /**
  119. * Define all facets provided by the module.
  120. *
  121. * Facets correspond with fields in the search index and are usually related to
  122. * entity properties and fields. However, it is not a requirement that the
  123. * source data be stored in Drupal. For example, if you are indexing external
  124. * RSS feeds, facets can be defined that filter by the field in the index that
  125. * stores the publication dates.
  126. *
  127. * @param array $searcher_info
  128. * The definition of the searcher that facets are being collected for.
  129. *
  130. * @return array
  131. * An associative array keyed by unique name of the facet. Each facet is an
  132. * associative array containing:
  133. * - name: Machine readable name of the facet.
  134. * - label: Human readable name of the facet displayed in settings forms.
  135. * - description: Description of the facet displayed in settings forms.
  136. * - field: The field name used by the backend to store and retrieve data from
  137. * the search index it is associated with. Defaults to the machine name of
  138. * the facet.
  139. * - field alias: The query string variable inside of the filter key used to
  140. * pass the filter information through the query string. Defaults to the
  141. * machine name of the facet.
  142. * - field api name: (optional) The machine readable name of the Field API
  143. * field data the facet is associated with, FALSE if it is not associated
  144. * with a field.
  145. * - field api bundles: (optional) An array of entity names that this field
  146. * contains bundle information for. Defaults to an empty array.
  147. * - query types: The query type plugins that that this facet supports. For
  148. * example, numeric fields support "term" and "range_filter" queries.
  149. * - alter callbacks: (optional) Callbacks that alter the initialized render
  150. * array returned by the query type plugin. Defaults to an empty array.
  151. * - dependency plugins: (optional) An array of dependency plugin IDs that are
  152. * supported by this facet.
  153. * - default widget: (optional) The widget plugin ID used if no plugin has
  154. * been selected or the one selected is not valid. Defaults to FALSE which
  155. * sets the default widget as the one defined by the realm.
  156. * - allowed operators: (optional) An array keyed by operator constant to
  157. * boolean values specifying whether the operator is supported. Defaults to
  158. * an array containing:
  159. * - FACETAPI_OPERATOR_AND: TRUE
  160. * - facet missing allowed: (optional) Whether or not missing facets are
  161. * allowed for this facet. Defaults to FALSE.
  162. * - facet mincount allowed: (optional) Whether or not the facet supports the
  163. * "minimum facet count" setting. Defaults to FALSE.
  164. * - weight: (optional) The weight of the facet. Defaults to 0.
  165. * - map callback: (optional) The callback used to map the raw values returned
  166. * by the index to something human readable. Defaults to FALSE
  167. * - map options: (optional) An array of options passed to the map callback,
  168. * defaults to en empty array.
  169. * - hierarchy callback: (optional) A callback that maps the parent / child
  170. * relationships of the facet data, defaults to FALSE meaning the list is
  171. * flat.
  172. * - values callback: (optional) In instances where facet data is not returned
  173. * by the backend, provide a list of values that can be used. Defaults to
  174. * FALSE.
  175. * - min callback: (optional) For facets containing ranges, a callback
  176. * returning the minimum value in the index. Defaults to FALSE.
  177. * - max callback: (optional) For facets containing ranges, a callback
  178. * returning the maximum value in the index. Defaults to FALSE.
  179. * - default sorts: (optional) An array of available sorts. Each item is an
  180. * array containing two values, the first being the item being filtered on,
  181. * the second being the SORT_* constant. Defaults to an array containing:
  182. * - active: SORT_DESC
  183. * - count: SORT_DESC
  184. * - display: SORT_ASC
  185. */
  186. function hook_facetapi_facet_info(array $searcher_info) {
  187. $facets = array();
  188. // Facets are usually associated with the type of content stored in the index.
  189. if (isset($searcher_info['types']['my_type'])) {
  190. $facets['my_field'] = array(
  191. 'name' => 'my_field',
  192. 'label' => t('My field'),
  193. 'description' => t('My field index some content we can facet by.'),
  194. 'field' => 'my_field_index_field_name',
  195. 'field alias' => 'my_alias',
  196. 'field api name' => FALSE,
  197. 'field api bundles' => array(),
  198. 'query types' => array('term', 'date'),
  199. 'dependency plugins' => array('role'),
  200. 'default widget' => 'links',
  201. 'allowed operators' => array(FACETAPI_OPERATOR_AND => TRUE, FACETAPI_OPERATOR_OR => TRUE),
  202. 'facet missing allowed' => FALSE,
  203. 'facet mincount allowed' => FALSE,
  204. 'weight' => 0,
  205. 'map callback' => 'mymodule_map_my_field',
  206. 'map options' => array('field_option_1', 'field_option_2'),
  207. 'hierarchy callback' => FALSE,
  208. 'values callback' => FALSE,
  209. 'min callback' => FALSE,
  210. 'max callback' => FALSE,
  211. 'default sorts' => array(
  212. array('active', SORT_DESC),
  213. array('count', SORT_DESC),
  214. array('display', SORT_ASC),
  215. ),
  216. );
  217. }
  218. return $facets;
  219. }
  220. /**
  221. * Allows for alterations to the facet definitions.
  222. *
  223. * @param array &$facet_info
  224. * The return values of hook_facetapi_facet_info() implementations.
  225. * @param array $searcher_info
  226. * The definition of the searcher that facets are being collected for.
  227. *
  228. * @see hook_facetapi_facet_info()
  229. */
  230. function hook_facetapi_facet_info_alter(array &$facet_info, array $searcher_info) {
  231. // Change the author index field for Apache Solr searchers indexing node data.
  232. if ('apachesolr' == $searcher_info['adapter'] && isset($searcher_info['types']['node'])) {
  233. $facet_info['author']['field'] = 'is_uid';
  234. }
  235. }
  236. /**
  237. * Allows for alterations of the facets on the fly, without caching.
  238. *
  239. * @param array &$enabled_facets
  240. * The return facets, which enabled for current search.
  241. * @param $searcher
  242. * The machine readable name of the searcher.
  243. * @param $realm_name
  244. * The machine readable name of the realm.
  245. */
  246. function hook_facetapi_enabled_facets_alter(array &$enabled_facets, $searcher, $realm_name) {
  247. if ($searcher == 'something') {
  248. // Put facet1 to the end.
  249. if (!empty($enabled_facets['facet1'])) {
  250. $facet1 = $enabled_facets['facet1'];
  251. unset($enabled_facets['facet1']);
  252. $enabled_facets['facet1'] = $facet1;
  253. }
  254. }
  255. }
  256. /**
  257. * Define all facets sorting algorithms provided by the module.
  258. *
  259. * Sorts are applied in the FacetapiWidget::sortFacet() method which is called
  260. * by FacetapiWidget::init().
  261. *
  262. * @return array
  263. * An associative array keyed by unique name of the sort. Each sort is an
  264. * associative array containing:
  265. * - title: The human readable name of the sort displayed in the admin UI.
  266. * - callback: The uasort() callback the render array is passed to.
  267. * - description: The description of the sort displayed in the admin UI.
  268. * - weight: (optional) The default weight of the sort specifying its
  269. * default processing order. Defaults to 0.
  270. *
  271. * @see FacetapiWidget::init()
  272. * @see FacetapiWidget::sortFacet()
  273. */
  274. function hook_facetapi_sort_info() {
  275. $sorts = array();
  276. $sorts['active'] = array(
  277. 'label' => t('Facet active'),
  278. 'callback' => 'facetapi_sort_active',
  279. 'description' => t('Sort by whether the facet is active or not.'),
  280. 'weight' => -50,
  281. );
  282. return $sorts;
  283. }
  284. /**
  285. * Allows for alterations to the sort definitions.
  286. *
  287. * @param array &$sort_info
  288. * The return values of hook_facetapi_sort_info() implementations.
  289. *
  290. * @see hook_facetapi_sort_info()
  291. */
  292. function hook_facetapi_sort_info_alter(array &$sort_info) {
  293. $sort_info['active']['weight'] = 10;
  294. }
  295. /**
  296. * Define all adapter plugins provided by the module.
  297. *
  298. * See the FacetapiAdapter docblock for more information on what an adapter does
  299. * and how it interacts with the implementing search module.
  300. *
  301. * @return array
  302. * An associative array keyed by unique name of the adapter. Each adapter is
  303. * an associative array keyed by "handler" containing:
  304. * - class: The name of the plugin class.
  305. *
  306. * @see FacetapiAdapter
  307. */
  308. function hook_facetapi_adapters() {
  309. return array(
  310. 'apachesolr' => array(
  311. 'handler' => array(
  312. 'class' => 'FacetapiApachesolrFacetapiAdapter',
  313. ),
  314. ),
  315. );
  316. }
  317. /**
  318. * Define all dependency plugins provided by the module.
  319. *
  320. * See the FacetapiDependency docblock for more information on what dependency
  321. * plugins do and what their responsibilities are.
  322. *
  323. * @return array
  324. * An associative array keyed by unique name of the dependency. Each
  325. * dependency is an associative array keyed by "handler" containing:
  326. * - label: The human readable name of the plugin displayed in the admin UI.
  327. * - class: The name of the plugin class.
  328. *
  329. * @see FacetapiDependency
  330. */
  331. function hook_facetapi_dependencies() {
  332. return array(
  333. 'bundle' => array(
  334. 'handler' => array(
  335. 'label' => t('Content types'),
  336. 'class' => 'FacetapiDependencyBundle',
  337. ),
  338. ),
  339. );
  340. }
  341. /**
  342. * Define all empty behavior plugins provided by the module.
  343. *
  344. * See the FacetapiEmptyBehavior docblock for more information on what empty
  345. * behavior plugins do and what their responsibilities are.
  346. *
  347. * @return array
  348. * An associative array keyed by unique name of the empty behavior. Each empty
  349. * behavior is an associative array keyed by "handler" containing:
  350. * - label: The human readable name of the plugin displayed in the admin UI.
  351. * - class: The name of the plugin class.
  352. *
  353. * @see FacetapiEmptyBehavior
  354. */
  355. function hook_facetapi_empty_behaviors() {
  356. return array(
  357. 'none' => array(
  358. 'handler' => array(
  359. 'label' => t('Do not display facet'),
  360. 'class' => 'FacetapiEmptyBehaviorNone',
  361. ),
  362. ),
  363. );
  364. }
  365. /**
  366. * Define all filter plugins provided by the module.
  367. *
  368. * See the FacetapiFilter docblock for more information on what filter plugins
  369. * do and what their responsibilities are.
  370. *
  371. * @return array
  372. * An associative array keyed by unique name of the filter. Each filter is an
  373. * associative array keyed by "handler" containing:
  374. * - label: The human readable name of the plugin displayed in the admin UI.
  375. * - class: The name of the plugin class.
  376. *
  377. * @see FacetapiFilter
  378. */
  379. function hook_facetapi_filters() {
  380. return array(
  381. 'active_items' => array(
  382. 'handler' => array(
  383. 'label' => t('Do not display active items'),
  384. 'class' => 'FacetapiFilterActiveItems',
  385. ),
  386. ),
  387. );
  388. }
  389. /**
  390. * Define all query type plugins provided by the module.
  391. *
  392. * See the FacetapiQueryTypeInterface docblock for more information on what
  393. * query type plugins do and what their responsibilities are.
  394. *
  395. * @return array
  396. * An associative array keyed by unique name of the query type. Each query
  397. * type is an associative array keyed by "handler" containing:
  398. * - class: The name of the plugin class.
  399. * - adapter: The adapter that the query type plugin is associated with.
  400. *
  401. * @see FacetapiQueryTypeInterface
  402. */
  403. function hook_facetapi_query_types() {
  404. return array(
  405. 'apachesolr_term' => array(
  406. 'handler' => array(
  407. 'class' => 'FacetapiApachesolrTerm',
  408. 'adapter' => 'apachesolr',
  409. ),
  410. ),
  411. );
  412. }
  413. /**
  414. * Define all URL processor plugins provided by the module.
  415. *
  416. * See the FacetapiUrlProcessor docblock for more information on what url
  417. * processor plugins do and what their responsibilities are.
  418. *
  419. * @return array
  420. * An associative array keyed by unique name of the URL processor. Each URL
  421. * processor is an associative array keyed by "handler" containing:
  422. * - label: The human readable name of the plugin displayed in the admin UI.
  423. * - class: The name of the plugin class.
  424. *
  425. * @see FacetapiUrlProcessor
  426. */
  427. function hook_facetapi_url_processors() {
  428. return array(
  429. 'standard' => array(
  430. 'handler' => array(
  431. 'label' => t('Standard URL processors'),
  432. 'class' => 'FacetapiUrlProcessorStandard',
  433. ),
  434. ),
  435. );
  436. }
  437. /**
  438. * Define all widget plugins provided by the module.
  439. *
  440. * See the FacetapiWidget docblock for more information on what widget plugins
  441. * do and what their responsibilities are.
  442. *
  443. * @return array
  444. * An associative array keyed by unique name of the widget. Each widget is an
  445. * associative array keyed by "handler" containing:
  446. * - label: The human readable name of the plugin displayed in the admin UI.
  447. * - class: The name of the plugin class.
  448. * - query types: An array of query-types that this widget is compatible with.
  449. * - requirements: An array of requirements that must pass in order for this
  450. * widget to be displayed. Requirements are associative arrays keyed by
  451. * function to requirement options. The value defaults to a requirement that
  452. * the "element type" realm property is equal to "links".
  453. *
  454. * @see FacetapiWidget
  455. * @see facetapi_get_widgets()
  456. */
  457. function hook_facetapi_widgets() {
  458. return array(
  459. 'facetapi_links' => array(
  460. 'handler' => array(
  461. 'label' => t('Links'),
  462. 'class' => 'FacetapiWidgetLinks',
  463. 'query types' => array('term', 'date'),
  464. 'requirements' => array(
  465. 'facetapi_requirement_realm_property' => array('element type' => 'links')
  466. ),
  467. ),
  468. ),
  469. );
  470. }
  471. /**
  472. * Forces delta mapping of a facet block.
  473. *
  474. * This obscure hook is useful for cases where facets are disabled, but their
  475. * block positioning needs to be set anyways. If a facet is enabled via the
  476. * facetapi_set_facet_enabled() API function, its block needs to be enabled
  477. * and assigned to a region despite the facet not being enabled in the Facet API
  478. * interface, which would normally prevent the block from being listed.
  479. *
  480. * @return array
  481. * An associative array keyed by searcher. Each sub array is an associative
  482. * array keyed by realm name to facet names whose delta mappings are forced.
  483. */
  484. function hook_facetapi_force_delta_mapping() {
  485. return array(
  486. // The machine-readable name of the searcher.
  487. 'my_searcher' => array(
  488. // The realm we are mapping, usually block.
  489. 'block' => array(
  490. // Machine readable names of facets whose mappping are being forced.
  491. // Regardless of whether they are enabled via the Facet API interface,
  492. // their blocks will be available to enable and position via
  493. // admin/structure/block.
  494. 'facet_one',
  495. 'facet_two',
  496. ),
  497. ),
  498. );
  499. }
  500. /**
  501. * Alters the hash that is generated for block deltas.
  502. *
  503. * @param type &$hash
  504. * The delta hash.
  505. * @param type $delta
  506. * The block's delta.
  507. *
  508. * @see https://www.drupal.org/node/1828396
  509. */
  510. function hook_facetapi_hash_alter(&$hash, $delta) {
  511. $hash = drupal_html_class($hash);
  512. }
  513. /**
  514. * Implemented by the translator module to translate a string.
  515. *
  516. * This hook is invoked by the facetapi_translate_string() function. The
  517. * "facetapi:translator_module" variable stores which translator module is
  518. * active since it wouldn't make sense to have multiple translator modules.
  519. *
  520. * @param $name
  521. * The name of the string in "textgroup:object_type:object_key:property_name"
  522. * format.
  523. * @param $string
  524. * The string being translated.
  525. * @param $langcode
  526. * The language code to translate to a language other than what is used to
  527. * display the page. Defaults to NULL, which uses the current language.
  528. *
  529. * @return
  530. * The translated string.
  531. *
  532. * @see facetapi_translate_string()
  533. */
  534. function hook_facetapi_translate_string($name, $string, $langcode = NULL) {
  535. // In this instance, the translator module integrates with the i18n project.
  536. return i18n_string($name, $string, array('langcode' => $langcode));
  537. }
  538. /**
  539. * @} End of "addtogroup hooks".
  540. */