15

How can I delete a node after, for example, 2 weeks it has been created?

18

If you're looking for a developer-centric solution, you can invoke hook_cron() in a custom module to clean up old nodes:

function MYMODULE_cron() {

  // Other conditions can be altered/added as neeed
  $query = \Drupal::entityQuery('node')
    ->condition('created', strtotime('-2 week'), '<=');
  $nids = $query->execute();
  foreach ($nids as $nid) {
    $node = node_load($nid);
    $node->delete();
  }
}
  • How can do it with rules in drupal 8 ? – RobinSon May 20 '16 at 17:21
  • 1
    This was intentionally a different approach from the site builder / Rules based approach. I'd ask @UnsettlingTrend to update his answer accordingly. I haven't tried out Rules in D8 yet, so I can speak to solution based on that module. – Shawn Conn May 20 '16 at 17:35
  • 7
    Using $nodes = $storage->loadMultiple($nids) and then $storage->deleteMultiple($nodes) is bit faster, but unless you're deleting dozens of nodes, not a big issue. – Berdir May 20 '16 at 22:40
  • @SiMoNe you can't yet. There is no rules scheduler module yet, plus Rules 8 is not production ready. – No Sssweat May 21 '16 at 5:42
  • 1
    I would create a queue based approach for scaling out. You don't need Rules. – Kevin Sep 4 '16 at 1:09
4

Based off Shawn Conn's answer, here is the full solution for novices:

  1. Go to your root file directory and create folder "delete_old_nodes"
  2. Create a file in the folder you just created called: "delete_old_nodes.info.yml" and paste this code in it:

    name: Delete old nodes
    description: Deletes nodes older than 30 days.
    package: Custom
    type: module
    version: 1.0
    core: 8.x
    
  3. Create a file called "delete_old_nodes.module" and put this code into it:

    <?php
    
    function delete_old_nodes_cron() {
    
      $query = \Drupal::entityQuery('node')
        ->condition('created', strtotime('-2 week'), '<='); // Can change -2 week to -2 year or -3 day
      $nids = $query->execute();
      foreach ($nids as $nid) {
        $node = node_load($nid);
        $node->delete();
      }
    }
    
    ?>
    
  4. Flush cache, then navigate to modules page — (yoursite.com/admin/modules) — and enable your module, (by searching for "delete old nodes", click the checkbox by the modules name and click save).

  5. Done! Whenever you run cron, the nodes/pages that were published -2 weeks, or whatever you have it at, from now will be deleted.

  6. Note: To schedule when cron runs, go to yoursite.com/admin/config/system/cron

Testing:

Create a node and change the published date, normally in the right sidebar, to -2 weeks or whatever you have it at. Manually run cron at yoursite.com/admin/config/system/cron and you should not be able to find your node.

  • You don't need the closing ?>. That will cause errors on some server setups. I would advise having a more structured setup using QueueAPI, that way if there are thousands or even hundreds of nodes to delete, it won't hang up the system within the cron op above. sitepoint.com/… – Kevin Sep 4 '16 at 2:40
  • Huh. When I didn't have the ?>, the code would not work for me. – Chris Happy Sep 4 '16 at 5:50
2

I would use a hook_cron() implementation too, but using the following code.

function mymodule_cron() {
  $storage_handler = \Drupal::entityTypeManager()
    ->getStorage('node');
  $query = \Drupal::entityQuery('node')
    ->accessCheck(FALSE)
    ->condition('created', strtotime('-2 week'), '<=');
  $result = $query->execute();
  if (!empty($result)) {
    $nids = array_keys($result);
    $nodes = $storage_handler->loadMultiple($nids);
    $storage_handler->delete($nodes);
  }
}

The code I used to delete the nodes is the one that the deprecation message for entity_delete_multiple() suggests to use.
I also used a call to accessCheck(FALSE) to avoid the entity query returns only the nodes to which the anonymous user has access. (Cron tasks run as anonymous user.)

If then there is the possibility the nodes to delete are too much, I would limit the number of nodes deleted each time cron tasks run.

function mymodule_cron() {
  $storage_handler = \Drupal::entityTypeManager()
    ->getStorage('node');
  $query = \Drupal::entityQuery('node')
    ->accessCheck(FALSE)
    ->condition('created', strtotime('-2 week'), '<=')
    ->range(0,30);
  $result = $query->execute();
  if (!empty($result)) {
    $nids = array_keys($result);
    $nodes = $storage_handler->loadMultiple($nids);
    $storage_handler->delete($nodes);
  }
}
  • I know this question is old but @kiamlaluno your answer saved my time! and instead of posting a new question which will be a duplicate of this one, Could you please elaborate more on how to limit the deletion of nodes to node of type article, Thank you – Elie Masaad Apr 25 at 1:55
  • The last hook_cron() implementation shown already does that, as it calls range(), differently from the previous implementation. – kiamlaluno Apr 25 at 15:38
  • The range() as I understand, will limit the number of nodes deleted each time cron tasks run. But say I have on the site 30 nodes of types page & article with creation date more than 2 weeks ago... How to delete only the nodes of type article without deleting the node of type page ?... Excuse my humble php skills but I could not see such implementation in the above code ! Thanks – Elie Masaad Apr 25 at 18:06
0

I would do try to do it as such:

  1. Create a View of all nodes that are 2+ weeks old
  2. Create a system Rule to run on Cron maintenance
  3. In the rule configuration, create a loop to iterate over those view results
  4. Delete each node

I'll try to test it when I get a chance, because I'm not entirely sure how easy/possible it'll be to utilize the view like that in 3., but that's definitely where I'd start. Of course, this comes with the caveat that it won't delete nodes when the become EXACTLY 2 weeks old, but will be dependent on when Cron runs on your system; but, I assume within 3 hours or so is still sufficient.

(I only just noticed this was for D8; I think the process is still sound though.)

  • I didn't realize D8 until after I typed that. I just know rules are are in alpha for stable for D8; haven't tried it yet. – UnsettlingTrend May 20 '16 at 16:07
  • I went with the dev version of Rules. For what I was trying, it seemed stable, but I'm stuck at the fact that there seems to be no--planned otherwise--D8 version of the Views Rules module to use to loop over the view results. If there's a way to get Views in a Rule that I can't think of, it might work. Otherwise, I'm not sure. – UnsettlingTrend May 20 '16 at 16:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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