-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprevnext.module
149 lines (130 loc) · 4.59 KB
/
prevnext.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
<?php
/**
* @file
* Contains prevnext.module.
*/
use Drupal\Core\Routing\RouteMatchInterface;
use \Drupal\Core\Url;
use \Drupal\Core\Cache\Cache;
/**
* Implements hook_help().
*/
function prevnext_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
// Main module help for the prevnext module.
case 'help.page.prevnext':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('Add a "Previous/Next" links to the node display.') . '</p>';
return $output;
default:
}
}
/**
* Implements hook_theme().
*/
function prevnext_theme($existing, $type, $theme, $path) {
$themes = [];
$themes['prevnext'] = [
'variables' => [
'direction' => '',
'text' => '',
'nid' => '',
'url' => '',
'void' => TRUE,
],
// Note that there is no need to indicate the template name, in absence of
// it the system will assume "prevnext.html.twig", inside "templates" dir.
];
return $themes;
}
/**
* Implements hook_entity_extra_field_info().
*/
function prevnext_entity_extra_field_info() {
$extra = [];
$config = \Drupal::config('prevnext.settings');
$enabled_nodetypes = $config->get('prevnext_enabled_nodetypes');
if (!empty($enabled_nodetypes)) {
foreach ($enabled_nodetypes as $bundle_key => $bundle_name) {
$extra['node'][$bundle_key]['display']['prevnext_previous'] = [
'label' => t('Previous'),
'description' => t('Previous node indicator'),
'weight' => 50,
];
$extra['node'][$bundle_key]['display']['prevnext_next'] = [
'label' => t('Next'),
'description' => t('Next node indicator'),
'weight' => 50,
];
}
}
return $extra;
}
/**
* Implements hook_ENTITY_TYPE_view().
*/
function prevnext_node_view(array &$build, \Drupal\Core\Entity\EntityInterface $entity, \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display, $view_mode) {
if ($display->getComponent('prevnext_previous')) {
$nids = _prevnext_get_prev_and_next_nids($entity);
$build['prevnext_previous'] = [
'#theme' => 'prevnext',
'#direction' => 'previous',
'#text' => t('Previous'),
'#nid' => $nids['prev'],
'#url' => Url::fromUserInput('/node/' . $nids['prev'], ['absolute' => TRUE])->toString(),
'#void' => empty($nids['prev']),
];
$build['prevnext_next'] = [
'#theme' => 'prevnext',
'#direction' => 'next',
'#text' => t('Next'),
'#nid' => $nids['next'],
'#url' => Url::fromUserInput('/node/' . $nids['next'], ['absolute' => TRUE])->toString(),
'#void' => empty($nids['next']),
];
// Once these links will be cached inside the node rendered output, we will
// add a custom cache tag to allow invalidation of all these cached info
// later (for example when a new node of this type is created).
$build['#cache']['tags'][] = 'prevnext-' . $entity->bundle();
}
}
/**
* Implements hook_ENTITY_TYPE_presave().
*/
function prevnext_node_presave(Drupal\Core\Entity\EntityInterface $entity) {
$config = \Drupal::config('prevnext.settings');
$enabled_nodetypes = $config->get('prevnext_enabled_nodetypes');
if (in_array($entity->bundle(), $enabled_nodetypes)) {
// We are saving a node of a type with prevnext enabled, so invalidate
// all cached rendered output of other nodes of this type with our tag.
Cache::invalidateTags(['prevnext-' . $entity->bundle()]);
}
}
/**
* Query the database and fetch the previous and next nids, if they exist.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The node being viewed.
*
* @return array
* An array with keys "prev" and "next", and the values are the NIDs of the
* corresponding previous and next nodes. The values may be empty, if the
* node is the first or last nodes of this type.
*/
function _prevnext_get_prev_and_next_nids(\Drupal\Core\Entity\EntityInterface $entity) {
// @TODO: isn't there a better way to get the query object?
$entity_query = \Drupal::entityQuery('node');
$nodes = $entity_query->condition('status', NODE_PUBLISHED)
->condition('type', $entity->bundle())
->condition('langcode', $entity->language()->getId())
->execute();
// @TODO: improve the logic to allow defining the sort criteria.
$current_nid = $entity->id();
// Reset the array to have numerically indexed keys.
$nodes = array_values($nodes);
$current_key = array_search($current_nid, $nodes);
$nids['prev'] = ($current_key == 0) ? '' : $nodes[$current_key - 1];
$nids['next'] = ($current_key == count($nodes) - 1) ? '' : $nodes[$current_key + 1];
return $nids;
}