views.api.php 30.3 KB
Newer Older
merlinofchaos's avatar
merlinofchaos committed
1 2 3 4
<?php

/**
 * @file
5
 * Describes hooks and plugins provided by the Views module.
merlinofchaos's avatar
merlinofchaos committed
6 7 8
 */

/**
9
 * @defgroup views_plugins Views plugins
merlinofchaos's avatar
merlinofchaos committed
10
 *
11
 * Views plugins are objects that are used to build and render the view.
12 13
 * Plugins are registered by extending one of the Views base plugin classes
 * and defining settings in the plugin annotation.
merlinofchaos's avatar
merlinofchaos committed
14
 *
15 16 17 18
 * Views has the following types of plugins:
 * - Access: Access plugins are responsible for controlling access to the
 *   view. Views includes plugins for checking user roles and individual
 *   permissions. Access plugins extend
19
 *   \Drupal\views\Plugin\views\access\AccessPluginBase.
20 21 22 23 24
 * - Argument default: Argument default plugins allow pluggable ways of
 *   providing default values for contextual filters. This is useful for
 *   blocks and other display types lacking a natural argument input.
 *   Examples are plugins to extract node and user IDs from the URL. Argument
 *   default plugins extend
25
 *   \Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase.
26 27 28 29 30 31
 * - Argument validator: Validator plugins can ensure arguments are valid,
 *   and even do transformations on the arguments. They can also provide
 *   replacement patterns for the view title. For example, the 'content'
 *   validator verifies verifies that the argument value corresponds to a
 *   node, loads that node and provides the node title as a replacement
 *   pattern. Argument validator plugins extend
32
 *   \Drupal\views\Plugin\views\argument_validator\ArgumentValidatorPluginBase.
33 34 35
 * - Cache: Cache plugins control the storage and loading of caches.
 *   Currently they can do both result and render caching. It might also be
 *   possible to cache the generated query. Cache plugins extend
36
 *   \Drupal\views\Plugin\views\cache\CachePluginBase.
37 38 39 40 41
 * - Display: Display plugins are responsible for controlling where a View is
 *   rendered; that is, how it is exposed to other parts of Drupal. 'Page'
 *   and 'block' are the most commonly used display plugins. Each View also
 *   has a 'master' (or 'default') display that includes information shared
 *   between all its displays. (See
42 43
 *   \Drupal\views\Plugin\views\display\DefaultDisplay.) Display plugins extend
 *   \Drupal\views\Plugin\views\display\DisplayPluginBase.
44 45 46 47 48
 * - Display extender: Display extender plugins allow additional options or
 *   configurations to added to views across all display types. For example,
 *   if you wanted to allow site users to add certain metadata to the rendered
 *   output of every view display regardless of display type, you could provide
 *   this option as a display extender. Display extender plugins extend
49
 *   \Drupal\views\Plugin\views\display_extender\DisplayExtenderPluginBase.
50 51
 * - Exposed form: Exposed form plugins are responsible for building,
 *   rendering, and controlling exposed forms. Exposed form plugins extend
52
 *   \Drupal\views\Plugin\views\display\DisplayPluginBase.
53 54 55
 * - Handlers: Handler plugins help build the view query object that the query
 *   plugin then executes to retrieve the data from the storage backend (see
 *   below). There are several types of handlers:
56
 *   - Area handlers: Extend \Drupal\views\Plugin\views\area\AreaHandlerBase
57
 *   - Argument handlers: Extend
58 59
 *     \Drupal\views\Plugin\views\argument\ArgumentHandlerBase
 *   - Field handlers: Extend \Drupal\views\Plugin\views\field\FieldHandlerBase
60
 *   - Filter handlers: Extend
61
 *     \Drupal\views\Plugin\views\filter\FilterHandlerBase
62
 *   - Relationship handlers:
63 64
 *     Extend \Drupal\views\Plugin\views\relationship\RelationshipHandlerBase
 *   - Sort handlers: Extend \Drupal\views\Plugin\views\sort:SortHandlerBase
65 66 67
 * - Pager: Pager plugins take care of everything regarding pagers, including
 *   getting setting the total number of items to render the pager and
 *   setting the global pager arrays. Pager plugins extend
68
 *   \Drupal\views\Plugin\views\pager\PagerPluginBase.
69 70 71 72
 * - Query: Query plugins generate and execute a built query object against a
 *   particular storage backend, converting the Views query object into an
 *   actual query. The only default implementation is SQL. (Note that most
 *   handler plugins currently rely on the SQL query plugin.) Query plugins
73
 *   extend \Drupal\views\Plugin\views\query\QueryPluginBase.
74 75 76
 * - Row style: Row styles handle rendering each individual record from the
 *   main view table. The two default implementations render the entire entity
 *   (nodes only), or selected fields. Row style plugins extend
77
 *   \Drupal\views\Plugin\views\row\RowPluginBase).
78 79 80
 * - Style: Style plugins control how a view is displayed. For the most part
 *   they are object wrappers around theme templates. Examples of styles
 *   include HTML lists, tables, etc. Style plugins extend
81
 *   \Drupal\views\Plugin\views\style\StylePluginBase.
82 83
 *
 * @todo Add an explanation for each type of handler.
84 85 86 87 88
 * @todo Document how to use annotations and what goes in them.
 * @todo Add @ingroup to all the base plugins for this group.
 * @todo Add a separate @ingroup for all plugins?
 * @todo Document specific options on the appropriate plugin base classes.
 * @todo Add examples.
merlinofchaos's avatar
merlinofchaos committed
89
 *
90 91
 * @see \Drupal\views\Plugin\views\PluginBase
 * @see \Drupal\views\Plugin\views\HandlerBase
merlinofchaos's avatar
merlinofchaos committed
92 93 94 95 96
 */

