Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions config/install/views.view.summary_contents_filters.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,21 @@ display:
entity_type: node
entity_field: changed
plugin_id: date
name:
id: name
table: taxonomy_term_field_data
field: name
relationship: field_topic
group_type: group
admin_label: ''
entity_type: taxonomy_term
entity_field: name
plugin_id: standard
order: ASC
expose:
label: ''
field_identifier: ''
exposed: false
title: Content
empty:
area_text_custom:
Expand All @@ -1031,6 +1046,15 @@ display:
admin_label: author
required: true
plugin_id: standard
field_topic:
id: field_topic
table: node__field_topic
field: field_topic
relationship: none
group_type: group
admin_label: 'field_topic: Taxonomy term'
plugin_id: standard
required: false
show_admin_links: false
filter_groups:
operator: AND
Expand Down
91 changes: 91 additions & 0 deletions src/Plugin/views/field/SortAwareEntityField.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

namespace Drupal\tide_core\Plugin\views\field;

use Drupal\views\Attribute\ViewsField;
use Drupal\views\Plugin\views\field\EntityField;

/**
* Entity field handler that delegates click sorting to the sort handler.
*
* Drupal core's EntityField::clickSort() implements its own simple sorting
* logic (ORDER BY raw field value) which completely ignores any custom sort
* plugin defined for the same field.
*
* This field handler fixes the issue by checking whether a matching sort
* handler exists in the view. If found, it delegates click sorting to that
* handler's query() method, ensuring table header click sorting respects
* the custom sort logic.
*
* Usage: In hook_views_data_alter(), set the field handler ID to
* 'sort_aware_field' for any entity field that has a custom sort plugin.
*
* @see https://www.drupal.org/project/drupal/issues/3174392
*
* @ingroup views_field_handlers
*/
#[ViewsField("sort_aware_field")]
class SortAwareEntityField extends EntityField {

/**
* {@inheritdoc}
*/
public function clickSort($order) {
foreach ($this->view->sort as $sort_handler) {
if ($this->isSortHandlerMatch($sort_handler)) {
$sort_handler->options['order'] = $order;
$sort_handler->setRelationship();
$sort_handler->query($this->view->display_handler->useGroupBy());
return;
}
}

// No matching sort handler found, fall back to default behavior.
parent::clickSort($order);
}

/**
* Determines whether a sort handler matches this field handler.
*/
protected function isSortHandlerMatch($sort_handler): bool {
// Skip broken handlers.
if (!empty($sort_handler->broken)) {
return FALSE;
}

// 1. Direct match by table and real field name.
if (isset($sort_handler->table) && isset($sort_handler->realField)) {
if ($sort_handler->table === $this->table && $sort_handler->realField === $this->realField) {
return TRUE;
}
}

// 2. Match by entity field_name definition for entity fields which may
// use different table aliases but refer to the same entity field.
if (isset($sort_handler->definition['field_name']) && isset($this->definition['field_name'])) {
if ($sort_handler->definition['field_name'] === $this->definition['field_name']
&& isset($sort_handler->definition['entity_type']) && isset($this->definition['entity_type'])
&& $sort_handler->definition['entity_type'] === $this->definition['entity_type']) {
return TRUE;
}
}

// 3. Relationship match: the sort handler uses a relationship that was
// built from this field. This covers entity reference fields where the
// sort operates on the referenced entity's table (e.g. field_topic
// field on node__field_topic, with a sort on taxonomy_term_field_data
// via a relationship built from field_topic).
if (!empty($sort_handler->options['relationship']) && $sort_handler->options['relationship'] !== 'none') {
$relationship_id = $sort_handler->options['relationship'];
if (isset($this->view->relationship[$relationship_id])) {
$rel_handler = $this->view->relationship[$relationship_id];
if ($rel_handler->table === $this->table && $rel_handler->realField === $this->realField) {
return TRUE;
}
}
}

return FALSE;
}

}
46 changes: 46 additions & 0 deletions tide_core.install
Original file line number Diff line number Diff line change
Expand Up @@ -1280,3 +1280,49 @@ function tide_core_update_10033() {
$config->setData($raw_data);
$config->save();
}

/**
* Add topic sort handler and field_topic relationship to the content view.
*/
function tide_core_update_10034() {
\Drupal::moduleHandler()->loadInclude('tide_core', 'inc', 'includes/helpers');
$config_location = [\Drupal::service('extension.list.module')->getPath('tide_core') . '/config/install'];
$config_read = _tide_read_config('views.view.summary_contents_filters', $config_location, FALSE);

$config = \Drupal::configFactory()->getEditable('views.view.summary_contents_filters');
if ($config->isNew()) {
return;
}

$raw_data = $config->getRawData();
$display_options = &$raw_data['display']['default']['display_options'];

// Add the 'name' sort handler (sort by taxonomy term name via field_topic
// relationship) after the existing 'changed' sort.
if (!isset($display_options['sorts']['name'])) {
$new_sorts = [];
foreach ($display_options['sorts'] as $key => $value) {
$new_sorts[$key] = $value;
if ($key === 'changed') {
$new_sorts['name'] = $config_read['display']['default']['display_options']['sorts']['name'];
}
}
$display_options['sorts'] = $new_sorts;
}

// Add the 'field_topic' relationship (joins to taxonomy_term_field_data)
// after the existing 'uid' relationship.
if (!isset($display_options['relationships']['field_topic'])) {
$new_relationships = [];
foreach ($display_options['relationships'] as $key => $value) {
$new_relationships[$key] = $value;
if ($key === 'uid') {
$new_relationships['field_topic'] = $config_read['display']['default']['display_options']['relationships']['field_topic'];
}
}
$display_options['relationships'] = $new_relationships;
}

$config->setData($raw_data);
$config->save();
}
6 changes: 6 additions & 0 deletions tide_core.module
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,12 @@ function tide_core_views_data_alter(array &$data) {
'id' => 'author_by_role_filter',
],
];
// Use sort-aware field handler for field_topic so that table click sorting
// delegates to the sort handler (which sorts by taxonomy term name via
// relationship) instead of sorting by the raw target_id.
if (isset($data['node__field_topic']['field_topic']['field'])) {
$data['node__field_topic']['field_topic']['field']['id'] = 'sort_aware_field';
}
}

/**
Expand Down