Problem/Motivation

I have configured a content type (Article) to automatically be included on the sitemap.

However, there are a few nodes that I want to exclude from the sitemap programmatically (because I am importing nodes using the Feeds module).

Based on this post, I tried the following code in hook_node_presave():

      $generator = \Drupal::service('simple_sitemap.generator');
      $generator->entityManager()->setEntityInstanceSettings('node', $node->id(), ['index' => false]);

However, when I open the node edit page, the node is still set to be indexed. What more do I need to do to exclude the node from the sitemap?

Comments

ptmkenny created an issue. See original summary.

gbyte’s picture

So what I understand is you are importing nodes programmatically (you are not using the node creation form) and would like to exclude said nodes from the sitemap permanently during the import.

You are on the right track, but I would change three things:

  • You can use hook_enity_insert to make sure the code only runs on node creation.
  • You could try and mark the nodes during the import (by using a node property or a dedictated field) and this way only exclude nodes that are imported. Alternatively: Check if feeds already marks the nodes as 'syncing' by checking for $node->isSyncing() in that update hook.
  • Now for your problem: The issue you linked is old and does not take sitemap variants into account. Try the following:
          $manager = \Drupal::service('simple_sitemap.generator')->entityManager();
          $manager->setVariants()->setEntityInstanceSettings('node', $node->id(), ['index' => false]);
    

    If you want to exclude the node in a particular variant only, do e.g $manager->setVariants(['default']) instead.

ptmkenny’s picture

Status: Active » Fixed

Thanks, that code worked!

I agree that hook_entity_insert() is generally better, but in my case the nodes might get re-imported (and the values updated), so in case the sitemap exclusion value changes, I want to check it every time.

debasish147’s picture

In hook_entity_insert() , above mentioned service is not working, but it is working during hook_entity_update().

ptmkenny’s picture

@Debasish147 hook_entity_insert() runs after the node has been saved, so it's too late to change the properties of the node.

You can use hook_entity_presave() and check node->isNew() to adjust the settings when the node is saved for the first time.

debasish147’s picture

@ptmkenny in hook_entity_presave(), inside node->isNew() condition, node id is not available as node is not save yet, so the above service is throwing error as it is required second parameter as node id.

$manager = \Drupal::service('simple_sitemap.generator')->entityManager();
$manager->setVariants()->setEntityInstanceSettings('node', $node->id(), ['index' => false]);
ptmkenny’s picture

@Debasish147 Oh right, I forgot about that. Sorry, I answered without checking my code :(

Yes, as you say, it doesn't work on the initial node save. But, I wanted to set this on the node insert. So, I did it like this.

Set it in hook_node_presave() while checking for $node->isNew() to avoid a crash.

And then, in hook_node_insert:

  $content_type = $node->getType();
  if ($content_type === 'my_type') {
    // Save it again to ensure it is excluded from the sitemap.
    $node->save();
  }

Forcefully resaving the node is not elegant but it does work.

debasish147’s picture

@ptmkenny Thanks for the code.

gbyte’s picture

Status: Fixed » Closed (fixed)

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

ptmkenny’s picture

Upon more testing, one problem with running this in `hook_entity_presave()` is that it will only resolve successfully when saving the node programmatically.

When using this code:

      $manager = \Drupal::service('simple_sitemap.generator')->entityManager();
      $manager->setVariants()->setEntityInstanceSettings('node', $node->id(), ['index' => false]);

If you save the node through the Drupal admin UI, the sitemap settings will not be changed, and whatever was set when the node was saved in the UI will be set.

gbyte’s picture

@ptmkenny Yes, the only way to do it on entity form save is to add a form submit handler via hook_form_alter and make sure it runs after simple_sitemap's form submit handler.

pshetty9005’s picture

Did anyone get this working for nodes created through the UI?

phjou’s picture

Go the same issue as #11, I had to use a form alter to achieve it.

In my case I had a field_enable_redirect and wanted to disable the sitemap when it was set to true, but you can change to use whatever custom behavior you need.

function mymodule_form_alter(&$form, FormStateInterface $form_state, $form_id) {
    if ($form_state->getFormObject() instanceof EntityFormInterface) {
        $entity = $form_state->getFormObject()->getEntity();

        if ($entity instanceof ContentEntityInterface && !$entity->isNew() && $entity->hasField('field_enable_redirect')) {
            $form['actions']['submit']['#validate'][] = '::validateForm';
            $form['actions']['submit']['#validate'][] = 'mymodule_redirect_form_validate';
        }
    }
}

function mymodule_redirect_form_validate(&$form, FormStateInterface $form_state) {
    $entity = $form_state->getFormObject()->getEntity();

    if ($entity instanceof ContentEntityInterface && !$entity->isNew() && $entity->hasField('field_enable_redirect')) {
        $field_enable_redirect = $form_state->getValue('field_enable_redirect');

        // Change the value of the sitemap index setting when there is a
        // redirect.
        if ($field_enable_redirect['value'] == 1) {
            $sitemap_index = $form_state->getValue('simple_sitemap');
            $sitemap_index['default']['index'] = 0;
            $form_state->setValue('simple_sitemap', $sitemap_index);
        }
    }
}

julienvey’s picture

The issue described in #11 is due to the module simple_sitemap overwritting the variant with the value of the form_state. Basically the node gets excluded in your hook_entity_presave() and then gets included again in the EntityFormHandler.php of the module.

#14 does the trick, but it means your node will be excluded two times : one in the EntityFormHandler.php and one in your hook_entity_presave().

One solution is to unset the value :)
The function of @phjou then becomes :

/**
 * Exclude from sitemap when there is a redirection.
 */
function mymodule_redirect_form_validate(&$form, FormStateInterface $form_state) {
    $entity = $form_state->getFormObject()->getEntity();

    if ($entity instanceof ContentEntityInterface && !$entity->isNew() && $entity->hasField('field_enable_redirect')) {
        // Exclusion will be processed in precreate function.
        // Clear the value so that it does not get overwritten by simple_sitemap module.
        if ($form_state->getValue('field_enable_redirect')['value']) {
            $form_state->unsetValue('field_enable_redirect')
        }
    }
}