/**
 * @defgroup views_hooks Views hooks
 * @{
97
 * Hooks that allow other modules to implement the Views API.
merlinofchaos's avatar
merlinofchaos committed
98 99
 */

100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
/**
 * Analyze a view to provide warnings about its configuration.
 *
 * @param \Drupal\views\ViewExecutable $view
 *   The view being executed.
 *
 * @return array
 *   Array of warning messages built by Analyzer::formatMessage to be displayed
 *   to the user following analysis of the view.
 */
function hook_views_analyze(Drupal\views\ViewExecutable $view) {
  $messages = array();

  if ($view->display_handler->options['pager']['type'] == 'none') {
    $messages[] = Drupal\views\Analyzer::formatMessage(t('This view has no pager. This could cause performance issues when the view contains many items.'), 'warning');
  }

  return $messages;
}

merlinofchaos's avatar
merlinofchaos committed
120
/**
121
 * Describe data tables (or the equivalent) to Views.
122
 *
123
 * The data described with this hook is fetched and retrieved by
124
 * \Drupal\views\Views::viewsData()->get().
125
 *
126
 * @return array
merlinofchaos's avatar
merlinofchaos committed
127
 *   An associative array describing the data structure. Primary key is the
128
 *   name used internally by Views for the table(s) – usually the actual table
merlinofchaos's avatar
merlinofchaos committed
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
 *   name. The values for the key entries are described in detail below.
 */
