Problem/Motivation

In Drupal 8.6, we want to make taxonomy terms usable with the Workspace module, which means they need to be revisionable and publishable. This issue has been split from #2880149: Convert taxonomy terms to be revisionable, and it handles only the publishable part.

Proposed resolution

Add a status field to taxonomy terms.

Remaining tasks

Review.

User interface changes

No UI changes yet, they will be handled in #2899923: UI for publishing/unpublishing taxonomy terms.

API changes

Nope.

Data model changes

Taxonomy terms will have a publishing status field.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

amateescu created an issue. See original summary.

amateescu’s picture

Status: Active » Needs review
FileSize
26.64 KB

Extracted the relevant parts from #2880149-170: Convert taxonomy terms to be revisionable into a separate patch.

amateescu’s picture

Forgot to change the number of the update function :)

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

I can't find any issues, looks good to me.

Should we also port all of the credit from #2880149: Convert taxonomy terms to be revisionable to this issue?

amateescu’s picture

Yes, we should definitely do that.

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Needs review

This looks good, I like how the update was considering the content translation scenario and views. On the other hand terms could appear in different ways in views, eg. as a relationship. What would happen to those?

Similar question: does this affect entity reference fields, do those have settings to allow unpublished/published or how does the handling of access happen there?

Also not RTBC yet given the lack of credit carryover.

amateescu’s picture

On the other hand terms could appear in different ways in views, eg. as a relationship. What would happen to those?

I don't think we can do anything for terms that come through a relationship. I've just tried this scenario using a taxonomy term view with a relationship to nodes based on the 'field_tags' field, and unpublished nodes do appear in the results by default. The fact that we don't have a unified query access API for entities is a known problem for many years, and there's an issue in the Entity API contrib module which tries to tackle this: #2909970: Implement a query-level entity access API

Similar question: does this affect entity reference fields, do those have settings to allow unpublished/published or how does the handling of access happen there?

That's an excellent point! Updated \Drupal\taxonomy\Plugin\EntityReferenceSelection\TermSelection to handle publishable terms and added test coverage for it.

Status: Needs review » Needs work

The last submitted patch, 7: 2981887-7.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Needs review
FileSize
35.28 KB

Rerolled on latest HEAD. The interdiff from #7 is good though.

Status: Needs review » Needs work

The last submitted patch, 9: 2981887-9.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Needs review
FileSize
35.58 KB
920 bytes
joachim’s picture

