2

I have an OG content type with a date field. When the date in the field comes up, I want to use Rules to send an email to everyone in the group using the other fields (title/body/og name) in the node.

(Edit) My OG is "Teams" and the OG Content node type is "Events" with the date field. So when field_date in Events is within 24 hours Rules will send out an email to all the OG Members of Teams.

I'm having a hard time wrapping my head around triggering the event based upon the date field and then send the node information to all the different users in the different groups.

  • Your answers have been brilliant but I wasn't clear that the date field is not in the Group node but in the Group Content node. There is an extra level of complexity to my problem. First I need to filter "Event" nodes to their date field and then send out emails to the members of the Group "Teams"<br> I've edited the original question to make it clearer. Sorry for the misunderstanding. – seanenroute Nov 28 '17 at 5:51
  • Out of curiosity which method VBO or Rules Scheduler runs smoother on the server? If there are tens of thousands of events and users does either of these methods have a bigger performance hit? – seanenroute Nov 28 '17 at 6:46
  • I'd imagine they're pretty similar performance-wise but Pierre might know better.. I'll add to my answer some time in the future for the sake of making it a possibly useful for someone in the future. Pierre's answer looks great for what you need. – Niall Murphy Nov 28 '17 at 6:56
2

To do what you're asking for, I would only use the Rules module, and the Rules Scheduler (a submodule of it), as further explained below.

Step 1 - Create a Rules Component

Create a Rules Component which looks like so (in Rules export format):

{ "rules_send_notification_to_og_members" : {
    "LABEL" : "Send notification to OG members",
    "PLUGIN" : "rule",
    "REQUIRES" : [ "rules", "og" ],
    "USES VARIABLES" : { "current_node" : { "label" : "Current node", "type" : "node" } },
    "IF" : [
      { "node_is_of_type" : {
          "node" : [ "current-node" ],
          "type" : { "value" : { "book" : "book" } }
        }
      }
    ],
    "DO" : [
      { "og_get_members" : {
          "USING" : { "group_content" : [ "current-node" ] },
          "PROVIDE" : { "group_members" : { "group_members" : "List of group members" } }
        }
      },
      { "LOOP" : {
          "USING" : { "list" : [ "group-members" ] },
          "ITEM" : { "group_member" : "Current group member" },
          "DO" : [
            { "mail" : {
                "to" : [ "group-member:mail" ],
                "subject" : "Friendly reminder about some post in group",
                "message" : "Hello [group-member:name],\r\n\r\nThere is a reminder about a post with title [current-node:title] (located at [current-node:url]) which belongs to one of the groups you are subscribed to.\r\n\r\nSome more details about this node:\r\n\r\n- Price: [current-node:field-book-price]\r\n- Release Date: [current-node:field-book-release-date]",
                "language" : [ "" ]
              }
            }
          ]
        }
      }
    ]
  }
}

Some details about the above Rules Component:

  • Component Variables: only a "node" (of type "node"), of type "parameter", labeled "Current node", and machine name current_node.
  • Rules Condition: use whatever extra condition you need/want, but actually you may not need any at all. As a sample, I just used "Content is of type" (with actual type = book).
  • Rules Actions:
    • Get group members from group audience, for current_node, and store the result in a list with machine name group_members.
    • Perform a Rules Loop, for each item in the group_members list, whereas the item is named group_member. And for each iteration of this loop, send an eMail to the group member being processed, with all sorts of data about the node included in the eMail title and/or eMail body (use your own imagination to make it fit your needs).

Step 2 - Create a Rules which schedules the Rules Component

Create a Rule which looks like so (in Rules export format):