function hook_views_data() {
  // This example describes how to write hook_views_data() for the following
  // table:
  //
  // CREATE TABLE example_table (
  //   nid INT(11) NOT NULL         COMMENT 'Primary key; refers to {node}.nid.',
  //   plain_text_field VARCHAR(32) COMMENT 'Just a plain text field.',
  //   numeric_field INT(11)        COMMENT 'Just a numeric field.',
  //   boolean_field INT(1)         COMMENT 'Just an on/off field.',
  //   timestamp_field INT(8)       COMMENT 'Just a timestamp field.',
  //   PRIMARY KEY(nid)
  // );

  // First, the entry $data['example_table']['table'] describes properties of
145
  // the actual table – not its content.
merlinofchaos's avatar
merlinofchaos committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

  // The 'group' index will be used as a prefix in the UI for any of this
  // table's fields, sort criteria, etc. so it's easy to tell where they came
  // from.
  $data['example_table']['table']['group'] = t('Example table');

  // Define this as a base table – a table that can be described in itself by
  // views (and not just being brought in as a relationship). In reality this
  // is not very useful for this table, as it isn't really a distinct object of
  // its own, but it makes a good example.
  $data['example_table']['table']['base'] = array(
    'field' => 'nid', // This is the identifier field for the view.
    'title' => t('Example table'),
    'help' => t('Example table contains example content and can be related to nodes.'),
    'weight' => -10,
  );

  // This table references the {node} table. The declaration below creates an
  // 'implicit' relationship to the node table, so that when 'node' is the base
  // table, the fields are automatically available.
  $data['example_table']['table']['join'] = array(
    // Index this array by the table name to which this table refers.
    // 'left_field' is the primary key in the referenced table.
    // 'field' is the foreign key in this table.
    'node' => array(
      'left_field' => 'nid',
      'field' => 'nid',
    ),
  );

  // Next, describe each of the individual fields in this table to Views. This
  // is done by describing $data['example_table']['FIELD_NAME']. This part of
  // the array may then have further entries:
  //   - title: The label for the table field, as presented in Views.
  //   - help: The description text for the table field.
181 182
  //   - relationship: A description of any relationship handler for the table
  //     field.
merlinofchaos's avatar
merlinofchaos committed
183 184 185 186 187 188 189 190 191 192 193 194 195
  //   - field: A description of any field handler for the table field.
  //   - sort: A description of any sort handler for the table field.
  //   - filter: A description of any filter handler for the table field.
  //   - argument: A description of any argument handler for the table field.
  //   - area: A description of any handler for adding content to header,
  //     footer or as no result behaviour.
  //
  // The handler descriptions are described with examples below.

  // Node ID table field.
  $data['example_table']['nid'] = array(
    'title' => t('Example content'),
    'help' => t('Some example content that references a node.'),
196 197 198 199
    // Define a relationship to the {node} table, so example_table views can
    // add a relationship to nodes. If you want to define a relationship the
    // other direction, use hook_views_data_alter(), or use the 'implicit' join
    // method described above.
merlinofchaos's avatar
merlinofchaos committed
200
    'relationship' => array(
dawehner's avatar
dawehner committed
201 202
      'base' => 'node', // The name of the table to join with
      'field' => 'nid', // The name of the field to join with
aspilicious's avatar
aspilicious committed
203
      'id' => 'standard',
dawehner's avatar
dawehner committed
204
      'label' => t('Example node'),
merlinofchaos's avatar
merlinofchaos committed
205 206 207 208 209 210 211 212
    ),
  );

  // Example plain text field.
  $data['example_table']['plain_text_field'] = array(
    'title' => t('Plain text field'),
    'help' => t('Just a plain text field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
213
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
214 215
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
216
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
217 218
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
219
      'id' => 'string',
merlinofchaos's avatar
merlinofchaos committed
220 221
    ),
    'argument' => array(
aspilicious's avatar
aspilicious committed
222
      'id' => 'string',
merlinofchaos's avatar
merlinofchaos committed
223 224 225 226 227 228 229 230
    ),
  );

  // Example numeric text field.
  $data['example_table']['numeric_field'] = array(
    'title' => t('Numeric field'),
    'help' => t('Just a numeric field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
231
      'id' => 'numeric',
merlinofchaos's avatar
merlinofchaos committed
232 233
     ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
234
      'id' => 'numeric',
merlinofchaos's avatar
merlinofchaos committed
235 236
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
237
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
238 239 240 241 242 243 244 245
    ),
  );

  // Example boolean field.
  $data['example_table']['boolean_field'] = array(
    'title' => t('Boolean field'),
    'help' => t('Just an on/off field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
246
      'id' => 'boolean',
merlinofchaos's avatar
merlinofchaos committed
247 248
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
249
      'id' => 'boolean',
merlinofchaos's avatar
merlinofchaos committed
250 251 252 253 254
      // Note that you can override the field-wide label:
      'label' => t('Published'),
      // This setting is used by the boolean filter handler, as possible option.
      'type' => 'yes-no',
      // use boolean_field = 1 instead of boolean_field <> 0 in WHERE statment.
255
      'use_equal' => TRUE,
merlinofchaos's avatar
merlinofchaos committed
256 257
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
258
      'id' => 'standard',
merlinofchaos's avatar
merlinofchaos committed
259 260 261 262 263 264 265 266
    ),
  );

  // Example timestamp field.
  $data['example_table']['timestamp_field'] = array(
    'title' => t('Timestamp field'),
    'help' => t('Just a timestamp field.'),
    'field' => array(
aspilicious's avatar
aspilicious committed
267
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
268 269
    ),
    'sort' => array(
aspilicious's avatar
aspilicious committed
270
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
271 272
    ),
    'filter' => array(
aspilicious's avatar
aspilicious committed
273
      'id' => 'date',
merlinofchaos's avatar
merlinofchaos committed
274 275 276 277 278 279 280
    ),
  );

  return $data;
}

