2

In short:

Utilizing Drupal 8, I'm hoping to to "hook" into an entity update event for a specific content type so that I can then take further action when that event occurs. In this case, delete the node if it's unpublished.

In long:

The Scheduler module allows scheduling of nodes to publish and unpublish as scheduled. My goal is to then delete a specific-type node when it gets unpublished.

At first I tried to use the Rules module to trigger removal of the unpublished node. However, Rules is not working properly on my website currently (getting errors when attempting to configure unpublish event node type). It spurs interest to see how I can accomplish the same task with a small custom module. I'm moving forward with a goal to understand Drupal 8 modules and module development better.

As a result, I wish to move handling of unpublish events for my content type into module code. Other examples I'm finding relate to Drupal 7. I'm building a Drupal 8 module.

Here is my starting module code so far (rough, draft, untested as I work out logistics).

Module structure:

hour_helper
  hour_helper.info.yml
  hour_helper.services.yml
  src
    EventSubscriber
      HourUnpublishEventSubscriber.php

hour_helper.info.yml:

name: Hours of Operation Helper
type: module
description: 'Utilities to assist with hours of operation, starting with the removal of hour content once it is unpublished via the scheduler module.'
package: Custom
core: 8.x

hour_helper.services.yml:

services:
  hour_helper.node_subscriber:
    class: Drupal\hour_helper\EventSubscriber
    arguments: ['@entity.manager']
    tags:
      - { name: event_subscriber }

HourUnpublishEventSubscriber.php:

<?php

/**
 * @file
 * Event subscriber
 */

namespace Drupal\hour_helper\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

//!!! use (... something entity or node related, we want to subscribe to entity updates?)

/**
 * Remove hour of opperation nodes after/when they are scheduled to unsubscribe to prevent garbage accumulation
 */
class HourUnpublishSubscriber implements EventSubscriberInterface  {
  /**
   * {@inheritdoc}
   */
  public function getSubscribedEvents() {

    // Subscribe to node update events with priority 0.
    //!!! which event....
    $events[SomethingEvents::SOMETHING][] = array('checkForRemoveStatus');
    return $events;
  }

  /**
   * This method is called whenever the ????? event is dispatched.
   *
   * @param GetResponseEvent $event
   */
  public function checkForRemoveStatus(GetResponseEvent $event) {

    //print '<pre>';
    //print_r($event);
    //print '</pre>';


    die('Well, at least an event has been triggered to be handled here...');

  }

}

I continue to ponder the Drupal events doc page...

2
  • 1
    The entity API in drupal 8 still uses hooks. Look up hook_entity_save
    – Eyal
    Jun 10, 2016 at 6:13
  • 1
    P.S. the entity manager service is deprecated and should not be used.
    – Eyal
    Jun 10, 2016 at 6:14

3 Answers 3

1

Based on this: My goal is to then delete a specific-type node when it gets unpublished.

You can use hook_ENTITY_TYPE_update.

You will have to just check, if the (not the original) entity is unpublished, and the it's type is the one you are looking for.

+1: From OO perspective you can also take a look on events.

1
  • This one came in first and I'll happily accept as the answer. I was under the impression that everything was "event based and not hook based" going into this module project, but it looks like hooks are still a thing. Thanks! Jun 10, 2016 at 15:05
0

This is quite easy to do with Rules in Drupal 8, which is what you originally asked ... It took me less than a minute to write and test the Rule below.

Rules actually automatically generates events for all Entity CRUD operations (for all entities of any type, even custom ones) and allows you to react on those events in order to conditionally perform actions. If you want to enable Rules just to make these events available so you can react to them with custom code you can do that. But it far more convenient to use Rules for the entire task, because Rules allows you to easily prototype and modify the operation both initially and in the future when you decide you want to change some detail of your task. Just as Views makes it easier to compose and display the results of a complex DB query without having to know a lot about the implementation details, Rules allows you to add and customize workflow.

Here's a complete example that accomplishes what you asked for. I chose to use the content type "Basic page" as that is pre-installed with Drupal so the Rule below will work on any site. Just change that to be the specific type (or types, even) that you're interested in. This example will DELETE any basic page that was updated if (and only if) that update changed the status of the page from published to unpublished. It also displays a message informing the user of what happened.

As I said, you can modify this, add additional conditions, add additional actions, alter the type that triggers the Rule, etc. to suit your needs.

langcode: en
status: true
dependencies: {  }
id: delete_content_of_type_basic_page_when_it_it_unpublished
label: 'Delete content of type "Basic page" when it it unpublished'
events:
  -
    event_name: 'rules_entity_update:node--page'
description: 'For https://drupal.stackexchange.com/questions/203680/how-do-i-make-a-custom-module-trigger-a-function-when-content-is-unpublished?rq=1'
tags: {  }
weight: 0
config_version: '3'
expression:
  id: rules_rule
  uuid: 4d5f5940-5d74-4402-9391-b2d0261f0194
  weight: 0
  conditions:
    id: rules_and
    uuid: 5c39832c-eed4-4ec7-b5c7-36f29879e22b
    weight: 0
    conditions:
      -
        id: rules_condition
        uuid: 7152f83f-5481-41bf-8f20-c8f3f0d89c48
        weight: 0
        context_values: {  }
        context_mapping:
          node: node_unchanged
        context_processors: {  }
        provides_mapping: {  }
        condition_id: rules_node_is_published
        negate: false
      -
        id: rules_condition
        uuid: 1694c6b6-96f7-4eb6-9026-3e7140bb2be9
        weight: 0
        context_values: {  }
        context_mapping:
          node: node
        context_processors: {  }
        provides_mapping: {  }
        condition_id: rules_node_is_published
        negate: true
  actions:
    id: rules_action_set
    uuid: d9e46518-c5e6-4839-8de8-3175b184a6fd
    weight: 0
    actions:
      -
        id: rules_action
        uuid: 8afb621c-3518-44bd-8a31-e1c2f7b0bc5b
        weight: 0
        context_values: {  }
        context_mapping:
          entity: node
        context_processors: {  }
        provides_mapping: {  }
        action_id: rules_entity_delete
      -
        id: rules_action
        uuid: 1f554fa6-2a44-4d03-985d-f87412cd0843
        weight: 0
        context_values:
          message: 'The basic page "{{ node.title }}" was deleted'
          type: status
          repeat: true
        context_mapping: {  }
        context_processors:
          message:
            rules_tokens: {  }
          type:
            rules_tokens: {  }
          repeat:
            rules_tokens: {  }
        provides_mapping: {  }
        action_id: rules_system_message
-1

If it is your own ContentEntity, hook on the ::save() method of your ContentEntityForm descendant (you may also \Drupal::service('event_dispatcher')->dispatch(... something ...) here. This would be OO.

If you can not do this, go for the hook_entity_update, this is not OO. But there is currently no Event in core for this.

Regards,

Rainer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.