Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
850 / 850 |
|
100.00% |
11 / 11 |
CRAP | n/a |
0 / 0 |
|
visitors_help | |
100.00% |
11 / 11 |
|
100.00% |
1 / 1 |
2 | |||
visitors_cron | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitors_page_attachments | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
visitors_form_user_form_alter | |
100.00% |
29 / 29 |
|
100.00% |
1 / 1 |
5 | |||
visitors_user_profile_form_submit | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
visitors_node_links_alter | |
100.00% |
16 / 16 |
|
100.00% |
1 / 1 |
4 | |||
visitors_entity_delete | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
visitors_ranking | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
3 | |||
visitors_views_data | |
100.00% |
721 / 721 |
|
100.00% |
1 / 1 |
7 | |||
visitors_token_info | |
100.00% |
21 / 21 |
|
100.00% |
1 / 1 |
2 | |||
visitors_tokens | |
100.00% |
20 / 20 |
|
100.00% |
1 / 1 |
12 |
1 | <?php |
2 | |
3 | /** |
4 | * @file |
5 | * Logs visitors for your site. |
6 | */ |
7 | |
8 | use Drupal\Core\Entity\ContentEntityInterface; |
9 | use Drupal\Core\Entity\EntityInterface; |
10 | use Drupal\Core\Form\FormStateInterface; |
11 | use Drupal\Core\Render\BubbleableMetadata; |
12 | use Drupal\node\NodeInterface; |
13 | use Drupal\visitors\VisitorsVisibilityInterface; |
14 | |
15 | /** |
16 | * Implements hook_help(). |
17 | */ |
18 | function visitors_help($route_name, $route_match) { |
19 | switch ($route_name) { |
20 | case 'help.page.visitors': |
21 | $help = '<p><a href="https://git.drupalcode.org/project/visitors/-/commits/8.x-2.x"><img alt="coverage report" src="https://git.drupalcode.org/project/visitors/badges/8.x-2.x/coverage.svg" /></a> '; |
22 | $help .= '<a href="https://git.drupalcode.org/project/visitors/-/commits/8.x-2.x"><img alt="pipeline status" src="https://git.drupalcode.org/project/visitors/badges/8.x-2.x/pipeline.svg" /></a> '; |
23 | $help .= '<a href="https://www.drupal.org/project/visitors">Homepage</a> '; |
24 | $help .= '<a href="https://www.drupal.org/project/issues/visitors?version=any_8.x-">Issues</a></p>'; |
25 | $help .= '<p>' |
26 | . t('The Visitors module logs all visitors to your site and provides various statistics about them.') |
27 | . '</p>'; |
28 | |
29 | return [ |
30 | '#title' => t('Visitors'), |
31 | 'description' => [ |
32 | '#markup' => $help, |
33 | ], |
34 | ]; |
35 | |
36 | } |
37 | } |
38 | |
39 | /** |
40 | * Implements hook_cron(). |
41 | */ |
42 | function visitors_cron(): void { |
43 | \Drupal::service('visitors.cron')->execute(); |
44 | } |
45 | |
46 | /** |
47 | * Implements hook_page_attachments(). |
48 | */ |
49 | function visitors_page_attachments(array &$page) { |
50 | \Drupal::service('visitors.page_attachments')->pageAttachments($page); |
51 | } |
52 | |
53 | /** |
54 | * Implements hook_form_FORM_ID_alter(). |
55 | * |
56 | * Allow users to decide if tracking code will be added to pages or not. |
57 | */ |
58 | function visitors_form_user_form_alter(&$form, FormStateInterface $form_state) { |
59 | |
60 | $config = \Drupal::config('visitors.config'); |
61 | $visibility_users = $config->get('visibility.user_account_mode'); |
62 | |
63 | if ($visibility_users == VisitorsVisibilityInterface::USER_NO_PERSONALIZATION) { |
64 | return; |
65 | } |
66 | |
67 | /** @var \Drupal\user\AccountForm $user_form */ |
68 | $user_form = $form_state->getFormObject(); |
69 | /** @var \Drupal\user\UserInterface $account */ |
70 | $account = $user_form->getEntity(); |
71 | |
72 | if (!$account->hasPermission('opt-out of visitors tracking')) { |
73 | return; |
74 | } |
75 | |
76 | $account_data_visitors = \Drupal::service('user.data')->get('visitors', $account->id()); |
77 | |
78 | $form['visitors'] = [ |
79 | '#type' => 'details', |
80 | '#title' => t('Visitors settings'), |
81 | '#weight' => 3, |
82 | '#open' => TRUE, |
83 | ]; |
84 | $description = ''; |
85 | switch ($visibility_users) { |
86 | case VisitorsVisibilityInterface::USER_OPT_OUT: |
87 | $description = t('Users are tracked by default, but you are able to opt out.'); |
88 | break; |
89 | |
90 | case VisitorsVisibilityInterface::USER_OPT_IN: |
91 | $description = t('Users are <em>not</em> tracked by default, but you are able to opt in.'); |
92 | break; |
93 | } |
94 | |
95 | $default_value = $account_data_visitors['user_account_users'] ?? $visibility_users; |
96 | $form['visitors']['user_account_users'] = [ |
97 | '#type' => 'checkbox', |
98 | '#title' => t('Enable user tracking'), |
99 | '#description' => $description, |
100 | '#default_value' => $default_value, |
101 | ]; |
102 | |
103 | // Custom submit handler. |
104 | $form['actions']['submit']['#submit'][] = 'visitors_user_profile_form_submit'; |
105 | |
106 | } |
107 | |
108 | /** |
109 | * Submit callback for user profile form to save the Visitor setting. |
110 | */ |
111 | function visitors_user_profile_form_submit($form, FormStateInterface $form_state) { |
112 | if (!$form_state->hasValue('user_account_users')) { |
113 | return; |
114 | } |
115 | /** @var \Drupal\user\AccountForm $user_form */ |
116 | $user_form = $form_state->getFormObject(); |
117 | /** @var \Drupal\user\UserInterface $account */ |
118 | $account = $user_form->getEntity(); |
119 | |
120 | $value = (int) $form_state->getValue('user_account_users'); |
121 | \Drupal::service('user.data') |
122 | ->set('visitors', $account->id(), 'user_account_users', $value); |
123 | } |
124 | |
125 | /** |
126 | * Implements hook_node_links_alter(). |
127 | */ |
128 | function visitors_node_links_alter(array &$links, NodeInterface $entity, array &$context) { |
129 | if ($context['view_mode'] == 'rss') { |
130 | return NULL; |
131 | } |
132 | $links['#cache']['contexts'][] = 'user.permissions'; |
133 | if (!\Drupal::currentUser()->hasPermission('view visitors counter')) { |
134 | return NULL; |
135 | } |
136 | $settings = \Drupal::config('visitors.config'); |
137 | |
138 | $statistics = \Drupal::service('visitors.counter')->fetchView('node', $entity->id()); |
139 | if ($statistics) { |
140 | $statistics_links['visitors_counter']['title'] = \Drupal::translation() |
141 | ->formatPlural($statistics->getTotalCount(), '1 view', '@count views'); |
142 | $links['visitors'] = [ |
143 | '#theme' => 'links__node__visitors', |
144 | '#links' => $statistics_links, |
145 | '#attributes' => ['class' => ['links', 'inline']], |
146 | ]; |
147 | } |
148 | $links['#cache']['max-age'] = $settings->get('counter.display_max_age'); |
149 | |
150 | } |
151 | |
152 | /** |
153 | * Implements hook_entity_delete(). |
154 | */ |
155 | function visitors_entity_delete(EntityInterface $entity) { |
156 | |
157 | $entity_id = $entity->id(); |
158 | if (!is_int($entity_id)) { |
159 | return; |
160 | } |
161 | $entity_type = $entity->getEntityTypeId(); |
162 | |
163 | \Drupal::service('visitors.counter') |
164 | ->deleteViews($entity_type, $entity_id); |
165 | } |
166 | |
167 | /** |
168 | * Implements hook_ranking(). |
169 | */ |
170 | function visitors_ranking() { |
171 | $settings = \Drupal::config('visitors.config'); |
172 | $is_enabled_and_has_node_entity_type = $settings->get('counter.enabled') |
173 | && in_array('node', $settings->get('counter.entity_types')); |
174 | if ($is_enabled_and_has_node_entity_type) { |
175 | return [ |
176 | 'views' => [ |
177 | 'title' => t('Number of views'), |
178 | 'join' => [ |
179 | 'type' => 'LEFT', |
180 | 'table' => 'visitors_counter', |
181 | 'alias' => 'visitors_counter', |
182 | 'on' => "visitors_counter.entity_id = i.sid AND visitors_counter.entity_type = 'node'", |
183 | ], |
184 | // Inverse law that maps the highest view count on the site to 1 and 0 |
185 | // to 0. Note that the ROUND here is necessary for PostgreSQL and SQLite |
186 | // in order to ensure that the :statistics_scale argument is treated as |
187 | // a numeric type, because the PostgreSQL PDO driver sometimes puts |
188 | // values in as strings instead of numbers in complex expressions like |
189 | // this. |
190 | 'score' => '2.0 - 2.0 / (1.0 + visitors_counter.total * (ROUND(:statistics_scale, 4)))', |
191 | 'arguments' => [':statistics_scale' => \Drupal::state()->get('visitors.node_counter_scale', 0)], |
192 | ], |
193 | ]; |
194 | } |
195 | } |
196 | |
197 | /** |
198 | * Implements hook_views_data(). |
199 | */ |
200 | function visitors_views_data() { |
201 | $data = []; |
202 | $data['visitors_counter']['table']['group'] = t('Visitor counters'); |
203 | $data['visitors_counter']['table']['base'] = [ |
204 | 'title' => t('Visitor Counters'), |
205 | 'help' => t('Visitors data from visitors DB table.'), |
206 | ]; |
207 | $settings = \Drupal::config('visitors.config'); |
208 | $supported_entity_types = $settings->get('counter.entity_types') ?? []; |
209 | foreach (\Drupal::entityTypeManager()->getDefinitions() as $entity_type_id => $entity_type) { |
210 | $base_table = $entity_type->getBaseTable(); |
211 | if (!in_array($entity_type_id, $supported_entity_types) || !$entity_type->entityClassImplements(ContentEntityInterface::class) || !$base_table) { |
212 | continue; |
213 | } |
214 | |
215 | $base_table = $entity_type->getDataTable() ?: $base_table; |
216 | $args = ['@entity_type' => $entity_type_id]; |
217 | |
218 | // Multilingual properties are stored in data table. |
219 | if (!($table = $entity_type->getDataTable())) { |
220 | $table = $base_table; |
221 | } |
222 | $data[$base_table]['visitors_counter'] = [ |
223 | 'title' => t('Visitors @entity_type counter', $args), |
224 | 'help' => t('Relate all visitor counts on the @entity_type.', $args), |
225 | 'relationship' => [ |
226 | 'group' => t('Visitor Counters'), |
227 | 'label' => t('Visitor counters'), |
228 | 'base' => 'visitors_counter', |
229 | 'base field' => 'entity_id', |
230 | 'relationship field' => $entity_type->getKey('id'), |
231 | 'id' => 'standard', |
232 | 'extra' => [ |
233 | [ |
234 | 'field' => 'entity_type', |
235 | 'value' => $entity_type_id, |
236 | ], |
237 | ], |
238 | ], |
239 | ]; |
240 | |
241 | $data['visitors_counter']['table']['join'][$table] = [ |
242 | 'type' => 'LEFT', |
243 | 'left_field' => $entity_type->getKey('id'), |
244 | 'field' => 'entity_id', |
245 | 'extra' => [ |
246 | [ |
247 | 'field' => 'entity_type', |
248 | 'value' => $entity_type_id, |
249 | ], |
250 | ], |
251 | ]; |
252 | |
253 | } |
254 | |
255 | $data['visitors_counter']['total'] = [ |
256 | 'title' => t('Total views'), |
257 | 'help' => t('The total number of times the node has been viewed.'), |
258 | 'field' => [ |
259 | 'id' => 'visitors_numeric', |
260 | 'click sortable' => TRUE, |
261 | ], |
262 | 'filter' => [ |
263 | 'id' => 'numeric', |
264 | ], |
265 | 'argument' => [ |
266 | 'id' => 'numeric', |
267 | ], |
268 | 'sort' => [ |
269 | 'id' => 'standard', |
270 | ], |
271 | ]; |
272 | $data['visitors_counter']['today'] = [ |
273 | 'title' => t('Views today'), |
274 | 'help' => t('The total number of times the node has been viewed today.'), |
275 | 'field' => [ |
276 | 'id' => 'visitors_numeric', |
277 | 'click sortable' => TRUE, |
278 | ], |
279 | 'filter' => [ |
280 | 'id' => 'numeric', |
281 | ], |
282 | 'argument' => [ |
283 | 'id' => 'numeric', |
284 | ], |
285 | 'sort' => [ |
286 | 'id' => 'standard', |
287 | ], |
288 | ]; |
289 | $data['visitors_counter']['timestamp'] = [ |
290 | 'title' => t('Most recent visit'), |
291 | 'help' => t('The most recent time the node has been viewed.'), |
292 | 'field' => [ |
293 | 'id' => 'visitors_counter_timestamp', |
294 | 'click sortable' => TRUE, |
295 | ], |
296 | 'filter' => [ |
297 | 'id' => 'date', |
298 | ], |
299 | 'argument' => [ |
300 | 'id' => 'date', |
301 | ], |
302 | 'sort' => [ |
303 | 'id' => 'standard', |
304 | ], |
305 | ]; |
306 | |
307 | $data['visitors']['table']['group'] = t('Visitors'); |
308 | $data['visitors']['table']['base'] = [ |
309 | 'title' => t('Visitors'), |
310 | 'help' => t('Visitors data from visitors DB table.'), |
311 | ]; |
312 | |
313 | $data['visitors']['visitors_id'] = [ |
314 | 'title' => t('Visitors ID'), |
315 | 'help' => t('Visitors entry ID.'), |
316 | 'field' => [ |
317 | 'id' => 'numeric', |
318 | ], |
319 | 'sort' => [ |
320 | 'id' => 'standard', |
321 | ], |
322 | 'filter' => [ |
323 | 'id' => 'numeric', |
324 | ], |
325 | 'argument' => [ |
326 | 'id' => 'numeric', |
327 | ], |
328 | ]; |
329 | $data['visitors']['visitor_id'] = [ |
330 | 'title' => t('Unique visitor'), |
331 | 'help' => t('A unique ID for the visitor.'), |
332 | 'field' => [ |
333 | 'id' => 'standard', |
334 | ], |
335 | 'filter' => [ |
336 | 'id' => 'string', |
337 | ], |
338 | 'sort' => [ |
339 | 'id' => 'standard', |
340 | ], |
341 | 'argument' => [ |
342 | 'id' => 'string', |
343 | ], |
344 | ]; |
345 | $data['visitors']['visitors_uid'] = [ |
346 | 'title' => t('Visitors UID'), |
347 | 'help' => t('The user ID of the visitors entry.'), |
348 | 'field' => [ |
349 | 'id' => 'standard', |
350 | ], |
351 | 'relationship' => [ |
352 | 'title' => t('User'), |
353 | 'help' => t('The user entity from the visitor entry.'), |
354 | 'base' => 'users_field_data', |
355 | 'base field' => 'uid', |
356 | 'id' => 'standard', |
357 | ], |
358 | 'filter' => [ |
359 | 'id' => 'numeric', |
360 | ], |
361 | 'argument' => [ |
362 | 'id' => 'numeric', |
363 | ], |
364 | ]; |
365 | $data['visitors']['visitors_date_time'] = [ |
366 | 'title' => t('Visitors Date Time'), |
367 | 'help' => t('The timestamp from the visitors entry.'), |
368 | 'field' => [ |
369 | 'id' => 'date', |
370 | 'click sortable' => TRUE, |
371 | ], |
372 | 'filter' => [ |
373 | 'id' => 'visitors_date', |
374 | ], |
375 | ]; |
376 | $data['visitors']['visitors_hour'] = [ |
377 | 'title' => t('Hour'), |
378 | 'help' => t('The hour (server) of the visit.'), |
379 | 'field' => [ |
380 | 'id' => 'visitors_hour', |
381 | 'field' => 'visitors_date_time', |
382 | ], |
383 | 'sort' => [ |
384 | 'id' => 'visitors_timestamp', |
385 | 'field' => 'visitors_date_time', |
386 | ], |
387 | ]; |
388 | $data['visitors']['visitors_month'] = [ |
389 | 'title' => t('Month'), |
390 | 'help' => t('The month of the visit.'), |
391 | 'field' => [ |
392 | 'id' => 'visitors_month', |
393 | 'field' => 'visitors_date_time', |
394 | ], |
395 | 'sort' => [ |
396 | 'id' => 'visitors_timestamp', |
397 | 'field' => 'visitors_date_time', |
398 | ], |
399 | ]; |
400 | $data['visitors']['visitors_day_of_week'] = [ |
401 | 'title' => t('Day of Week'), |
402 | 'help' => t('The day of week of the visit.'), |
403 | 'field' => [ |
404 | 'id' => 'visitors_day_of_week', |
405 | 'field' => 'visitors_date_time', |
406 | ], |
407 | 'sort' => [ |
408 | 'id' => 'visitors_timestamp', |
409 | 'field' => 'visitors_date_time', |
410 | ], |
411 | ]; |
412 | $data['visitors']['visitors_day_of_month'] = [ |
413 | 'title' => t('Day of Month'), |
414 | 'help' => t('The day of month of the visit.'), |
415 | 'field' => [ |
416 | 'id' => 'visitors_day_of_month', |
417 | 'field' => 'visitors_date_time', |
418 | ], |
419 | 'sort' => [ |
420 | 'id' => 'visitors_timestamp', |
421 | 'field' => 'visitors_date_time', |
422 | ], |
423 | ]; |
424 | $data['visitors']['visitors_day'] = [ |
425 | 'title' => t('Day'), |
426 | 'help' => t('The day of the visit.'), |
427 | 'field' => [ |
428 | 'id' => 'visitors_day', |
429 | 'field' => 'visitors_date_time', |
430 | ], |
431 | 'sort' => [ |
432 | 'id' => 'visitors_timestamp', |
433 | 'field' => 'visitors_date_time', |
434 | ], |
435 | ]; |
436 | $data['visitors']['visitors_week'] = [ |
437 | 'title' => t('Week'), |
438 | 'help' => t('The week of the visit.'), |
439 | 'field' => [ |
440 | 'id' => 'visitors_week', |
441 | 'field' => 'visitors_date_time', |
442 | ], |
443 | 'sort' => [ |
444 | 'id' => 'visitors_timestamp', |
445 | 'field' => 'visitors_date_time', |
446 | ], |
447 | ]; |
448 | $data['visitors']['visitor_localtime'] = [ |
449 | 'title' => t('Visitor Hour'), |
450 | 'help' => t('The hour (client) of the visit.'), |
451 | 'field' => [ |
452 | 'id' => 'visitors_local_hour', |
453 | 'field' => 'visitor_localtime', |
454 | ], |
455 | 'sort' => [ |
456 | 'id' => 'visitors_timestamp', |
457 | 'field' => 'visitors_date_time', |
458 | ], |
459 | ]; |
460 | $data['visitors']['visitors_ip'] = [ |
461 | 'title' => t('Visitors IP'), |
462 | 'help' => t('The IP of the visitors entry.'), |
463 | 'field' => [ |
464 | 'id' => 'standard', |
465 | ], |
466 | 'filter' => [ |
467 | 'id' => 'string', |
468 | ], |
469 | 'argument' => [ |
470 | 'id' => 'string', |
471 | ], |
472 | ]; |
473 | $data['visitors']['server'] = [ |
474 | 'title' => t('Server'), |
475 | 'help' => t('The server that generated the response.'), |
476 | 'field' => [ |
477 | 'id' => 'standard', |
478 | ], |
479 | 'filter' => [ |
480 | 'id' => 'string', |
481 | ], |
482 | 'argument' => [ |
483 | 'id' => 'string', |
484 | ], |
485 | ]; |
486 | $data['visitors']['visitors_url'] = [ |
487 | 'title' => t('Visitors URL'), |
488 | 'help' => t('The URL of the visitors entry.'), |
489 | 'field' => [ |
490 | 'id' => 'standard', |
491 | ], |
492 | 'filter' => [ |
493 | 'id' => 'string', |
494 | ], |
495 | ]; |
496 | $data['visitors']['visitors_referer'] = [ |
497 | 'title' => t('Visitors referer'), |
498 | 'help' => t('The referer of the visitors entry.'), |
499 | 'field' => [ |
500 | 'id' => 'standard', |
501 | ], |
502 | 'filter' => [ |
503 | 'id' => 'string', |
504 | ], |
505 | ]; |
506 | $data['visitors']['visitors_path'] = [ |
507 | 'title' => t('Visitors path'), |
508 | 'help' => t('The path of the visitors entry.'), |
509 | 'field' => [ |
510 | 'id' => 'standard', |
511 | ], |
512 | 'filter' => [ |
513 | 'id' => 'string', |
514 | ], |
515 | 'argument' => [ |
516 | 'id' => 'string', |
517 | ], |
518 | ]; |
519 | $data['visitors']['route'] = [ |
520 | 'title' => t('Route'), |
521 | 'help' => t('The route of the visitors entry.'), |
522 | 'field' => [ |
523 | 'id' => 'standard', |
524 | ], |
525 | 'filter' => [ |
526 | 'id' => 'string', |
527 | ], |
528 | 'argument' => [ |
529 | 'id' => 'string', |
530 | ], |
531 | ]; |
532 | $data['visitors']['visitors_title'] = [ |
533 | 'title' => t('Visitors title'), |
534 | 'help' => t('The title of the visitors entry.'), |
535 | 'field' => [ |
536 | 'id' => 'standard', |
537 | ], |
538 | 'filter' => [ |
539 | 'id' => 'string', |
540 | ], |
541 | ]; |
542 | $data['visitors']['visitors_user_agent'] = [ |
543 | 'title' => t('Visitors user agent'), |
544 | 'help' => t('The user agent of the visitors entry.'), |
545 | 'field' => [ |
546 | 'id' => 'standard', |
547 | ], |
548 | 'filter' => [ |
549 | 'id' => 'string', |
550 | ], |
551 | ]; |
552 | $data['visitors']['config_resolution'] = [ |
553 | 'title' => t('Resolution'), |
554 | 'help' => t("The visitor's screen resolution."), |
555 | 'field' => [ |
556 | 'id' => 'standard', |
557 | ], |
558 | 'filter' => [ |
559 | 'id' => 'string', |
560 | ], |
561 | 'argument' => [ |
562 | 'id' => 'string', |
563 | ], |
564 | ]; |
565 | $data['visitors']['config_pdf'] = [ |
566 | 'title' => t('PDF Plugin'), |
567 | 'help' => t("The visitor's browser supports PDFs."), |
568 | 'field' => [ |
569 | 'id' => 'visitors_pdf', |
570 | ], |
571 | 'filter' => [ |
572 | 'id' => 'boolean', |
573 | ], |
574 | ]; |
575 | $data['visitors']['config_flash'] = [ |
576 | 'title' => t('Flash Plugin'), |
577 | 'help' => t("The visitor's browser supports Flash."), |
578 | 'field' => [ |
579 | 'id' => 'visitors_flash', |
580 | ], |
581 | 'filter' => [ |
582 | 'id' => 'boolean', |
583 | ], |
584 | ]; |
585 | $data['visitors']['config_java'] = [ |
586 | 'title' => t('Java Plugin'), |
587 | 'help' => t("The visitor's browser supports Java."), |
588 | 'field' => [ |
589 | 'id' => 'visitors_java', |
590 | ], |
591 | 'filter' => [ |
592 | 'id' => 'boolean', |
593 | ], |
594 | ]; |
595 | $data['visitors']['config_quicktime'] = [ |
596 | 'title' => t('Quicktime Plugin'), |
597 | 'help' => t("The visitor's browser supports Quicktime."), |
598 | 'field' => [ |
599 | 'id' => 'visitors_quicktime', |
600 | ], |
601 | 'filter' => [ |
602 | 'id' => 'boolean', |
603 | ], |
604 | ]; |
605 | $data['visitors']['config_realplayer'] = [ |
606 | 'title' => t('Realplayer Plugin'), |
607 | 'help' => t("The visitor's browser supports Realplayer."), |
608 | 'field' => [ |
609 | 'id' => 'visitors_realplayer', |
610 | ], |
611 | 'filter' => [ |
612 | 'id' => 'boolean', |
613 | ], |
614 | ]; |
615 | $data['visitors']['config_windowsmedia'] = [ |
616 | 'title' => t('Windows Media Plugin'), |
617 | 'help' => t("The visitor's browser supports Windows Media."), |
618 | 'field' => [ |
619 | 'id' => 'visitors_windowsmedia', |
620 | ], |
621 | 'filter' => [ |
622 | 'id' => 'boolean', |
623 | ], |
624 | ]; |
625 | $data['visitors']['config_silverlight'] = [ |
626 | 'title' => t('Silverlight Plugin'), |
627 | 'help' => t("The visitor's browser supports Silverlight."), |
628 | 'field' => [ |
629 | 'id' => 'visitors_silverlight', |
630 | ], |
631 | 'filter' => [ |
632 | 'id' => 'boolean', |
633 | ], |
634 | ]; |
635 | $data['visitors']['config_cookie'] = [ |
636 | 'title' => t('Cookie Plugin'), |
637 | 'help' => t("The visitor's browser supports cookies."), |
638 | 'field' => [ |
639 | 'id' => 'visitors_cookie', |
640 | ], |
641 | 'filter' => [ |
642 | 'id' => 'boolean', |
643 | ], |
644 | ]; |
645 | $data['visitors']['config_browser_engine'] = [ |
646 | 'title' => t('Browser Engine'), |
647 | 'help' => t('The engine used by the browser.'), |
648 | 'field' => [ |
649 | 'id' => 'standard', |
650 | ], |
651 | 'filter' => [ |
652 | 'id' => 'string', |
653 | ], |
654 | 'argument' => [ |
655 | 'id' => 'string', |
656 | ], |
657 | ]; |
658 | $data['visitors']['config_browser_name'] = [ |
659 | 'title' => t('Browser Name'), |
660 | 'help' => t('The name of the browser.'), |
661 | 'field' => [ |
662 | 'id' => 'visitors_browser', |
663 | ], |
664 | 'filter' => [ |
665 | 'id' => 'string', |
666 | ], |
667 | 'argument' => [ |
668 | 'id' => 'string', |
669 | ], |
670 | ]; |
671 | $data['visitors']['config_browser_version'] = [ |
672 | 'title' => t('Browser Version'), |
673 | 'help' => t('The version of the browser.'), |
674 | 'field' => [ |
675 | 'id' => 'standard', |
676 | ], |
677 | 'filter' => [ |
678 | 'id' => 'string', |
679 | ], |
680 | 'argument' => [ |
681 | 'id' => 'string', |
682 | ], |
683 | ]; |
684 | $data['visitors']['config_client_type'] = [ |
685 | 'title' => t('Client type'), |
686 | 'help' => t('The type of the client.'), |
687 | 'field' => [ |
688 | 'id' => 'standard', |
689 | ], |
690 | 'filter' => [ |
691 | 'id' => 'string', |
692 | ], |
693 | 'argument' => [ |
694 | 'id' => 'string', |
695 | ], |
696 | ]; |
697 | $data['visitors']['config_device_brand'] = [ |
698 | 'title' => t('Device brand'), |
699 | 'help' => t('The brand of the device.'), |
700 | 'field' => [ |
701 | 'id' => 'visitors_brand', |
702 | ], |
703 | 'filter' => [ |
704 | 'id' => 'string', |
705 | ], |
706 | 'argument' => [ |
707 | 'id' => 'string', |
708 | ], |
709 | ]; |
710 | $data['visitors']['config_device_model'] = [ |
711 | 'title' => t('Device model'), |
712 | 'help' => t('The model of the device.'), |
713 | 'field' => [ |
714 | 'id' => 'standard', |
715 | ], |
716 | 'filter' => [ |
717 | 'id' => 'string', |
718 | ], |
719 | 'argument' => [ |
720 | 'id' => 'string', |
721 | ], |
722 | ]; |
723 | $data['visitors']['config_device_type'] = [ |
724 | 'title' => t('Device type'), |
725 | 'help' => t('The type of device.'), |
726 | 'field' => [ |
727 | 'id' => 'visitors_device', |
728 | ], |
729 | 'filter' => [ |
730 | 'id' => 'string', |
731 | ], |
732 | 'argument' => [ |
733 | 'id' => 'string', |
734 | ], |
735 | ]; |
736 | $data['visitors']['config_os'] = [ |
737 | 'title' => t('Operating System'), |
738 | 'help' => t('The operating system.'), |
739 | 'field' => [ |
740 | 'id' => 'visitors_operating_system', |
741 | ], |
742 | 'filter' => [ |
743 | 'id' => 'string', |
744 | ], |
745 | 'argument' => [ |
746 | 'id' => 'string', |
747 | ], |
748 | ]; |
749 | $data['visitors']['config_os_version'] = [ |
750 | 'title' => t('OS version'), |
751 | 'help' => t('The version of the Operating System.'), |
752 | 'field' => [ |
753 | 'id' => 'standard', |
754 | ], |
755 | 'filter' => [ |
756 | 'id' => 'string', |
757 | ], |
758 | 'argument' => [ |
759 | 'id' => 'string', |
760 | ], |
761 | ]; |
762 | $data['visitors']['bot'] = [ |
763 | 'title' => t('Bot'), |
764 | 'help' => t("The visit is from a bot."), |
765 | 'field' => [ |
766 | 'id' => 'boolean', |
767 | ], |
768 | 'filter' => [ |
769 | 'id' => 'boolean', |
770 | ], |
771 | 'argument' => [ |
772 | 'id' => 'numeric', |
773 | ], |
774 | ]; |
775 | $data['visitors']['language'] = [ |
776 | 'title' => t('Language'), |
777 | 'help' => t('The browser language.'), |
778 | 'field' => [ |
779 | 'id' => 'visitors_language', |
780 | ], |
781 | 'filter' => [ |
782 | 'id' => 'string', |
783 | ], |
784 | 'argument' => [ |
785 | 'id' => 'string', |
786 | ], |
787 | ]; |
788 | $data['visitors']['location_continent'] = [ |
789 | 'title' => t('Continent'), |
790 | 'help' => t('The location continent.'), |
791 | 'field' => [ |
792 | 'id' => 'visitors_continent', |
793 | ], |
794 | 'filter' => [ |
795 | 'id' => 'string', |
796 | ], |
797 | 'argument' => [ |
798 | 'id' => 'string', |
799 | ], |
800 | ]; |
801 | $data['visitors']['location_country'] = [ |
802 | 'title' => t('Country'), |
803 | 'help' => t('The location country.'), |
804 | 'field' => [ |
805 | 'id' => 'visitors_country', |
806 | ], |
807 | 'filter' => [ |
808 | 'id' => 'string', |
809 | ], |
810 | 'argument' => [ |
811 | 'id' => 'string', |
812 | ], |
813 | ]; |
814 | |
815 | $data['visitors']['pf_network'] = [ |
816 | 'title' => t('Network'), |
817 | 'help' => t('Network performance.'), |
818 | 'field' => [ |
819 | 'id' => 'numeric', |
820 | ], |
821 | 'sort' => [ |
822 | 'id' => 'standard', |
823 | ], |
824 | 'filter' => [ |
825 | 'id' => 'numeric', |
826 | ], |
827 | 'argument' => [ |
828 | 'id' => 'numeric', |
829 | ], |
830 | ]; |
831 | $data['visitors']['pf_server'] = [ |
832 | 'title' => t('Server'), |
833 | 'help' => t('Server performance.'), |
834 | 'field' => [ |
835 | 'id' => 'numeric', |
836 | ], |
837 | 'sort' => [ |
838 | 'id' => 'standard', |
839 | ], |
840 | 'filter' => [ |
841 | 'id' => 'numeric', |
842 | ], |
843 | 'argument' => [ |
844 | 'id' => 'numeric', |
845 | ], |
846 | ]; |
847 | $data['visitors']['pf_transfer'] = [ |
848 | 'title' => t('Transfer'), |
849 | 'help' => t('Transfer performance.'), |
850 | 'field' => [ |
851 | 'id' => 'numeric', |
852 | ], |
853 | 'sort' => [ |
854 | 'id' => 'standard', |
855 | ], |
856 | 'filter' => [ |
857 | 'id' => 'numeric', |
858 | ], |
859 | 'argument' => [ |
860 | 'id' => 'numeric', |
861 | ], |
862 | ]; |
863 | $data['visitors']['pf_dom_processing'] = [ |
864 | 'title' => t('DOM Processing'), |
865 | 'help' => t('DOM Processing performance.'), |
866 | 'field' => [ |
867 | 'id' => 'numeric', |
868 | ], |
869 | 'sort' => [ |
870 | 'id' => 'standard', |
871 | ], |
872 | 'filter' => [ |
873 | 'id' => 'numeric', |
874 | ], |
875 | 'argument' => [ |
876 | 'id' => 'numeric', |
877 | ], |
878 | ]; |
879 | $data['visitors']['pf_dom_complete'] = [ |
880 | 'title' => t('DOM Complete'), |
881 | 'help' => t('DOM Complete performance.'), |
882 | 'field' => [ |
883 | 'id' => 'numeric', |
884 | ], |
885 | 'sort' => [ |
886 | 'id' => 'standard', |
887 | ], |
888 | 'filter' => [ |
889 | 'id' => 'numeric', |
890 | ], |
891 | 'argument' => [ |
892 | 'id' => 'numeric', |
893 | ], |
894 | ]; |
895 | $data['visitors']['pf_on_load'] = [ |
896 | 'title' => t('On Load'), |
897 | 'help' => t('On Load performance.'), |
898 | 'field' => [ |
899 | 'id' => 'numeric', |
900 | ], |
901 | 'sort' => [ |
902 | 'id' => 'standard', |
903 | ], |
904 | 'filter' => [ |
905 | 'id' => 'numeric', |
906 | ], |
907 | 'argument' => [ |
908 | 'id' => 'numeric', |
909 | ], |
910 | ]; |
911 | $data['visitors']['pf_total'] = [ |
912 | 'title' => t('Total'), |
913 | 'help' => t('Total performance.'), |
914 | 'field' => [ |
915 | 'id' => 'numeric', |
916 | ], |
917 | 'sort' => [ |
918 | 'id' => 'standard', |
919 | ], |
920 | 'filter' => [ |
921 | 'id' => 'numeric', |
922 | ], |
923 | 'argument' => [ |
924 | 'id' => 'numeric', |
925 | ], |
926 | ]; |
927 | |
928 | $data['visitors']['visitors_display_link'] = [ |
929 | 'title' => t('Link to Visitors display'), |
930 | 'help' => t('Displays a link to a non-path-based display of this view while keeping the filter criteria, sort criteria, pager settings and contextual filters.'), |
931 | 'area' => [ |
932 | 'id' => 'visitors_display_link', |
933 | ], |
934 | ]; |
935 | |
936 | return $data; |
937 | } |
938 | |
939 | /** |
940 | * Implements hook_token_info(). |
941 | */ |
942 | function visitors_token_info() { |
943 | $entity['total-count'] = [ |
944 | 'name' => t("Number of views"), |
945 | 'description' => t("The number of visitors who have read the node."), |
946 | ]; |
947 | $entity['day-count'] = [ |
948 | 'name' => t("Views today"), |
949 | 'description' => t("The number of visitors who have read the node today."), |
950 | ]; |
951 | $entity['last-view'] = [ |
952 | 'name' => t("Last view"), |
953 | 'description' => t("The date on which a visitor last read the node."), |
954 | 'type' => 'date', |
955 | ]; |
956 | |
957 | $token = [ |
958 | 'tokens' => [], |
959 | ]; |
960 | $entity_types = \Drupal::config('visitors.config') |
961 | ->get('counter.entity_types') ?? []; |
962 | foreach ($entity_types as $entity_type) { |
963 | $token['tokens'][$entity_type] = $entity; |
964 | } |
965 | |
966 | return $token; |
967 | } |
968 | |
969 | /** |
970 | * Implements hook_tokens(). |
971 | */ |
972 | function visitors_tokens($type, $tokens, array $data, array $options, BubbleableMetadata $bubbleable_metadata) { |
973 | $token_service = \Drupal::token(); |
974 | $entity_types = \Drupal::config('visitors.config') |
975 | ->get('counter.entity_types') ?? []; |
976 | $replacements = []; |
977 | |
978 | if (!in_array($type, $entity_types) || empty($data[$type])) { |
979 | return $replacements; |
980 | } |
981 | $entity = $data[$type]; |
982 | |
983 | /** @var \Drupal\visitors\VisitorsCounterInterface $counter_storage */ |
984 | $counter_storage = \Drupal::service('visitors.counter'); |
985 | |
986 | $entity_id = $entity->id() ?? 0; |
987 | $entity_view = $counter_storage->fetchView($type, $entity_id); |
988 | foreach ($tokens as $name => $original) { |
989 | if ($name == 'total-count') { |
990 | $replacements[$original] = $entity_view ? $entity_view->getTotalCount() : 0; |
991 | } |
992 | elseif ($name == 'day-count') { |
993 | $replacements[$original] = $entity_view ? $entity_view->getDayCount() : 0; |
994 | } |
995 | elseif ($name == 'last-view') { |
996 | $replacements[$original] = $entity_view ? \Drupal::service('date.formatter')->format($entity_view->getTimestamp()) : t('never'); |
997 | } |
998 | } |
999 | |
1000 | if ($created_tokens = $token_service->findWithPrefix($tokens, 'last-view')) { |
1001 | $replacements += $token_service->generate('date', $created_tokens, ['date' => $entity_view ? $entity_view->getTimestamp() : 0], $options, $bubbleable_metadata); |
1002 | } |
1003 | |
1004 | return $replacements; |
1005 | } |