/**
281
 * Alter the table structure defined by hook_views_data().
merlinofchaos's avatar
merlinofchaos committed
282
 *
283
 * @param array $data
284 285
 *   An array of all Views data, passed by reference. See hook_views_data() for
 *   structure.
merlinofchaos's avatar
merlinofchaos committed
286 287 288
 *
 * @see hook_views_data()
 */
289
function hook_views_data_alter(array &$data) {
290
  // This example alters the title of the node:nid field in the Views UI.
merlinofchaos's avatar
merlinofchaos committed
291 292
  $data['node']['nid']['title'] = t('Node-Nid');

293
  // This example adds an example field to the users table.
merlinofchaos's avatar
merlinofchaos committed
294 295 296 297 298 299 300
  $data['users']['example_field'] = array(
    'title' => t('Example field'),
    'help' => t('Some example content that references a user'),
    'handler' => 'hook_handlers_field_example_field',
  );

  // This example changes the handler of the node title field.
301
  // In this handler you could do stuff, like preview of the node when clicking
merlinofchaos's avatar
merlinofchaos committed
302 303 304
  // the node title.
  $data['node']['title']['handler'] = 'modulename_handlers_field_node_title';

305 306 307 308 309 310 311 312 313 314 315
  // This example adds a relationship to table {foo}, so that 'foo' views can
  // add this table using a relationship. Because we don't want to write over
  // the primary key field definition for the {foo}.fid field, we use a dummy
  // field name as the key.
  $data['foo']['dummy_name'] = array(
    'title' => t('Example relationship'),
    'help' => t('Example help'),
    'relationship' => array(
      'base' => 'example_table', // Table we're joining to.
      'base field' => 'eid', // Field on the joined table.
      'field' => 'fid', // Real field name on the 'foo' table.
aspilicious's avatar
aspilicious committed
316
      'id' => 'standard',
317 318 319 320 321 322
      'label' => t('Default label for relationship'),
      'title' => t('Title seen when adding relationship'),
      'help' => t('More information about relationship.'),
    ),
  );

merlinofchaos's avatar
merlinofchaos committed
323 324 325 326
  // Note that the $data array is not returned – it is modified by reference.
}

/**
327
 * Replace special strings in the query before it is executed.
merlinofchaos's avatar
merlinofchaos committed
328
 *
329
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
330
 *   The View being executed.
331 332 333 334
 * @return array
 *   An associative array where each key is a string to be replaced, and the
 *   corresponding value is its replacement. The strings to replace are often
 *   surrounded with '***', as illustrated in the example implementation.
merlinofchaos's avatar
merlinofchaos committed
335
 */
336
function hook_views_query_substitutions(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
337 338 339 340
  // Example from views_views_query_substitutions().
  return array(
    '***CURRENT_VERSION***' => VERSION,
    '***CURRENT_TIME***' => REQUEST_TIME,
341 342
    '***CURRENT_LANGUAGE***' => language(\Drupal\Core\Language\Language::TYPE_CONTENT)->id,
    '***DEFAULT_LANGUAGE***' => language_default()->id,
merlinofchaos's avatar
merlinofchaos committed
343 344 345 346
  );
}

/**
347
 * Replace special strings when processing a view with form elements.
merlinofchaos's avatar
merlinofchaos committed
348
 *
349 350 351
 * @return array
 *   An associative array where each key is a string to be replaced, and the
 *   corresponding value is its replacement.
merlinofchaos's avatar
merlinofchaos committed
352 353 354 355 356 357 358 359
 */
function hook_views_form_substitutions() {
  return array(
    '<!--views-form-example-substitutions-->' => 'Example Substitution',
  );
}

/**
360
 * Alter a view at the very beginning of Views processing.
merlinofchaos's avatar
merlinofchaos committed
361
 *
362 363 364
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
365
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
366
 *   The view object about to be processed.
367
 * @param string $display_id
merlinofchaos's avatar
merlinofchaos committed
368
 *   The machine name of the active display.
369
 * @param array $args
merlinofchaos's avatar
merlinofchaos committed
370
 *   An array of arguments passed into the view.
371
 *
372
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
373
 */
