views.api.php 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107
  1. <?php
  2. /**
  3. * @file
  4. * Describe hooks provided by the Views module.
  5. */
  6. /**
  7. * @mainpage Views 3 API Manual
  8. *
  9. * Much of this information is actually stored in the advanced help; please
  10. * check the API topic. This help will primarily be aimed at documenting
  11. * classes and function calls.
  12. *
  13. * Topics:
  14. * - @link views_lifetime The life of a view @endlink
  15. * - @link views_hooks Views hooks @endlink
  16. * - @link views_handlers About Views handlers @endlink
  17. * - @link views_plugins About Views plugins @endlink
  18. * - @link views_templates Views template files @endlink
  19. * - @link views_module_handlers Views module handlers @endlink
  20. */
  21. /**
  22. * @defgroup views_lifetime The life of a view
  23. * @{
  24. * This page explains the basic cycle of a view and what processes happen.
  25. *
  26. * @todo.
  27. * @}
  28. */
  29. /**
  30. * @defgroup views_handlers About Views handlers
  31. * @{
  32. * In Views, a handler is an object that is part of the view and is part of the
  33. * query building flow.
  34. *
  35. * Handlers are objects; much of the time, the base handlers will work, but
  36. * often you'll need to override the handler to achieve something meaningful.
  37. * One typical handler override will be views_handler_filter_operator_in which
  38. * allows you to have a filter select from a list of options; you'll need to
  39. * override this to provide your list.
  40. *
  41. * Handlers have two distinct code flows; the UI flow and the view building
  42. * flow.
  43. *
  44. * For the query flow:
  45. * - handler->construct()
  46. * - Create the initial handler; at this time it is not yet attached to a
  47. * view. It is here that you can set basic defaults if needed, but there
  48. * will be no knowledge of the environment yet.
  49. * - handler->set_definition()
  50. * - Set the data from hook_views_data() relevant to the handler.
  51. * - handler->init()
  52. * - Attach the handler to a view, and usually provides the options from the
  53. * display.
  54. * - handler->pre_query()
  55. * - Run prior to the query() stage to do early processing.
  56. * - handler->query()
  57. * - Do the bulk of the work this handler needs to do to add itself to the
  58. * query.
  59. *
  60. * Fields, being the only handlers concerned with output, also have an extended
  61. * piece of the flow:
  62. *
  63. * - handler->pre_render(&$values)
  64. * - Called prior to the actual rendering, this allows handlers to query for
  65. * extra data; the entire resultset is available here, and this is where
  66. * items that have "multiple values" per record can do their extra query for
  67. * all of the records available. There are several examples of this at work
  68. * in the code, see for example views_handler_field_user_roles.
  69. * - handler->render()
  70. * - This does the actual work of rendering the field.
  71. *
  72. * Most handlers are just extensions of existing classes with a few tweaks that
  73. * are specific to the field in question. For example,
  74. * views_handler_filter_in_operator provides a simple mechanism to set a
  75. * multiple-value list for setting filter values. Below,
  76. * views_handler_filter_node_type overrides the list options, but inherits
  77. * everything else.
  78. *
  79. * @code
  80. * class views_handler_filter_node_type extends views_handler_filter_in_operator {
  81. * function get_value_options() {
  82. * if (!isset($this->value_options)) {
  83. * $this->value_title = t('Node type');
  84. * $types = node_get_types();
  85. * foreach ($types as $type => $info) {
  86. * $options[$type] = $info-&gt;name;
  87. * }
  88. * $this->value_options = $options;
  89. * }
  90. * }
  91. * }
  92. * @endcode
  93. *
  94. * Handlers are stored in their own files and loaded on demand. Like all other
  95. * module files, they must first be registered through the module's info file.
  96. * For example:
  97. *
  98. * @code
  99. * name = Example module
  100. * description = "Gives an example of a module."
  101. * core = 7.x
  102. * files[] = example.module
  103. * files[] = example.install
  104. *
  105. * ; Views handlers
  106. * files[] = includes/views/handlers/example_handler_argument_string.inc
  107. * @endcode
  108. *
  109. * The best place to learn more about handlers and how they work is to explore
  110. * @link views_handlers Views' handlers @endlink and use existing handlers as a
  111. * guide and a model. Understanding how views_handler and its child classes work
  112. * is handy but you can do a lot just following these models. You can also
  113. * explore the views module directory, particularly node.views.inc.
  114. *
  115. * Please note that while all handler names in views are prefixed with views_,
  116. * you should use your own module's name to prefix your handler names in order
  117. * to ensure namespace safety. Note that the basic pattern for handler naming
  118. * goes like this:
  119. *
  120. * [module]_handler_[type]_[tablename]_[fieldname].
  121. *
  122. * Sometimes table and fieldname are not appropriate, but something that
  123. * resembles what the table/field would be can be used.
  124. *
  125. * See also:
  126. * - @link views_field_handlers Views field handlers @endlink
  127. * - @link views_sort_handlers Views sort handlers @endlink
  128. * - @link views_filter_handlers Views filter handlers @endlink
  129. * - @link views_argument_handlers Views argument handlers @endlink
  130. * - @link views_relationship_handlers Views relationship handlers @endlink
  131. * - @link views_area_handlers Views area handlers @endlink
  132. * @}
  133. */
  134. /**
  135. * @defgroup views_plugins About Views plugins
  136. *
  137. * In Views, a plugin is a bit like a handler, but plugins are not directly
  138. * responsible for building the query. Instead, they are objects that are used
  139. * to display the view or make other modifications.
  140. *
  141. * There are 10 types of plugins in Views:
  142. * - Display: Display plugins are responsible for controlling *where* a view
  143. * lives; that is, how they are being exposed to other parts of Drupal. Page
  144. * and block are the most common displays, as well as the ubiquitous 'master'
  145. * (or 'default') display.
  146. * - Style: Style plugins control how a view is displayed. For the most part
  147. * they are object wrappers around theme templates. Styles could for example
  148. * be HTML lists or tables.
  149. * - Row style: Row styles handle each individual record from the main view
  150. * table. The two included by default render the entire entity (nodes only),
  151. * or selected fields.
  152. * - Argument default: Argument default plugins allow pluggable ways of
  153. * providing default values for contextual filters (previously 'arguments').
  154. * This is useful for blocks and other display types lacking a natural
  155. * argument input. Examples are plugins to extract node and user IDs from the
  156. * URL.
  157. * - Argument validator: Validator plugins can ensure arguments are valid, and
  158. * even do transformations on the arguments. They can also provide replacement
  159. * patterns for the view title. For example, the 'content' validator
  160. * verifies verifies that the argument value corresponds to a node, loads
  161. * that node and provides the node title as a replacement pattern.
  162. * - Access: Access plugins are responsible for controlling access to the view.
  163. * Views includes plugins for checking user roles and individual permissions.
  164. * - Query: Query plugins generate and execute a query, so they can be seen as
  165. * a data backend. The default implementation is using SQL. There are
  166. * contributed modules reading data from other sources, see for example the
  167. * Views XML Backend module.
  168. * - Cache: Cache plugins control the storage and loading of caches. Currently
  169. * they can do both result and render caching, but maybe one day cache the
  170. * generated query.
  171. * - Pager plugins: Pager plugins take care of everything regarding pagers.
  172. * From getting and setting the total amount of items to render the pager and
  173. * setting the global pager arrays.
  174. * - Exposed form plugins: Exposed form plugins are responsible for building,
  175. * rendering and controlling exposed forms. They can expose new parts of the
  176. * view to the user and more.
  177. * - Localization plugins: Localization plugins take care how the view options
  178. * are translated. There are example implementations for t(), 'no
  179. * translation' and i18n.
  180. * - Display extenders: Display extender plugins allow scaling of views options
  181. * horizontally. This means that you can add options and do stuff on all
  182. * views displays. One theoretical example is metatags for views.
  183. *
  184. * Plugins are registered by implementing hook_views_plugins() in your
  185. * modulename.views.inc file and returning an array of data.
  186. * For examples please look at views_views_plugins() in
  187. * views/includes/plugins.inc as it has examples for all of them.
  188. *
  189. * Similar to handlers, make sure that you add your plugin files to the
  190. * module.info file.
  191. *
  192. * The array defining plugins will look something like this:
  193. * @code
  194. * return array(
  195. * 'display' => array(
  196. * // ... list of display plugins,
  197. * ),
  198. * 'style' => array(
  199. * // ... list of style plugins,
  200. * ),
  201. * 'row' => array(
  202. * // ... list of row style plugins,
  203. * ),
  204. * 'argument default' => array(
  205. * // ... list of argument default plugins,
  206. * ),
  207. * 'argument validator' => array(
  208. * // ... list of argument validator plugins,
  209. * ),
  210. * 'access' => array(
  211. * // ... list of access plugins,
  212. * ),
  213. * 'query' => array(
  214. * // ... list of query plugins,
  215. * ),,
  216. * 'cache' => array(
  217. * // ... list of cache plugins,
  218. * ),,
  219. * 'pager' => array(
  220. * // ... list of pager plugins,
  221. * ),,
  222. * 'exposed_form' => array(
  223. * // ... list of exposed_form plugins,
  224. * ),,
  225. * 'localization' => array(
  226. * // ... list of localization plugins,
  227. * ),
  228. * 'display_extender' => array(
  229. * // ... list of display extender plugins,
  230. * ),
  231. * );
  232. * @endcode
  233. *
  234. * Each plugin will be registered with an identifier for the plugin, plus a
  235. * fairly lengthy list of items that can define how and where the plugin is
  236. * used. Here is an example of a row style plugin from Views core:
  237. * @code
  238. * 'node' => array(
  239. * 'title' => t('Node'),
  240. * 'help' => t('Display the node with standard node view.'),
  241. * 'handler' => 'views_plugin_row_node_view',
  242. * 'path' => drupal_get_path('module', 'views') . '/modules/node', // not necessary for most modules
  243. * 'theme' => 'views_view_row_node',
  244. * 'base' => array('node'), // only works with 'node' as base.
  245. * 'uses options' => TRUE,
  246. * 'type' => 'normal',
  247. * ),
  248. * @endcode
  249. *
  250. * Of particular interest is the *path* directive, which works a little
  251. * differently from handler registration; each plugin must define its own path,
  252. * rather than relying on a global info for the paths. For example:
  253. * @code
  254. * 'feed' => array(
  255. * 'title' => t('Feed'),
  256. * 'help' => t('Display the view as a feed, such as an RSS feed.'),
  257. * 'handler' => 'views_plugin_display_feed',
  258. * 'uses hook menu' => TRUE,
  259. * 'use ajax' => FALSE,
  260. * 'use pager' => FALSE,
  261. * 'accept attachments' => FALSE,
  262. * 'admin' => t('Feed'),
  263. * 'help topic' => 'display-feed',
  264. * ),
  265. * @endcode
  266. *
  267. * Please be sure to prefix your plugin identifiers with your module name to
  268. * ensure namespace safety; after all, two different modules could try to
  269. * implement the 'grid2' plugin, and that would cause one plugin to completely
  270. * fail.
  271. *
  272. * @todo Finish this document.
  273. *
  274. * See also:
  275. * - @link views_display_plugins Views display plugins @endlink
  276. * - @link views_style_plugins Views style plugins @endlink
  277. * - @link views_row_plugins Views row plugins @endlink
  278. */
  279. /**
  280. * @defgroup views_hooks Views hooks
  281. * @{
  282. * Hooks that can be implemented by other modules in order to implement the
  283. * Views API.
  284. */
  285. /**
  286. * Describes data tables (or the equivalent) to Views.
  287. *
  288. * This hook should be placed in MODULENAME.views.inc and it will be
  289. * auto-loaded. MODULENAME.views.inc must be in the directory specified by the
  290. * 'path' key returned by MODULENAME_views_api(), or the same directory as the
  291. * .module file, if 'path' is unspecified.
  292. *
  293. * @return
  294. * An associative array describing the data structure. Primary key is the
  295. * name used internally by Views for the table(s) – usually the actual table
  296. * name. The values for the key entries are described in detail below.
  297. */
  298. function hook_views_data() {
  299. // This example describes how to write hook_views_data() for the following
  300. // table:
  301. //
  302. // CREATE TABLE example_table (
  303. // nid INT(11) NOT NULL COMMENT 'Primary key; refers to {node}.nid.',
  304. // plain_text_field VARCHAR(32) COMMENT 'Just a plain text field.',
  305. // numeric_field INT(11) COMMENT 'Just a numeric field.',
  306. // boolean_field INT(1) COMMENT 'Just an on/off field.',
  307. // timestamp_field INT(8) COMMENT 'Just a timestamp field.',
  308. // PRIMARY KEY(nid)
  309. // );
  310. // First, the entry $data['example_table']['table'] describes properties of
  311. // the actual table – not its content.
  312. // The 'group' index will be used as a prefix in the UI for any of this
  313. // table's fields, sort criteria, etc. so it's easy to tell where they came
  314. // from.
  315. $data['example_table']['table']['group'] = t('Example table');
  316. // Define this as a base table – a table that can be described in itself by
  317. // views (and not just being brought in as a relationship). In reality this
  318. // is not very useful for this table, as it isn't really a distinct object of
  319. // its own, but it makes a good example.
  320. $data['example_table']['table']['base'] = array(
  321. 'field' => 'nid', // This is the identifier field for the view.
  322. 'title' => t('Example table'),
  323. 'help' => t('Example table contains example content and can be related to nodes.'),
  324. 'weight' => -10,
  325. );
  326. // This table references the {node} table. The declaration below creates an
  327. // 'implicit' relationship to the node table, so that when 'node' is the base
  328. // table, the fields are automatically available.
  329. $data['example_table']['table']['join'] = array(
  330. // Index this array by the table name to which this table refers.
  331. // 'left_field' is the primary key in the referenced table.
  332. // 'field' is the foreign key in this table.
  333. 'node' => array(
  334. 'left_field' => 'nid',
  335. 'field' => 'nid',
  336. ),
  337. );
  338. // Next, describe each of the individual fields in this table to Views. This
  339. // is done by describing $data['example_table']['FIELD_NAME']. This part of
  340. // the array may then have further entries:
  341. // - title: The label for the table field, as presented in Views.
  342. // - help: The description text for the table field.
  343. // - relationship: A description of any relationship handler for the table
  344. // field.
  345. // - field: A description of any field handler for the table field.
  346. // - sort: A description of any sort handler for the table field.
  347. // - filter: A description of any filter handler for the table field.
  348. // - argument: A description of any argument handler for the table field.
  349. // - area: A description of any handler for adding content to header,
  350. // footer or as no result behaviour.
  351. //
  352. // The handler descriptions are described with examples below.
  353. // Node ID table field.
  354. $data['example_table']['nid'] = array(
  355. 'title' => t('Example content'),
  356. 'help' => t('Some example content that references a node.'),
  357. // Define a relationship to the {node} table, so example_table views can
  358. // add a relationship to nodes. If you want to define a relationship the
  359. // other direction, use hook_views_data_alter(), or use the 'implicit' join
  360. // method described above.
  361. 'relationship' => array(
  362. 'base' => 'node', // The name of the table to join with.
  363. 'base field' => 'nid', // The name of the field on the joined table.
  364. // 'field' => 'nid' -- see hook_views_data_alter(); not needed here.
  365. 'handler' => 'views_handler_relationship',
  366. 'label' => t('Default label for the relationship'),
  367. 'title' => t('Title shown when adding the relationship'),
  368. 'help' => t('More information on this relationship'),
  369. ),
  370. );
  371. // Example plain text field.
  372. $data['example_table']['plain_text_field'] = array(
  373. 'title' => t('Plain text field'),
  374. 'help' => t('Just a plain text field.'),
  375. 'field' => array(
  376. 'handler' => 'views_handler_field',
  377. 'click sortable' => TRUE, // This is use by the table display plugin.
  378. ),
  379. 'sort' => array(
  380. 'handler' => 'views_handler_sort',
  381. ),
  382. 'filter' => array(
  383. 'handler' => 'views_handler_filter_string',
  384. ),
  385. 'argument' => array(
  386. 'handler' => 'views_handler_argument_string',
  387. ),
  388. );
  389. // Example numeric text field.
  390. $data['example_table']['numeric_field'] = array(
  391. 'title' => t('Numeric field'),
  392. 'help' => t('Just a numeric field.'),
  393. 'field' => array(
  394. 'handler' => 'views_handler_field_numeric',
  395. 'click sortable' => TRUE,
  396. ),
  397. 'filter' => array(
  398. 'handler' => 'views_handler_filter_numeric',
  399. ),
  400. 'sort' => array(
  401. 'handler' => 'views_handler_sort',
  402. ),
  403. );
  404. // Example boolean field.
  405. $data['example_table']['boolean_field'] = array(
  406. 'title' => t('Boolean field'),
  407. 'help' => t('Just an on/off field.'),
  408. 'field' => array(
  409. 'handler' => 'views_handler_field_boolean',
  410. 'click sortable' => TRUE,
  411. ),
  412. 'filter' => array(
  413. 'handler' => 'views_handler_filter_boolean_operator',
  414. // Note that you can override the field-wide label:
  415. 'label' => t('Published'),
  416. // This setting is used by the boolean filter handler, as possible option.
  417. 'type' => 'yes-no',
  418. // use boolean_field = 1 instead of boolean_field <> 0 in WHERE statment.
  419. 'use equal' => TRUE,
  420. ),
  421. 'sort' => array(
  422. 'handler' => 'views_handler_sort',
  423. ),
  424. );
  425. // Example timestamp field.
  426. $data['example_table']['timestamp_field'] = array(
  427. 'title' => t('Timestamp field'),
  428. 'help' => t('Just a timestamp field.'),
  429. 'field' => array(
  430. 'handler' => 'views_handler_field_date',
  431. 'click sortable' => TRUE,
  432. ),
  433. 'sort' => array(
  434. 'handler' => 'views_handler_sort_date',
  435. ),
  436. 'filter' => array(
  437. 'handler' => 'views_handler_filter_date',
  438. ),
  439. );
  440. return $data;
  441. }
  442. /**
  443. * Alter table structure.
  444. *
  445. * You can add/edit/remove existing tables defined by hook_views_data().
  446. *
  447. * This hook should be placed in MODULENAME.views.inc and it will be
  448. * auto-loaded. MODULENAME.views.inc must be in the directory specified by the
  449. * 'path' key returned by MODULENAME_views_api(), or the same directory as the
  450. * .module file, if 'path' is unspecified.
  451. *
  452. * @param $data
  453. * An array of all Views data, passed by reference. See hook_views_data() for
  454. * structure.
  455. *
  456. * @see hook_views_data()
  457. */
  458. function hook_views_data_alter(&$data) {
  459. // This example alters the title of the node:nid field in the Views UI.
  460. $data['node']['nid']['title'] = t('Node-Nid');
  461. // This example adds an example field to the users table.
  462. $data['users']['example_field'] = array(
  463. 'title' => t('Example field'),
  464. 'help' => t('Some example content that references a user'),
  465. 'handler' => 'hook_handlers_field_example_field',
  466. );
  467. // This example changes the handler of the node title field.
  468. // In this handler you could do stuff, like preview of the node when clicking
  469. // the node title.
  470. $data['node']['title']['handler'] = 'modulename_handlers_field_node_title';
  471. // This example adds a relationship to table {foo}, so that 'foo' views can
  472. // add this table using a relationship. Because we don't want to write over
  473. // the primary key field definition for the {foo}.fid field, we use a dummy
  474. // field name as the key.
  475. $data['foo']['dummy_name'] = array(
  476. 'title' => t('Example relationship'),
  477. 'help' => t('Example help'),
  478. 'relationship' => array(
  479. 'base' => 'example_table', // Table we're joining to.
  480. 'base field' => 'eid', // Field on the joined table.
  481. 'field' => 'fid', // Real field name on the 'foo' table.
  482. 'handler' => 'views_handler_relationship',
  483. 'label' => t('Default label for relationship'),
  484. 'title' => t('Title seen when adding relationship'),
  485. 'help' => t('More information about relationship.'),
  486. ),
  487. );
  488. // Note that the $data array is not returned – it is modified by reference.
  489. }
  490. /**
  491. * Describes plugins defined by the module.
  492. *
  493. * This hook should be placed in MODULENAME.views.inc and it will be
  494. * auto-loaded. MODULENAME.views.inc must be in the directory specified by the
  495. * 'path' key returned by MODULENAME_views_api(), or the same directory as the
  496. * .module file, if 'path' is unspecified. All plugin files need to be
  497. * referenced in MODULENAME.info with the files[] directive.
  498. *
  499. * @return
  500. * An array on the form $plugins['PLUGIN TYPE']['PLUGIN NAME']. The plugin
  501. * must be one of row, display, display_extender, style, argument default,
  502. * argument validator, access, query, cache, pager, exposed_form or
  503. * localization. The plugin name should be prefixed with your module name.
  504. * The value for each entry is an associateive array that may contain the
  505. * following entries:
  506. * - Used by all plugin types:
  507. * - title (required): The name of the plugin, as shown in Views. Wrap in
  508. * t().
  509. * - handler (required): The name of the file containing the class
  510. * describing the handler, which must also be the name of the handler's
  511. * class.
  512. * - path: Path to the handler. Only required if the handler is not placed
  513. * in the same folder as the .module file or in the subfolder 'views'.
  514. * - parent: The name of the plugin this plugin extends. Since Drupal 7 this
  515. * is no longer required, but may still be useful from a code readability
  516. * perspective.
  517. * - no ui: Set to TRUE to denote that the plugin doesn't appear to be
  518. * selectable in the ui, though on the api side they still exists.
  519. * - uses options: Set to TRUE to denote that the plugin has an additional
  520. * options form.
  521. * - help: A short help text, wrapped in t() used as description on the plugin settings form.
  522. * - help topic: The name of an entry by advanced help for the plugin.
  523. * - theme: The name of a theme suggestion to use for the display.
  524. * - js: An array with paths to js files that should be included for the
  525. * display. Note that the path should be relative Drupal root, not module
  526. * root.
  527. * - type: Each plugin can specify a type parameter to group certain
  528. * plugins together. For example all row plugins related to feeds are
  529. * grouped together, because a rss style plugin only accepts feed row
  530. * plugins.
  531. *
  532. * - Used by display plugins:
  533. * - admin: The administrative name of the display, as displayed on the
  534. * Views overview and also used as default name for new displays. Wrap in
  535. * t().
  536. * - no remove: Set to TRUE to make the display non-removable. (Basically
  537. * only used for the master/default display.)
  538. * - use ajax: Set to TRUE to allow AJAX loads in the display. If it's
  539. * disabled there will be no ajax option in the ui.
  540. * - use pager: Set to TRUE to allow paging in the display.
  541. * - use more: Set to TRUE to allow the 'use more' setting in the display.
  542. * - accept attachments: Set to TRUE to allow attachment displays to be
  543. * attached to this display type.
  544. * - contextual links locations: An array with places where contextual links
  545. * should be added. Can for example be 'page' or 'block'. If you don't
  546. * specify it there will be contextual links around the rendered view. If
  547. * this is not set or regions have been specified, views will display an
  548. * option to 'hide contextual links'. Use an empty array if you do not want
  549. * this.
  550. * - uses hook menu: Set to TRUE to have the display included by
  551. * views_menu_alter(). views_menu_alter executes then execute_hook_menu
  552. * on the display object.
  553. * - uses hook block: Set to TRUE to have the display included by
  554. * views_block_info().
  555. * - theme: The name of a theme suggestion to use for the display.
  556. * - js: An array with paths to js files that should be included for the
  557. * display. Note that the path should be relative Drupal root, not module
  558. * root.
  559. *
  560. * - Used by style plugins:
  561. * - uses row plugin: Set to TRUE to allow row plugins for this style.
  562. * - uses row class: Set to TRUE to allow the CSS class settings for rows.
  563. * - uses fields: Set to TRUE to have the style plugin accept field
  564. * handlers.
  565. * - uses grouping: Set to TRUE to allow the grouping settings for rows.
  566. * - even empty: May have the value 'even empty' to tell Views that the style
  567. * should be rendered even if there are no results.
  568. *
  569. * - Used by row plugins:
  570. * - uses fields: Set to TRUE to have the row plugin accept field handlers.
  571. */
  572. function hook_views_plugins() {
  573. $plugins = array();
  574. $plugins['argument validator'] = array(
  575. 'taxonomy_term' => array(
  576. 'title' => t('Taxonomy term'),
  577. 'handler' => 'views_plugin_argument_validate_taxonomy_term',
  578. // Declaring path explicitly not necessary for most modules.
  579. 'path' => drupal_get_path('module', 'views') . '/modules/taxonomy',
  580. ),
  581. );
  582. return array(
  583. 'module' => 'views', // This just tells our themes are elsewhere.
  584. 'argument validator' => array(
  585. 'taxonomy_term' => array(
  586. 'title' => t('Taxonomy term'),
  587. 'handler' => 'views_plugin_argument_validate_taxonomy_term',
  588. 'path' => drupal_get_path('module', 'views') . '/modules/taxonomy', // not necessary for most modules
  589. ),
  590. ),
  591. 'argument default' => array(
  592. 'taxonomy_tid' => array(
  593. 'title' => t('Taxonomy term ID from URL'),
  594. 'handler' => 'views_plugin_argument_default_taxonomy_tid',
  595. 'path' => drupal_get_path('module', 'views') . '/modules/taxonomy',
  596. 'parent' => 'fixed',
  597. ),
  598. ),
  599. );
  600. }
  601. /**
  602. * Alter existing plugins data, defined by modules.
  603. *
  604. * @see hook_views_plugins()
  605. */
  606. function hook_views_plugins_alter(&$plugins) {
  607. // Add apachesolr to the base of the node row plugin.
  608. $plugins['row']['node']['base'][] = 'apachesolr';
  609. }
  610. /**
  611. * Register View API information.
  612. *
  613. * This is required for your module to have its include files loaded; for
  614. * example, when implementing hook_views_default_views().
  615. *
  616. * @return
  617. * An array with the following possible keys:
  618. * - api: (required) The version of the Views API the module implements.
  619. * - path: (optional) If includes are stored somewhere other than within the
  620. * root module directory, specify its path here.
  621. * - template path: (optional) A path where the module has stored it's views
  622. * template files. When you have specificed this key views automatically
  623. * uses the template files for the views. You can use the same naming
  624. * conventions like for normal views template files.
  625. */
  626. function hook_views_api() {
  627. return array(
  628. 'api' => 3,
  629. 'path' => drupal_get_path('module', 'example') . '/includes/views',
  630. 'template path' => drupal_get_path('module', 'example') . '/themes',
  631. );
  632. }
  633. /**
  634. * This hook allows modules to provide their own views which can either be used
  635. * as-is or as a "starter" for users to build from.
  636. *
  637. * This hook should be placed in MODULENAME.views_default.inc and it will be
  638. * auto-loaded. MODULENAME.views_default.inc must be in the directory specified
  639. * by the 'path' key returned by MODULENAME_views_api(), or the same directory
  640. * as the .module file, if 'path' is unspecified.
  641. *
  642. * The $view->disabled boolean flag indicates whether the View should be
  643. * enabled (FALSE) or disabled (TRUE) by default.
  644. *
  645. * @return
  646. * An associative array containing the structures of views, as generated from
  647. * the Export tab, keyed by the view name. A best practice is to go through
  648. * and add t() to all title and label strings, with the exception of menu
  649. * strings.
  650. */
  651. function hook_views_default_views() {
  652. // Begin copy and paste of output from the Export tab of a view.
  653. $view = new view;
  654. $view->name = 'frontpage';
  655. $view->description = 'Emulates the default Drupal front page; you may set the default home page path to this view to make it your front page.';
  656. $view->tag = 'default';
  657. $view->base_table = 'node';
  658. $view->human_name = 'Front page';
  659. $view->core = 0;
  660. $view->api_version = '3.0';
  661. $view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
  662. /* Display: Master */
  663. $handler = $view->new_display('default', 'Master', 'default');
  664. $handler->display->display_options['access']['type'] = 'none';
  665. $handler->display->display_options['cache']['type'] = 'none';
  666. $handler->display->display_options['query']['type'] = 'views_query';
  667. $handler->display->display_options['query']['options']['query_comment'] = FALSE;
  668. $handler->display->display_options['exposed_form']['type'] = 'basic';
  669. $handler->display->display_options['pager']['type'] = 'full';
  670. $handler->display->display_options['style_plugin'] = 'default';
  671. $handler->display->display_options['row_plugin'] = 'node';
  672. /* Sort criterion: Content: Sticky */
  673. $handler->display->display_options['sorts']['sticky']['id'] = 'sticky';
  674. $handler->display->display_options['sorts']['sticky']['table'] = 'node';
  675. $handler->display->display_options['sorts']['sticky']['field'] = 'sticky';
  676. $handler->display->display_options['sorts']['sticky']['order'] = 'DESC';
  677. /* Sort criterion: Content: Post date */
  678. $handler->display->display_options['sorts']['created']['id'] = 'created';
  679. $handler->display->display_options['sorts']['created']['table'] = 'node';
  680. $handler->display->display_options['sorts']['created']['field'] = 'created';
  681. $handler->display->display_options['sorts']['created']['order'] = 'DESC';
  682. /* Filter criterion: Content: Promoted to front page */
  683. $handler->display->display_options['filters']['promote']['id'] = 'promote';
  684. $handler->display->display_options['filters']['promote']['table'] = 'node';
  685. $handler->display->display_options['filters']['promote']['field'] = 'promote';
  686. $handler->display->display_options['filters']['promote']['value'] = '1';
  687. $handler->display->display_options['filters']['promote']['group'] = 0;
  688. $handler->display->display_options['filters']['promote']['expose']['operator'] = FALSE;
  689. /* Filter criterion: Content: Published */
  690. $handler->display->display_options['filters']['status']['id'] = 'status';
  691. $handler->display->display_options['filters']['status']['table'] = 'node';
  692. $handler->display->display_options['filters']['status']['field'] = 'status';
  693. $handler->display->display_options['filters']['status']['value'] = '1';
  694. $handler->display->display_options['filters']['status']['group'] = 0;
  695. $handler->display->display_options['filters']['status']['expose']['operator'] = FALSE;
  696. /* Display: Page */
  697. $handler = $view->new_display('page', 'Page', 'page');
  698. $handler->display->display_options['path'] = 'frontpage';
  699. /* Display: Feed */
  700. $handler = $view->new_display('feed', 'Feed', 'feed');
  701. $handler->display->display_options['defaults']['title'] = FALSE;
  702. $handler->display->display_options['title'] = 'Front page feed';
  703. $handler->display->display_options['pager']['type'] = 'some';
  704. $handler->display->display_options['style_plugin'] = 'rss';
  705. $handler->display->display_options['row_plugin'] = 'node_rss';
  706. $handler->display->display_options['path'] = 'rss.xml';
  707. $handler->display->display_options['displays'] = array(
  708. 'default' => 'default',
  709. 'page' => 'page',
  710. );
  711. $handler->display->display_options['sitename_title'] = '1';
  712. // (Export ends here.)
  713. // Add view to list of views to provide.
  714. $views[$view->name] = $view;
  715. // ...Repeat all of the above for each view the module should provide.
  716. // At the end, return array of default views.
  717. return $views;
  718. }
  719. /**
  720. * Alter default views defined by other modules.
  721. *
  722. * This hook is called right before all default views are cached to the
  723. * database. It takes a keyed array of views by reference.
  724. *
  725. * Example usage to add a field to a view:
  726. * @code
  727. * $handler =& $view->display['DISPLAY_ID']->handler;
  728. * // Add the user name field to the view.
  729. * $handler->display->display_options['fields']['name']['id'] = 'name';
  730. * $handler->display->display_options['fields']['name']['table'] = 'users';
  731. * $handler->display->display_options['fields']['name']['field'] = 'name';
  732. * $handler->display->display_options['fields']['name']['label'] = 'Author';
  733. * $handler->display->display_options['fields']['name']['link_to_user'] = 1;
  734. * @endcode
  735. */
  736. function hook_views_default_views_alter(&$views) {
  737. if (isset($views['taxonomy_term'])) {
  738. $views['taxonomy_term']->display['default']->display_options['title'] = 'Categories';
  739. }
  740. }
  741. /**
  742. * Performs replacements in the query before being performed.
  743. *
  744. * @param $view
  745. * The View being executed.
  746. * @return
  747. * An array with keys being the strings to replace, and the values the strings
  748. * to replace them with. The strings to replace are ofted surrounded with
  749. * '***', as illustrated in the example implementation.
  750. */
  751. function hook_views_query_substitutions($view) {
  752. // Example from views_views_query_substitutions().
  753. global $language_content;
  754. return array(
  755. '***CURRENT_VERSION***' => VERSION,
  756. '***CURRENT_TIME***' => REQUEST_TIME,
  757. '***CURRENT_LANGUAGE***' => $language_content->language,
  758. '***DEFAULT_LANGUAGE***' => language_default('language'),
  759. );
  760. }
  761. /**
  762. * This hook is called to get a list of placeholders and their substitutions,
  763. * used when preprocessing a View with form elements.
  764. *
  765. * @return
  766. * An array with keys being the strings to replace, and the values the strings
  767. * to replace them with.
  768. */
  769. function hook_views_form_substitutions() {
  770. return array(
  771. '<!--views-form-example-substitutions-->' => 'Example Substitution',
  772. );
  773. }
  774. /**
  775. * Allows altering a view at the very beginning of views processing, before
  776. * anything is done.
  777. *
  778. * Adding output to the view can be accomplished by placing text on
  779. * $view->attachment_before and $view->attachment_after.
  780. * @param $view
  781. * The view object about to be processed.
  782. * @param $display_id
  783. * The machine name of the active display.
  784. * @param $args
  785. * An array of arguments passed into the view.
  786. */
  787. function hook_views_pre_view(&$view, &$display_id, &$args) {
  788. // Change the display if the acting user has 'administer site configuration'
  789. // permission, to display something radically different.
  790. // (Note that this is not necessarily the best way to solve that task. Feel
  791. // free to contribute another example!)
  792. if (
  793. $view->name == 'my_special_view' &&
  794. user_access('administer site configuration') &&
  795. $display_id == 'public_display'
  796. ) {
  797. $display_id = 'private_display';
  798. }
  799. }
  800. /**
  801. * This hook is called right before the build process, but after displays
  802. * are attached and the display performs its pre_execute phase.
  803. *
  804. * Adding output to the view can be accomplished by placing text on
  805. * $view->attachment_before and $view->attachment_after.
  806. * @param $view
  807. * The view object about to be processed.
  808. */
  809. function hook_views_pre_build(&$view) {
  810. // Because of some unexplicable business logic, we should remove all
  811. // attachments from all views on Mondays.
  812. // (This alter could be done later in the execution process as well.)
  813. if (date('D') == 'Mon') {
  814. unset($view->attachment_before);
  815. unset($view->attachment_after);
  816. }
  817. }
  818. /**
  819. * This hook is called right after the build process. The query is now fully
  820. * built, but it has not yet been run through db_rewrite_sql.
  821. *
  822. * Adding output to the view can be accomplished by placing text on
  823. * $view->attachment_before and $view->attachment_after.
  824. * @param $view
  825. * The view object about to be processed.
  826. */
  827. function hook_views_post_build(&$view) {
  828. // If the exposed field 'type' is set, hide the column containing the content
  829. // type. (Note that this is a solution for a particular view, and makes
  830. // assumptions about both exposed filter settings and the fields in the view.
  831. // Also note that this alter could be done at any point before the view being
  832. // rendered.)
  833. if ($view->name == 'my_view' && isset($view->exposed_raw_input['type']) && $view->exposed_raw_input['type'] != 'All') {
  834. // 'Type' should be interpreted as content type.
  835. if (isset($view->field['type'])) {
  836. $view->field['type']->options['exclude'] = TRUE;
  837. }
  838. }
  839. }
  840. /**
  841. * This hook is called right before the execute process. The query is now fully
  842. * built, but it has not yet been run through db_rewrite_sql.
  843. *
  844. * Adding output to the view can be accomplished by placing text on
  845. * $view->attachment_before and $view->attachment_after.
  846. * @param $view
  847. * The view object about to be processed.
  848. */
  849. function hook_views_pre_execute(&$view) {
  850. // Whenever a view queries more than two tables, show a message that notifies
  851. // view administrators that the query might be heavy.
  852. // (This action could be performed later in the execution process, but not
  853. // earlier.)
  854. if (count($view->query->tables) > 2 && user_access('administer views')) {
  855. drupal_set_message(t('The view %view may be heavy to execute.', array('%view' => $view->name)), 'warning');
  856. }
  857. }
  858. /**
  859. * This hook is called right after the execute process. The query has
  860. * been executed, but the pre_render() phase has not yet happened for
  861. * handlers.
  862. *
  863. * Adding output to the view can be accomplished by placing text on
  864. * $view->attachment_before and $view->attachment_after. Altering the
  865. * content can be achieved by editing the items of $view->result.
  866. * @param $view
  867. * The view object about to be processed.
  868. */
  869. function hook_views_post_execute(&$view) {
  870. // If there are more than 100 results, show a message that encourages the user
  871. // to change the filter settings.
  872. // (This action could be performed later in the execution process, but not
  873. // earlier.)
  874. if ($view->total_rows > 100) {
  875. drupal_set_message(t('You have more than 100 hits. Use the filter settings to narrow down your list.'));
  876. }
  877. }
  878. /**
  879. * This hook is called right before the render process. The query has been
  880. * executed, and the pre_render() phase has already happened for handlers, so
  881. * all data should be available.
  882. *
  883. * Adding output to the view can be accomplished by placing text on
  884. * $view->attachment_before and $view->attachment_after. Altering the content
  885. * can be achieved by editing the items of $view->result.
  886. *
  887. * This hook can be utilized by themes.
  888. * @param $view
  889. * The view object about to be processed.
  890. */
  891. function hook_views_pre_render(&$view) {
  892. // Scramble the order of the rows shown on this result page.
  893. // Note that this could be done earlier, but not later in the view execution
  894. // process.
  895. shuffle($view->result);
  896. }
  897. /**
  898. * Post process any rendered data.
  899. *
  900. * This can be valuable to be able to cache a view and still have some level of
  901. * dynamic output. In an ideal world, the actual output will include HTML
  902. * comment based tokens, and then the post process can replace those tokens.
  903. *
  904. * Example usage. If it is known that the view is a node view and that the
  905. * primary field will be a nid, you can do something like this:
  906. *
  907. * <!--post-FIELD-NID-->
  908. *
  909. * And then in the post render, create an array with the text that should
  910. * go there:
  911. *
  912. * strtr($output, array('<!--post-FIELD-1-->' => 'output for FIELD of nid 1');
  913. *
  914. * All of the cached result data will be available in $view->result, as well,
  915. * so all ids used in the query should be discoverable.
  916. *
  917. * This hook can be utilized by themes.
  918. * @param $view
  919. * The view object about to be processed.
  920. * @param $output
  921. * A flat string with the rendered output of the view.
  922. * @param $cache
  923. * The cache settings.
  924. */
  925. function hook_views_post_render(&$view, &$output, &$cache) {
  926. // When using full pager, disable any time-based caching if there are less
  927. // then 10 results.
  928. if ($view->query->pager instanceof views_plugin_pager_full && $cache->options['type'] == 'time' && count($view->result) < 10) {
  929. $cache['options']['results_lifespan'] = 0;
  930. $cache['options']['output_lifespan'] = 0;
  931. }
  932. }
  933. /**
  934. * Alter the query before executing the query.
  935. *
  936. * This hook should be placed in MODULENAME.views.inc and it will be
  937. * auto-loaded. MODULENAME.views.inc must be in the directory specified by the
  938. * 'path' key returned by MODULENAME_views_api(), or the same directory as the
  939. * .module file, if 'path' is unspecified.
  940. *
  941. * @param $view
  942. * The view object about to be processed.
  943. * @param $query
  944. * An object describing the query.
  945. * @see hook_views_query_substitutions()
  946. */
  947. function hook_views_query_alter(&$view, &$query) {
  948. // (Example assuming a view with an exposed filter on node title.)
  949. // If the input for the title filter is a positive integer, filter against
  950. // node ID instead of node title.
  951. if ($view->name == 'my_view' && is_numeric($view->exposed_raw_input['title']) && $view->exposed_raw_input['title'] > 0) {
  952. // Traverse through the 'where' part of the query.
  953. foreach ($query->where as &$condition_group) {
  954. foreach ($condition_group['conditions'] as &$condition) {
  955. // If this is the part of the query filtering on title, chang the
  956. // condition to filter on node ID.
  957. if ($condition['field'] == 'node.title') {
  958. $condition = array(
  959. 'field' => 'node.nid',
  960. 'value' => $view->exposed_raw_input['title'],
  961. 'operator' => '=',
  962. );
  963. }
  964. }
  965. }
  966. }
  967. }
  968. /**
  969. * Alter the information box that (optionally) appears with a view preview,
  970. * including query and performance statistics.
  971. *
  972. * This hook should be placed in MODULENAME.views.inc and it will be
  973. * auto-loaded. MODULENAME.views.inc must be in the directory specified by the
  974. * 'path' key returned by MODULENAME_views_api(), or the same directory as the
  975. * .module file, if 'path' is unspecified.
  976. *
  977. * Warning: $view is not a reference in PHP4 and cannot be modified here. But it
  978. * IS a reference in PHP5, and can be modified. Please be careful with it.
  979. *
  980. * @param $rows
  981. * An associative array with two keys:
  982. * - query: An array of rows suitable for theme('table'), containing
  983. * information about the query and the display title and path.
  984. * - statistics: An array of rows suitable for theme('table'), containing
  985. * performance statistics.
  986. * @param $view
  987. * The view object.
  988. * @see theme_table()
  989. */
  990. function hook_views_preview_info_alter(&$rows, $view) {
  991. // Adds information about the tables being queried by the view to the query
  992. // part of the info box.
  993. $rows['query'][] = array(
  994. t('<strong>Table queue</strong>'),
  995. count($view->query->table_queue) . ': (' . implode(', ', array_keys($view->query->table_queue)) . ')',
  996. );
  997. }
  998. /**
  999. * This hooks allows to alter the links at the top of the view edit form. Some
  1000. * modules might want to add links there.
  1001. *
  1002. * @param $links
  1003. * An array of links which will be displayed at the top of the view edit form.
  1004. * Each entry should be on a form suitable for theme('link').
  1005. * @param view $view
  1006. * The full view object which is currently edited.
  1007. * @param $display_id
  1008. * The current display id which is edited. For example that's 'default' or
  1009. * 'page_1'.
  1010. */
  1011. function hook_views_ui_display_top_links_alter(&$links, $view, $display_id) {
  1012. // Put the export link first in the list.
  1013. if (isset($links['export'])) {
  1014. $links = array('export' => $links['export']) + $links;
  1015. }
  1016. }
  1017. /**
  1018. * This hook allows to alter the commands which are used on a views ajax
  1019. * request.
  1020. *
  1021. * @param $commands
  1022. * An array of ajax commands
  1023. * @param $view view
  1024. * The view which is requested.
  1025. */
  1026. function hook_views_ajax_data_alter(&$commands, $view) {
  1027. // Replace Views' method for scrolling to the top of the element with your
  1028. // custom scrolling method.
  1029. foreach ($commands as &$command) {
  1030. if ($command['method'] == 'viewsScrollTop') {
  1031. $command['method'] .= 'myScrollTop';
  1032. }
  1033. }
  1034. }
  1035. /**
  1036. * Allow modules to respond to the Views cache being invalidated.
  1037. *
  1038. * This hook should fire whenever a view is enabled, disabled, created,
  1039. * updated, or deleted.
  1040. *
  1041. * @see views_invalidate_cache()
  1042. */
  1043. function hook_views_invalidate_cache() {
  1044. cache_clear_all('views:*', 'cache_mymodule', TRUE);
  1045. }
  1046. /**
  1047. * @}
  1048. */
  1049. /**
  1050. * @defgroup views_module_handlers Views module handlers
  1051. * @{
  1052. * Handlers exposed by various modules to Views.
  1053. * @}
  1054. */