{ "rules_remind_og_members_about_node_content" : {
    "LABEL" : "Remind OG members about node content",
    "PLUGIN" : "reaction rule",
    "REQUIRES" : [ "og", "rules", "rules_scheduler" ],
    "ON" : [ "node_insert", "node_update" ],
    "IF" : [
      { "og_entity_is_group_content" : { "entity" : [ "node" ] } },
      { "entity_has_field" : { "entity" : [ "node" ], "field" : "field_book_release_date" } }
    ],
    "DO" : [
      { "schedule_delete" : {
          "component" : "rules_send_notification_to_og_members",
          "task" : "Notify-OG-members-for-node-[node:nid]"
        }
      },
      { "schedule" : {
          "component" : "rules_send_notification_to_og_members",
          "date" : {
            "select" : "node:field-book-release-date",
            "date_offset" : { "value" : -259200 }
          },
          "identifier" : "Notify-OG-members-for-node-[node:nid]",
          "param_current_node" : [ "node" ]
        }
      }
    ]
  }
}

Some details about the above Rule:

  • Rules Events (either of both):
    • After saving new content.
    • After updating existing content.
  • Rules Conditions (all conditions must be true):
    • Entity group content, for entity = node.
    • Entity has field for field field_book_release_date, which is defined as a date field, and which you could consider as something like the release data of a book. Note: for nodes which don't have that field, or for which it is empty, this Rules Condition is false (so no Rules Actions will be performed).
  • Rules Actions:
    • Delete scheduled task, with Notify-OG-members-for-node-[node:nid] as the "Task identifier", whereas the task refers to the Rules Component created in Step 1.
    • Schedule component evaluation, with Notify-OG-members-for-node-[node:nid] as the "Task identifier", whereas the task refers to the Rules Component created in Step 1. And the actual date to schedule the execution of this Rules Component, is the date indicated in the node's field field_book_release_date, but with an offset of -3 days (pick whatever value for this offset the fits your needs), so 3 days before the date indicated in that field, the Rules Component is executed.

To be complete: the first Rules Action (to delete the previously scheduled task with the very same Task identifier), is to ensure that the Rules Component is only executed once. The typical scenario is that first the node gets created (and the Rules Component is scheduled accordingly). But later on the node is updated. In that case, the request to execute the previously scheduled Rules Component is deleted, and a new request is scheduled again. And if the date itself was not updated, it will be scheduled for execution at the very same moment. But if the date was updated also, only the date of the most recent update will be taken into account. For this mechanism to work, it's important to use a unique Task Identifier, to be used in both Rules Actions. That's why I added the token [node:nid] to it (with a prefix like Notify-OG-members-for-node- so that it can be recognized by somebody looking at the currently scheduled Rules Components also).

Bonus tip - Resolving potential access issues

By using the Rules Scheduler, in the end the Rules Component will be executed when cron is running (the very first time after the date/time the Rules Component was asked to be scheduled). But cron jobs always run with user Anonymous.

So the question that remains is: "How will the eMail content look like if you're processing a node for which an anonymous user has no access?". If you run in any such access issues, the easiest workaround I can think of is that you improve the Rules Component by adding additional variables (used as "Parameter"), and so that these variables contain the values of the relevant node's fields that you want to be able to refer to in the eMail to be created. Since the user who triggers the Rule from Step 2 (due to a create or update of a node) should have (read) access, for sure these values will be passed to the Rules Component at the time of scheduling the Rules Component.

PS: I'm assuming this question is about D7.

  • Hi this method worked exceptionally well for me. Thank you! – seanenroute Nov 28 '17 at 6:43
  • 2
    I like this one a lot! Very concise and shows me I should look at scheduler more. It also solves an issue I hadn't thought of with my answer in that my first view needs to be filtered by an OG content's field. The only benefit to the VBO approach I guess is some customisability of the views with things like flags and roles, but Rules conditional could probably take care of that. – Niall Murphy Nov 28 '17 at 6:43
1

For this you should use VBO to provide a list of nodes to your rule. Here is an answer of mine that gives some detail for this.

When you get the list of nodes, you should be loop them, fetch the users for each, and send the email.

You should probably also add an email sent boolean field to the content type, set it to TRUE in the rule and then use that to filter out nodes in your view so emails don't get sent twice.

More Detail:

For this, you probably need to use the latest Dev release which fixes an issue with VBO not supplying data to Rules.

Views