374
function hook_views_pre_view(ViewExecutable &$view, &$display_id, array &$args) {
merlinofchaos's avatar
merlinofchaos committed
375 376
  // Change the display if the acting user has 'administer site configuration'
  // permission, to display something radically different.
377 378 379
  // @todo Note that this is not necessarily the best way to solve that task.
  //   Add a better example.
  if ($view->name == 'my_special_view' && user_access('administer site configuration') && $display_id == 'public_display') {
merlinofchaos's avatar
merlinofchaos committed
380 381 382 383 384
    $display_id = 'private_display';
  }
}

/**
385
 * Act on the view before the query is built, but after displays are attached.
merlinofchaos's avatar
merlinofchaos committed
386
 *
387 388 389
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
390
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
391
 *   The view object about to be processed.
392
 *
393
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
394
 */
395
function hook_views_pre_build(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
396 397 398 399 400 401 402 403 404 405
  // Because of some unexplicable business logic, we should remove all
  // attachments from all views on Mondays.
  // (This alter could be done later in the execution process as well.)
  if (date('D') == 'Mon') {
    unset($view->attachment_before);
    unset($view->attachment_after);
  }
}

/**
406
 * Act on the view immediately after the query is built.
merlinofchaos's avatar
merlinofchaos committed
407
 *
408 409 410
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
411
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
412
 *   The view object about to be processed.
413
 *
414
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
415
 */
416
function hook_views_post_build(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430
  // If the exposed field 'type' is set, hide the column containing the content
  // type. (Note that this is a solution for a particular view, and makes
  // assumptions about both exposed filter settings and the fields in the view.
  // Also note that this alter could be done at any point before the view being
  // rendered.)
  if ($view->name == 'my_view' && isset($view->exposed_raw_input['type']) && $view->exposed_raw_input['type'] != 'All') {
    // 'Type' should be interpreted as content type.
    if (isset($view->field['type'])) {
      $view->field['type']->options['exclude'] = TRUE;
    }
  }
}

/**
431
 * Act on the view after the query is built and just before it is executed.
merlinofchaos's avatar
merlinofchaos committed
432
 *
433 434 435
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
436
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
437
 *   The view object about to be processed.
438
 *
439
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
440
 */
441
function hook_views_pre_execute(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
442 443 444 445 446 447 448 449 450 451
  // Whenever a view queries more than two tables, show a message that notifies
  // view administrators that the query might be heavy.
  // (This action could be performed later in the execution process, but not
  // earlier.)
  if (count($view->query->tables) > 2 && user_access('administer views')) {
    drupal_set_message(t('The view %view may be heavy to execute.', array('%view' => $view->name)), 'warning');
  }
}

/**
452
 * Act on the view immediately after the query has been executed.
merlinofchaos's avatar
merlinofchaos committed
453
 *
454
 * At this point the query has been executed, but the preRender() phase has
455 456 457 458 459
 * not yet happened for handlers.
 *
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
460
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
461
 *   The view object about to be processed.
462
 *
463
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
464
 */
465
function hook_views_post_execute(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
466 467 468 469 470 471 472 473 474 475
  // If there are more than 100 results, show a message that encourages the user
  // to change the filter settings.
  // (This action could be performed later in the execution process, but not
  // earlier.)
  if ($view->total_rows > 100) {
    drupal_set_message(t('You have more than 100 hits. Use the filter settings to narrow down your list.'));
  }
}

/**
476
 * Act on the view immediately before rendering it.
merlinofchaos's avatar
merlinofchaos committed
477
 *
478
 * At this point the query has been executed, and the preRender() phase has
479 480
 * already happened for handlers, so all data should be available. This hook
 * can be utilized by themes.
merlinofchaos's avatar
merlinofchaos committed
481
 *
482 483 484
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
485
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
486
 *   The view object about to be processed.
487
 *
488
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
489
 */
490
function hook_views_pre_render(ViewExecutable &$view) {
merlinofchaos's avatar
merlinofchaos committed
491 492 493 494 495 496 497
  // Scramble the order of the rows shown on this result page.
  // Note that this could be done earlier, but not later in the view execution
  // process.
  shuffle($view->result);
}

