Problem/Motivation
If you have the content moderation state filter in an OR group, then it adds a bundle condition to that group which bypasses the moderation state filter itself.
- Enable content moderation, workflows, and views UI.
- Enable the workflow for at least one content type at
/admin/config/workflow/workflows/manage/editorial
. - Edit the moderated content view at
/admin/structure/views/view/moderated_content
. - Set up the conditions so that it matches the following example structure:
- Default group is an And group with Content revision: Is Latest Translation Affected Revision.
- Group 2 is an Or group with Content revision: Moderation state <> Published and (Get the actual content from a content revision.) Content: Changed > -1 day.
- The logical operator between the Default group and Group 2 is And.
- Preview the query.
You end up with something like the following where clause:
WHERE
((node_field_revision2.nid IS NULL) AND (node_field_revision.revision_translation_affected = '1')) AND
((node.type IN ('article', 'page')) OR
((content_moderation_state.workflow = 'editorial') AND (content_moderation_state.moderation_state <> 'published')) OR
((node_field_data_node_field_revision.changed > 1581335239-86400)))
Rather than showing content that is an article and page and is in the correct moderation state, it will show me content that is either an article/page or is not in the published state. I think that's because the bundle condition is added directly to the group:
$this->query->addWhere($this->options['group'], "$entity_base_table_alias.{$entity_type->getKey('bundle')}", $moderated_bundles, 'IN');
Which contrasts to how the workflow and state IDs are handled further down:
// The values are strings composed from the workflow ID and the state ID, so
// we need to create a complex WHERE condition.
$field = new Condition('OR');
foreach ((array) $this->value as $value) {
list($workflow_id, $state_id) = explode('-', $value, 2);
$and = new Condition('AND');
$and
->condition("$this->tableAlias.workflow", $workflow_id, '=')
->condition("$this->tableAlias.$this->realField", $state_id, $operator);
$field->condition($and);
}
$this->query->addWhere($this->options['group'], $field);
Proposed resolution
Ensure an AND is used between the bundle condition and the workflow/state conditions (rather than just inheriting the current group's).
Remaining tasks
- Review the patch
Comment | File | Size | Author |
---|---|---|---|
#19 | 3112433-19-9.1.patch | 11.62 KB | AndyF |
#19 | interdiff_4-19.txt | 845 bytes | AndyF |
#4 | 3112433-2.png | 14.54 KB | AndyF |
#4 | interdiff_2-4.patch | 9.24 KB | AndyF |
#4 | 3112433-4.patch | 11.57 KB | AndyF |
Comments
Comment #2
AndyF CreditAttribution: AndyF at Fabb commentedAttached a small patch that groups all the content moderation state filter conditions together with explicit conjunctions, no tests yet.
Comment #3
AndyF CreditAttribution: AndyF at Fabb commentedComment #4
AndyF CreditAttribution: AndyF at Fabb commentedHere's a test - I've duplicated the test view
test_content_moderation_state_filter_base_table
and put the two moderation state filters each into an OR filter group (ie each group has only one filter, so the OR logic shouldn't actually change the behaviour).I'm not sure if it's worth also doing the same with a revisions table view?
Comment #6
AndyF CreditAttribution: AndyF at Fabb commentedOops, I gave the interdiff a
.patch
extension so testbot dutifully ran and failed that - the actual patches passed and failed as expected.Comment #7
Baysaa CreditAttribution: Baysaa as a volunteer and at Fabb commentedTested the patch against latest 8.9.x, applies cleanly. Looks good to me +1.
The moderated content view's SQL query before patch:
and after patch:
The `node.type IN` clause which had an OR operator now has an AND operator.
Comment #9
Sam152 CreditAttribution: Sam152 as a volunteer and at PreviousNext commentedWow, really nice analysis and patch. The explanation and reasoning for this, as well as the tests all look great. I would have perhaps just gone the verbose route of adding a new test method and copied the relevant parts from
testStateFilterViewsRelationship
, but the complexity added by the singleforeach
seems okay to me as well.Patch still applies to 9.1.x.
Comment #10
SpadXIII CreditAttribution: SpadXIII at SIM commentedCan confirm this patch fixes the issue. It even works when nesting the filter in a group with an OR-operator.
The whole part of this filter (bundle + workflow + moderation_state) is wrapped within braces.
This was the issue that threw off my query; all nodes were found because they were matched on content type (bundle-part of this filter), effectively ignoring the rest of the filters in the filter-group.
+1 for a merge (patch also still applies to 8.9)
Comment #12
catchCommitted/pushed to 9.1.x and cherry-picked back to 8.9.x, thanks!
Comment #17
catchLooks like this caused https://www.drupal.org/pift-ci-job/1787683, rolling back.
Think it might be missing a use statement in the 9.1.x patch that was previously there when the test passed.
Comment #19
AndyF CreditAttribution: AndyF at Fabb for FRUITION commentedThanks @catch! I think it got caught in the wake of #3130655: Deprecate creating an instance of the class Drupal\Core\Database\Query\Condition with the new keyword, here's an updated patch for 9.1, I think the old patch should be fine for < 9.1?
Comment #20
Baysaa CreditAttribution: Baysaa at Fabb for Gizra commentedThe change in #19 makes good sense and lgtm. RTBC +1
Comment #23
catchOK let's try that again.