+++ b/core/modules/taxonomy/taxonomy.post_update.php
@@ -18,3 +21,107 @@ function taxonomy_post_update_clear_views_data_cache() {
+ * Add a 'published' = TRUE filter for all Taxonomy term views and converts
+ * existing ones that were using the 'content_translation_status' field.
+ */

Shouldn't we also convert views that show entities with taxonomy term arguments, so that the argument validation fails if the term is unpublished?

Status: Needs review » Needs work

The last submitted patch, 11: 2981887-11.patch, failed testing. View results

amateescu’s picture

Status: Needs work » Needs review
FileSize
36.82 KB
1.24 KB

@joachim, I looked at all the views argument plugins provided by the node module (in core/modules/node/src/Plugin/views/argument and .../argument_default) and I couldn't find anything related to the publishing status of a node. I guess that means there's nothing special to do for taxonomy terms as well?

amateescu’s picture

However, there is indeed something that we need to do related to the access for viewing taxonomy terms.

Status: Needs review » Needs work

The last submitted patch, 15: 2981887-15.patch, failed testing. View results

joachim’s picture

> @joachim, I looked at all the views argument plugins provided by the node module (in core/modules/node/src/Plugin/views/argument and .../argument_default) and I couldn't find anything related to the publishing status of a node. I guess that means there's nothing special to do for taxonomy terms as well?

I don't really follow... a term argument won't care about node status. But it *should* care about taxonomy status.

Here's how I see it:

Consider the taxonomy_term view that taxonomy module provides OOTB. This shows published nodes that are tagged with a term.

Suppose node N is tagged with term T.

- if I unpublish the node N, then it doesn't appear in the list of nodes for term T
- if I unpublish the term T, then the whole of the page at taxonomy/term/T should go. Because otherwise, it's possible to get to that URL and see the term's name, and the things it's tagged with. Which is pretty much what "seeing the term" means. And unpublishing it should mean you can't see it any more.

amateescu’s picture

Status: Needs work » Needs review
FileSize
39.83 KB
2.55 KB

@joachim, I was looking at node's views argument implementations *as an example*. And if node didn't have any special handling for *the node status field*, the conclusion was that taxonomy terms also don't need any special handling for *taxonomy term status field*.

And the scenario you describe is *exactly* what the patch from #15 provides.

joachim’s picture

+++ b/core/modules/taxonomy/taxonomy.post_update.php
@@ -18,3 +21,107 @@ function taxonomy_post_update_clear_views_data_cache() {
+ * Add a 'published' = TRUE filter for all Taxonomy term views and converts
...
+    // Only alter taxonomy term views.
+    if ($view->get('base_table') !== 'taxonomy_term_field_data') {
+      return FALSE;
+    }

This update is only changing views whose base is terms. So it won't change core's taxonomy_term view, for instance, as the base of that is nodes.

Am I looking at the wrong one?

amateescu’s picture

That's right, the post update function from this patch does not change core's taxonomy_term view. I don't get the question about looking at the wrong one though.

joachim’s picture

> That's right, the post update function from this patch does not change core's taxonomy_term view.

That's what I am trying to say.

> And the scenario you describe is *exactly* what the patch from #15 provides.

And so no, this does not happen.

If term 42 is 'Cats', and I unpublish it, then /taxonomy/term/42 will *still* show a title of 'Cats' and the nodes tagged with 'Cats'.

So, what has unpublishing actually done? The term's title is still visible, and it's still possible to see the relationships. Surely that's a security issue.

amateescu’s picture

And so no, this does not happen.

Yes, it does. I already said that I tested it with the patch applied, have you?

amateescu’s picture

I just looked at views' code and it's the entity argument validator which checks entity access in \Drupal\views\Plugin\views\argument_validator\Entity::validateEntity().

joachim’s picture

Yes, you're right. Sorry for getting all mixed up -- running on insufficient sleep :(

amateescu’s picture

No need to.. I was the same:

+++ b/core/modules/taxonomy/src/TermAccessControlHandler.php
@@ -18,19 +18,37 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
+        return AccessResult::neutral()->setReason("The following permissions are required: 'edit terms in camelids' OR 'administer taxonomy'.");
...
+        return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in camelids' OR 'administer taxonomy'.");

Let's add proper test coverage for all this instead :)

Manuel Garcia’s picture

@amateescu++

Went over the test, I think its pristine, only one nitpick

+++ b/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php
@@ -0,0 +1,124 @@
+    // For some reason, Views emits a 404 status code if the argument does not
+    // validate.

Hummm this sounds like we should open up a bug report and link to it here perhaps (not a blocker for this obviously).

amateescu’s picture

Manuel Garcia’s picture

Thanks @amateescu, even with a patch!

This looks RTBC to me...


+++ b/core/modules/rest/tests/src/Functional/EntityResource/XmlEntityNormalizationQuirksTrait.php
@@ -63,6 +64,9 @@ protected function applyXmlFieldDecodingQuirks(array $normalization) {
+            //   https://www.drupal.org/project/drupal/issues/2936864.

+++ b/core/modules/taxonomy/src/Entity/Term.php
@@ -116,6 +120,12 @@ public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+    //   https://www.drupal.org/project/drupal/issues/2936864.

+++ b/core/modules/taxonomy/tests/src/Functional/TermAccessTest.php
@@ -0,0 +1,124 @@
+    //   https://www.drupal.org/project/drupal/issues/2983070 is fixed.

Nit: do we need these two extra spaces before the links?

amateescu’s picture

@Manuel Garcia, yup, we need them because they're part of the @todo comment, and all the following lines need two extra spaces :)

Manuel Garcia’s picture

Ah of course, thanks @amateescu for clarifying :)

I think this is ready now, anything else left here besides carrying credit from #2880149: Convert taxonomy terms to be revisionable ?

amateescu’s picture

Nope, I think we're done..

timmillwood’s picture

Status: Needs review » Reviewed & tested by the community

I think we're done..

Looks good!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 27: 2981887-27.patch, failed testing. View results

chr.fritsch’s picture

Looks like we need to add @group legacy in the update tests since #2973791: Fix deprecation messages related to deprecated comment Action plugins was committed.

amateescu’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
45.34 KB
529 bytes

Right, let's do that.

jibran’s picture

Can we please also add a change notice for this?

jibran’s picture

Ignore previous comment found https://www.drupal.org/node/2897789

chr.fritsch’s picture

But it looks like we should split the CR as well

amateescu’s picture

Wrote a new CR for this issue (https://www.drupal.org/node/2985366) and updated https://www.drupal.org/node/2897789 to only mention the revisionability part.

jibran’s picture

I have a question: if a term is published and its parent is unpublished would the user(with view access) be able to see the term? If the same user has the edit access and can't view unpublished parent then how would the parent widget look like or allow the user to change the parent?

amateescu’s picture

That's an interesting question :)

Since a term can have multiple parents, some of which could be published and others unpublished, and entity access does not offer any kind of context, I don't think we can restrict view access for individual terms based on the publishing status of its parent(s).

Note that the entity reference selection is able to do this, as can be seen in the patch, because it has the full taxonomy tree as a context to base its logic on.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Wim Leers’s picture

  1. +++ b/core/modules/taxonomy/src/TermAccessControlHandler.php
    @@ -18,19 +18,37 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
    +    if ($account->hasPermission('administer taxonomy')) {
    +      return AccessResult::allowed()->cachePerPermissions();
    +    }
    ...
    -        return AccessResult::allowedIfHasPermissions($account, ["edit terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
    +        if ($account->hasPermission("edit terms in {$entity->bundle()}")) {
    +          return AccessResult::allowed()->cachePerPermissions();
    +        }
    +
    +        return AccessResult::neutral()->setReason("The following permissions are required: 'edit terms in {$entity->bundle()}' OR 'administer taxonomy'.");
     
           case 'delete':
    -        return AccessResult::allowedIfHasPermissions($account, ["delete terms in {$entity->bundle()}", 'administer taxonomy'], 'OR');
    +        if ($account->hasPermission("delete terms in {$entity->bundle()}")) {
    +          return AccessResult::allowed()->cachePerPermissions();
    +        }
    +
    +        return AccessResult::neutral()->setReason("The following permissions are required: 'delete terms in {$entity->bundle()}' OR 'administer taxonomy'.");
    ...
    -        return AccessResult::neutral();
    +        return AccessResult::neutral()->cachePerPermissions();
    

    👍

  2. +++ b/core/modules/taxonomy/src/TermAccessControlHandler.php
    @@ -18,19 +18,37 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
    -        return AccessResult::allowedIfHasPermission($account, 'access content');
    +        $access_result = AccessResult::allowedIf($account->hasPermission('access content') && $entity->isPublished())
    +          ->cachePerPermissions()
    +          ->addCacheableDependency($entity);
    +        if (!$access_result->isAllowed()) {
    +          $access_result->setReason("The 'access content' permission is required and the taxonomy term must be published.");
    +        }
    +        return $access_result;
    

    👍

  3. +++ b/core/modules/taxonomy/tests/fixtures/update/views.view.test_taxonomy_term_view_without_content_translation_status.yml
    --- a/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php
    +++ b/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php
    
    +++ b/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php
    +++ b/core/modules/taxonomy/tests/src/Functional/Rest/TermResourceTestBase.php
    @@ -200,6 +200,11 @@ protected function getExpectedNormalizedEntity() {
    
    @@ -200,6 +200,11 @@ protected function getExpectedNormalizedEntity() {
               'langcode' => 'en',
             ],
           ],
    +      'status' => [
    +        [
    +          'value' => TRUE,
    +        ],
    +      ],
         ];
       }
     
    @@ -237,7 +242,7 @@ protected function getExpectedUnauthorizedAccessMessage($method) {
    
    @@ -237,7 +242,7 @@ protected function getExpectedUnauthorizedAccessMessage($method) {
     
         switch ($method) {
           case 'GET':
    -        return "The 'access content' permission is required.";
    +        return "The 'access content' permission is required and the taxonomy term must be published.";
           case 'POST':
             return "The following permissions are required: 'create terms in camelids' OR 'administer taxonomy'.";
           case 'PATCH':
    @@ -348,4 +353,13 @@ public function providerTestGetTermWithParent() {
    
    @@ -348,4 +353,13 @@ public function providerTestGetTermWithParent() {
         ];
       }
     
    +  /**
    +   * {@inheritdoc}
    +   */
    +  protected function getExpectedUnauthorizedAccessCacheability() {
    +    // @see \Drupal\taxonomy\TermAccessControlHandler::checkAccess()
    +    return parent::getExpectedUnauthorizedAccessCacheability()
    +      ->addCacheTags(['taxonomy_term:1']);
    +  }
    +
     }
    

    I love it when a plan comes together 😀

    I think this may be the first time that updating core REST is now slowing down @amateescu!

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 35: 2981887-35.patch, failed testing. View results

chr.fritsch’s picture

anavarre’s picture

Issue tags: +Needs reroll
amateescu’s picture

Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs reroll
FileSize
45.83 KB

Rerolled.

plach’s picture

Priority: Normal » Major
Status: Reviewed & tested by the community » Needs work

This is looking almost ready to go!

  1. +++ b/core/modules/taxonomy/taxonomy.install
    @@ -126,3 +128,43 @@ function taxonomy_update_8503() {
    +  $entity_keys['published'] = 'status';
    ...
    +  $definition_update_manager->installFieldStorageDefinition('status', 'taxonomy_term', 'taxonomy_term', $status);
    

    I think we should support the case where a status field already exists and skip the update in that case, as we did in system_update_8501(). We'll need also a similar change record.

  2. +++ b/core/modules/taxonomy/tests/src/Functional/Update/TaxonomyTermUpdatePathTest.php
    @@ -0,0 +1,126 @@
    +    $this->assertTrue($term->isPublished());
    

    Can we also add an assertion to check the term can be unpublished as well?

amateescu’s picture

Status: Needs work » Needs review
FileSize
46.42 KB
1.75 KB

Thanks for reviewing! Fixed both points and I'll update the CR tomorrow.

jibran’s picture

Status: Needs review » Reviewed & tested by the community

Latest interdiff looks good to me. #48 is addressed so back to RTBC.

plach credited Berdir.

plach credited Bojhan.

plach credited Fabianx.

plach credited catch.

plach credited dawehner.

plach credited jojototh.

plach credited pameeela.

plach’s picture

Saving credits and crediting people from #2880149: Convert taxonomy terms to be revisionable.

  • plach committed 8081895 on 8.6.x
    Issue #2981887 by amateescu, joachim, jibran, chr.fritsch, Manuel Garcia...

  • plach committed 543b3f4 on 8.7.x
    Issue #2981887 by amateescu, joachim, jibran, chr.fritsch, Manuel Garcia...
plach’s picture

Version: 8.7.x-dev » 8.6.x-dev
Status: Reviewed & tested by the community » Fixed

Since this will allow us to test taxonomy with Workspaces in contrib via the Multiversion module, it's valuable to go ahead and commit this patch even if the parent one does not make it into 8.6.

Pushed 543b3f4 to 8.7.x and backported it as 8081895 to 8.6.x.

Thank you all, see you in #2880149: Convert taxonomy terms to be revisionable!

plach’s picture

Status: Fixed » Needs work

We still need to update the CR with the instructions to write a manual DB update in case of name collisions.

plach’s picture

Issue tags: +8.6.0 release notes
amateescu’s picture

Status: Needs work » Fixed

Updated the CR to add instructions about manual updates in case taxonomy terms already have a status field, and published it.

Thanks, everyone!

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

xjm’s picture

Is there any disruption or important update information that needs to be mentioned in the release notes, or is it just a highlighted feature? If the latter the tag should be "8.6.0 highlights". Otherwiwse, if there is some important update information please document it here on the issue so the information can be included in the final release notes. Thanks!

jibran’s picture

That there is no UI yet and it has been worked on in #2899923: UI for publishing/unpublishing taxonomy terms

amateescu’s picture

I think this can be just a highlight.

SlayJay’s picture

Just FYI for anyone else that comes across this, I did *NOT* have any status fields on my taxonomy terms, but this change broke every entity reference field to terms on my site for non-admins. Took me about 2 weeks to track this down and figure out the cause.

Essentially the status field was created but with null values, basically preventing anyone without admin access from seeing them.

Since there's no UI yet, what I had to do was create a route that would loop through all terms and run ->setPublished() on them. Which was easy and quick (once I understood the issue) for me, but would be really hard for someone who's not a developer.

jedgar1mx’s picture

Should i install #35 if i am running 8.6x?

amateescu’s picture

@jedgar1mx, you don't need to apply this patch manually, it is already included in core since 8.6.0.

jedgar1mx’s picture

Thanks for the clarification amateescu. I did notice that even though the taxonomy is unpublished, the taxonomy term page still accessible. Node have an item in permission View own unpublished content. Shouldn't taxonomy has the same ability to limit access to unpublished terms? Thanks

amateescu’s picture

@jedgar1mx, the taxonomy term page is a view, and this patch automatically updated all views and added a status filter to them. In your case, I would start investigating that view for custom modifications.

jedgar1mx’s picture

Ok, thanks again amateescu

cilefen’s picture