/**
498
 * Post-process any rendered data.
merlinofchaos's avatar
merlinofchaos committed
499 500 501
 *
 * This can be valuable to be able to cache a view and still have some level of
 * dynamic output. In an ideal world, the actual output will include HTML
502 503
 * comment-based tokens, and then the post process can replace those tokens.
 * This hook can be utilized by themes.
merlinofchaos's avatar
merlinofchaos committed
504 505 506
 *
 * Example usage. If it is known that the view is a node view and that the
 * primary field will be a nid, you can do something like this:
507 508 509 510
 * @code
 *   <!--post-FIELD-NID-->
 * @encode
 * And then in the post-render, create an array with the text that should
merlinofchaos's avatar
merlinofchaos committed
511
 * go there:
512 513 514
 * @code
 *   strtr($output, array('<!--post-FIELD-1-->' => 'output for FIELD of nid 1');
 * @encode
merlinofchaos's avatar
merlinofchaos committed
515 516 517
 * All of the cached result data will be available in $view->result, as well,
 * so all ids used in the query should be discoverable.
 *
518
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
519
 *   The view object about to be processed.
520
 * @param string $output
merlinofchaos's avatar
merlinofchaos committed
521
 *   A flat string with the rendered output of the view.
522
 * @param CacheBackendInterface $cache
merlinofchaos's avatar
merlinofchaos committed
523
 *   The cache settings.
524
 *
525
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
526
 */
527 528 529 530 531 532
function hook_views_post_render(ViewExecutable &$view, &$output, CacheBackendInterface &$cache) {
  // When using full pager, disable any time-based caching if there are fewer
  // than 10 results.
  if ($view->pager instanceof Drupal\views\Plugin\views\pager\Full && $cache instanceof Drupal\views\Plugin\views\cache\Time && count($view->result) < 10) {
    $cache->options['results_lifespan'] = 0;
    $cache->options['output_lifespan'] = 0;
merlinofchaos's avatar
merlinofchaos committed
533 534 535 536
  }
}

/**
537
 * Alter the query before it is executed.
merlinofchaos's avatar
merlinofchaos committed
538
 *
539
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
540
 *   The view object about to be processed.
541 542 543
 * @param QueryPluginBase $query
 *   The query plugin object for the query.
 *
merlinofchaos's avatar
merlinofchaos committed
544
 * @see hook_views_query_substitutions()
545
 * @see \Drupal\views\Plugin\views\query\Sql
merlinofchaos's avatar
merlinofchaos committed
546
 */
547
function hook_views_query_alter(ViewExecutable &$view, QueryPluginBase &$query) {
merlinofchaos's avatar
merlinofchaos committed
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
  // (Example assuming a view with an exposed filter on node title.)
  // If the input for the title filter is a positive integer, filter against
  // node ID instead of node title.
  if ($view->name == 'my_view' && is_numeric($view->exposed_raw_input['title']) && $view->exposed_raw_input['title'] > 0) {
    // Traverse through the 'where' part of the query.
    foreach ($query->where as &$condition_group) {
      foreach ($condition_group['conditions'] as &$condition) {
        // If this is the part of the query filtering on title, chang the
        // condition to filter on node ID.
        if ($condition['field'] == 'node.title') {
          $condition = array(
            'field' => 'node.nid',
            'value' => $view->exposed_raw_input['title'],
            'operator' => '=',
          );
        }
      }
    }
  }
}

/**
570 571 572 573 574
 * Alter the view preview information.
 *
 * The view preview information is optionally displayed when a view is
 * previewed in the administrative UI. It includes query and performance
 * statistics.
merlinofchaos's avatar
merlinofchaos committed
575
 *
576
 * @param array $rows
merlinofchaos's avatar
merlinofchaos committed
577
 *   An associative array with two keys:
578
 *   - query: An array of rows suitable for '#theme' => 'table', containing
merlinofchaos's avatar
merlinofchaos committed
579
 *     information about the query and the display title and path.
580 581
 *   - statistics: An array of rows suitable for '#theme' => 'table',
 *     containing performance statistics.
582
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
583
 *   The view object.
584
 *
585
 * @see \Drupal\views_ui\ViewUI
merlinofchaos's avatar
merlinofchaos committed
586 587
 * @see theme_table()
 */
588
function hook_views_preview_info_alter(array &$rows, ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
589 590 591 592 593 594 595 596 597
  // Adds information about the tables being queried by the view to the query
  // part of the info box.
  $rows['query'][] = array(
    t('<strong>Table queue</strong>'),
    count($view->query->table_queue) . ': (' . implode(', ', array_keys($view->query->table_queue)) . ')',
  );
}