View 1: List of groups. You would add an extra filter here to get OG groups based on time.

View 1

View 2: List of users of a group. Note the contextual filter and the second image showing its settings.

View 2

View 3

Rules

Rule: This rule runs on Cron, grabs the Groups from View 1 and sends each group to a rule component.

{ "rules_test_og_2" : {
    "LABEL" : "Test OG",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "views_bulk_operations", "rules" ],
    "ON" : { "cron" : [] },
    "DO" : [
      { "views_bulk_operations_action_load_list" : {
          "USING" : { "view" : "vbo_all_groups|block_1" },
          "PROVIDE" : { "entity_list" : { "entity_list" : "A list of entities" } }
        }
      },
      { "LOOP" : {
          "USING" : { "list" : [ "entity-list" ] },
          "ITEM" : { "current_group" : "Current Group" },
          "DO" : [ { "component_rules_og_helper" : { "node" : [ "current-group" ] } } ]
        }
      }
    ]
  }
}

Or in picture format.

Rule1

Rule Component: This sends each group to View 2 and returns a list of users. The "body" condition and drupal message is to show how to use the group's fields in an email.

{ "rules_og_helper" : {
    "LABEL" : "OG Helper",
    "PLUGIN" : "rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "rules", "views_bulk_operations" ],
    "USES VARIABLES" : { "node" : { "label" : "node", "type" : "node" } },
    "IF" : [ { "entity_has_field" : { "entity" : [ "node" ], "field" : "body" } } ],
    "DO" : [
      { "views_bulk_operations_action_load_list" : {
          "USING" : { "view" : "my_og_members_view|block_1", "args" : [ "node:nid" ] },
          "PROVIDE" : { "entity_list" : { "users_list" : "List of Users" } }
        }
      },
      { "LOOP" : {
          "USING" : { "list" : [ "users-list" ] },
          "ITEM" : { "current_user" : "Current User" },
          "DO" : [
            { "drupal_message" : { "message" : [ "current-user:mail" ] } },
            { "drupal_message" : { "message" : [ "node:body:value" ] } }
          ]
        }
      }
    ]
  }
}

Or in picture format.

Rule2

I tested external cron with creating some nodes with user details and it worked fine. It looks complicated but is pretty easy, even with having to apply the patch.

What I haven't included here is an extra field on your content type that you would use as a filter in View 1 and change in your Rule so that emails only get sent once.

  • Bonjour (again) ... Not to hijack your answer to post a new question, but your answer is based on using cron, which runs with user anonymous (I bet you know that). But since the question here is about OG, chances are that anonymous does not have access to the view and/or some of the nodes, agree? If so, are you sure the eMail is produced for such nodes? FYI, you may want to look at this answer (it's mine) to possibly address that also. With that, I'm tempted to post another answer which avoids all these cron/anonymous issues ... – Pierre.Vriens Nov 27 '17 at 10:03
  • I hadn't thought of that. But checking View > Other > Query settings > Disable SQL rewriting would likely allow anonymous cron to use the view results. I'll check it properly in a while. – Niall Murphy Nov 27 '17 at 10:12
  • Grrrrrrrrrrreeting again ... so you do know about that trick already. But what if that is not "acceptable"? Also, can you predict what will happen if some of "the other fields" (as in the question) are not included as some column in the views results? Sorry for challenging you with this extra comment (consider it as QA-reading, ok?). – Pierre.Vriens Nov 27 '17 at 10:22
  • Haha, well I'm gonna go through it from start to finish and update the answer as needed. My idea was to send each group to a Rules component rule which could then check the supplied node for those fields and then use them. – Niall Murphy Nov 27 '17 at 10:46
  • 1
    Wow, that's a kind of painfull ... From that issue you mentioned, it looks like it is time to call Argiepiano ... Of course, another way to solve an issue, is to prevent it from happening (stay tuned for a completely different answer I'm thinking of. Even if it was only because of that "Please avoid extended discussions in comments. ..." showing up above my comment here now ... – Pierre.Vriens Nov 27 '17 at 11:43

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.