views.api.php 30.1 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
375
376
377
378
function hook_views_pre_view(ViewExecutable $view, $display_id, array &$args) {

  // Modify contextual filters for my_special_view if user has 'my special permission'.
  if ($view->name == 'my_special_view' && user_access('my special permission')) {
    $args[0] = 'custom value';
merlinofchaos's avatar
merlinofchaos committed
379
380
381
382
  }
}

/**
383
 * Act on the view before the query is built, but after displays are attached.
merlinofchaos's avatar
merlinofchaos committed
384
 *
385
386
387
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
388
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
389
 *   The view object about to be processed.
390
 *
391
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
392
 */
393
function hook_views_pre_build(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
394
395
396
397
398
399
400
401
402
403
  // 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);
  }
}

/**
404
 * Act on the view immediately after the query is built.
merlinofchaos's avatar
merlinofchaos committed
405
 *
406
407
408
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
409
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
410
 *   The view object about to be processed.
411
 *
412
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
413
 */
414
function hook_views_post_build(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
415
416
417
418
419
420
421
422
423
424
425
426
427
428
  // 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;
    }
  }
}

/**
429
 * Act on the view after the query is built and just before it is executed.
merlinofchaos's avatar
merlinofchaos committed
430
 *
431
432
433
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
434
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
435
 *   The view object about to be processed.
436
 *
437
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
438
 */
439
function hook_views_pre_execute(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
440
441
442
443
444
445
446
447
448
449
  // 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');
  }
}

/**
450
 * Act on the view immediately after the query has been executed.
merlinofchaos's avatar
merlinofchaos committed
451
 *
452
 * At this point the query has been executed, but the preRender() phase has
453
454
455
456
457
 * not yet happened for handlers.
 *
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
458
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
459
 *   The view object about to be processed.
460
 *
461
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
462
 */
463
function hook_views_post_execute(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
464
465
466
467
468
469
470
471
472
473
  // 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.'));
  }
}

/**
474
 * Act on the view immediately before rendering it.
merlinofchaos's avatar
merlinofchaos committed
475
 *
476
 * At this point the query has been executed, and the preRender() phase has
477
478
 * already happened for handlers, so all data should be available. This hook
 * can be utilized by themes.
merlinofchaos's avatar
merlinofchaos committed
479
 *
480
481
482
 * Output can be added to the view by setting $view->attachment_before
 * and $view->attachment_after.
 *
483
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
484
 *   The view object about to be processed.
485
 *
486
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
487
 */
488
function hook_views_pre_render(ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
489
490
491
492
493
494
495
  // 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);
}

/**
496
 * Post-process any rendered data.
merlinofchaos's avatar
merlinofchaos committed
497
498
499
 *
 * 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
500
501
 * comment-based tokens, and then the post process can replace those tokens.
 * This hook can be utilized by themes.
merlinofchaos's avatar
merlinofchaos committed
502
503
504
 *
 * 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:
505
506
507
508
 * @code
 *   <!--post-FIELD-NID-->
 * @encode
 * And then in the post-render, create an array with the text that should
merlinofchaos's avatar
merlinofchaos committed
509
 * go there:
510
511
512
 * @code
 *   strtr($output, array('<!--post-FIELD-1-->' => 'output for FIELD of nid 1');
 * @encode
merlinofchaos's avatar
merlinofchaos committed
513
514
515
 * All of the cached result data will be available in $view->result, as well,
 * so all ids used in the query should be discoverable.
 *
516
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
517
 *   The view object about to be processed.
518
 * @param string $output
merlinofchaos's avatar
merlinofchaos committed
519
 *   A flat string with the rendered output of the view.
520
 * @param CacheBackendInterface $cache
merlinofchaos's avatar
merlinofchaos committed
521
 *   The cache settings.
522
 *
523
 * @see \Drupal\views\ViewExecutable
merlinofchaos's avatar
merlinofchaos committed
524
 */
525
function hook_views_post_render(ViewExecutable $view, &$output, CacheBackendInterface $cache) {
526
527
528
529
530
  // 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
531
532
533
534
  }
}

/**
535
 * Alter the query before it is executed.
merlinofchaos's avatar
merlinofchaos committed
536
 *
537
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
538
 *   The view object about to be processed.
539
540
541
 * @param QueryPluginBase $query
 *   The query plugin object for the query.
 *
merlinofchaos's avatar
merlinofchaos committed
542
 * @see hook_views_query_substitutions()
543
 * @see \Drupal\views\Plugin\views\query\Sql
merlinofchaos's avatar
merlinofchaos committed
544
 */
545
function hook_views_query_alter(ViewExecutable $view, QueryPluginBase $query) {
merlinofchaos's avatar
merlinofchaos committed
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
  // (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' => '=',
          );
        }
      }
    }
  }
}

/**
568
569
570
571
572
 * 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
573
 *
574
 * @param array $rows
merlinofchaos's avatar
merlinofchaos committed
575
 *   An associative array with two keys:
576
 *   - query: An array of rows suitable for '#theme' => 'table', containing
merlinofchaos's avatar
merlinofchaos committed
577
 *     information about the query and the display title and path.
578
579
 *   - statistics: An array of rows suitable for '#theme' => 'table',
 *     containing performance statistics.
580
 * @param \Drupal\views\ViewExecutable $view
merlinofchaos's avatar
merlinofchaos committed
581
 *   The view object.
582
 *
583
 * @see \Drupal\views_ui\ViewUI
merlinofchaos's avatar
merlinofchaos committed
584
585
 * @see theme_table()
 */
586
function hook_views_preview_info_alter(array &$rows, ViewExecutable $view) {
merlinofchaos's avatar
merlinofchaos committed
587
588
589
590
591
592
593
594
595
  // 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)) . ')',
  );
}

/**
596
597
598
599
 * 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
600
 *   view edit form. Each entry will be in a form suitable for
601
 *   '#theme' => 'links'.
602
603
604
605
606
607
 * @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
608
 */
609
function hook_views_ui_display_top_links_alter(array &$links, ViewExecutable $view, $display_id) {
merlinofchaos's avatar
merlinofchaos committed
610
611
612
613
614
615
  // Put the export link first in the list.
  if (isset($links['export'])) {
    $links = array('export' => $links['export']) + $links;
  }
}

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

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

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
/**
 * 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
839
840
841
842
843
844
845
846
847
848
/**
 * @}
 */

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