/**
598 599 600 601
 * Alter the links displayed at the top of the view edit form.
 *
 * @param array $links
 *   A renderable array of links which will be displayed at the top of the
602
 *   view edit form. Each entry will be in a form suitable for
603
 *   '#theme' => 'links'.
604 605 606 607 608 609
 * @param \Drupal\views\ViewExecutable $view
 *   The view object being edited.
 * @param string $display_id
 *   The ID of the display being edited, e.g. 'default' or 'page_1'.
 *
 * @see \Drupal\views_ui\ViewUI::renderDisplayTop()
merlinofchaos's avatar
merlinofchaos committed
610
 */
611
function hook_views_ui_display_top_links_alter(array &$links, ViewExecutable $view, $display_id) {
merlinofchaos's avatar
merlinofchaos committed
612 613 614 615 616 617
  // Put the export link first in the list.
  if (isset($links['export'])) {
    $links = array('export' => $links['export']) + $links;
  }
}

618
// @todo Describe how to alter a view ajax response with event listeners.
merlinofchaos's avatar
merlinofchaos committed
619

620
/**
621
 * Allow modules to respond to the invalidation of the Views cache.
622
 *
623
 * This hook will fire whenever a view is enabled, disabled, created,
624 625 626 627 628
 * updated, or deleted.
 *
 * @see views_invalidate_cache()
 */
function hook_views_invalidate_cache() {
629
  cache('mymodule')->invalidateTags(array('views' => TRUE));
630 631
}

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
/**
 * Modify the list of available views access plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_access_alter(array &$plugins) {
  // Remove the available plugin because the users should not have access to it.
  unset($plugins['role']);
}

/**
 * Modify the list of available views default argument plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_argument_default_alter(array &$plugins) {
  // Remove the available plugin because the users should not have access to it.
  unset($plugins['php']);
}

/**
 * Modify the list of available views argument validation plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_argument_validator_alter(array &$plugins) {
  // Remove the available plugin because the users should not have access to it.
  unset($plugins['php']);
}

/**
 * Modify the list of available views cache plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_cache_alter(array &$plugins) {
  // Change the title.
  $plugins['time']['title'] = t('Custom title');
}

/**
 * Modify the list of available views display extender plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_display_extenders_alter(array &$plugins) {
  // Alter the title of an existing plugin.
  $plugins['time']['title'] = t('Custom title');
}

/**
 * Modify the list of available views display plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_display_alter(array &$plugins) {
  // Alter the title of an existing plugin.
  $plugins['rest_export']['title'] = t('Export');
}

/**
 * Modify the list of available views exposed form plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_exposed_form_alter(array &$plugins) {
  // Remove the available plugin because the users should not have access to it.
  unset($plugins['input_required']);
}

/**
 * Modify the list of available views join plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_join_alter(array &$plugins) {
  // Print out all join plugin names for debugging purposes.
  debug($plugins);
}

/**
 * Modify the list of available views join plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_pager_alter(array &$plugins) {
  // Remove the sql based plugin to force good performance.
  unset($plugins['full']);
}

/**
 * Modify the list of available views query plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_query_alter(array &$plugins) {
  // Print out all query plugin names for debugging purposes.
  debug($plugins);
}

/**
 * Modify the list of available views row plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_row_alter(array &$plugins) {
  // Change the used class of a plugin.
  $plugins['entity:node']['class'] = 'Drupal\node\Plugin\views\row\NodeRow';
  $plugins['entity:node']['module'] = 'node';
}

/**
 * Modify the list of available views style plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_style_alter(array &$plugins) {
  // Change the theme hook of a plugin.
  $plugins['html_list']['theme'] = 'custom_views_view_list';
}

/**
 * Modify the list of available views wizard plugins.
 *
 * This hook may be used to modify plugin properties after they have been
 * specified by other modules.
 *
 * @param array $plugins
 *   An array of all the existing plugin definitions, passed by reference.
 *
 * @see \Drupal\views\Plugin\ViewsPluginManager
 */
function hook_views_plugins_wizard_alter(array &$plugins) {
  // Change the title of a plugin.
  $plugins['node_revision']['title'] = t('Node revision wizard');
}

merlinofchaos's avatar
merlinofchaos committed
841 842 843 844 845 846 847 848 849 850
/**
 * @}
 */

/**
 * @defgroup views_module_handlers Views module handlers
 * @{
 * Handlers exposed by various modules to Views.
 * @}
 */
851