0

I have a View Top 3 that displays the 3 nodes with the highest average voting scores (I use Fivestar via comments on the nodes for voting). Every node has a field Highest ranking, that - as the name suggests - should store the highest ranking ever obtained in Top 3.

Now, the View Top 3 also filters nodes that were created less than 5 days ago. I'm wondering how I can change the Highest ranking fields of the nodes in the top 3 when the top 3 changes. The above explanation should make clear that this can happen when

  • a new comment with a vote has been created;
  • an existing comment with a vote has been changed;
  • a node is older than 5 days and is therefore banned from the top 3.

Which hooks can I use for this?

0

Implement something like hook_views_pre_render() or hook_views_post_execute() and, every time your "Top 3" view is executed have your code iterate over the results and update the "Highest Ranking" field for each of the nodes in the top 3 as needed.

The only downside of this is that if your "Top 3" view is rarely ever executed then it's possible that a node could move into then back out of the Top 3 without the view ever being executed and thus without your code ever recording the node's presence in the top 3. If you want to try to avoid this you might implement hook_cron and programmatically call your view every time cron is run.

  • Thank you for your answer! I've succesfully implemented the first part using hook_views_pre_render() with just a few lines of code. Although Top 3 is placed on the front page and is therefore often viewed, I'd like to add a hook_cron as you proposed. What do you mean exactly with "programmatically call your view"? I've now added $view = views_get_view('myview'); but that doesn't do anything. – Jeroen Sep 7 '15 at 20:59
  • @Jeroen views_get_view() doesn't actually execute the view. The easiest thing is probably to call views_embed_view(). – Aaron Sep 7 '15 at 21:03
  • That sounds reasonable. For some reason my hook_cron isn't called when manually running cron. I've cleared caches, but still nothing. Even a simple dpm('test'); doesn't do anything... Any experience with this? – Jeroen Sep 7 '15 at 21:21
  • @Jeroen dpm('test'); may not give you what you expect unless you're running cron through the UI (won't work with drush). This sounds silly, but I assume you've actually named your function mymodulename_cron(). If so, and you're still not hitting your function, then it's possible that another cron-related function is throwing a fatal error before your function is hit. Please consult your logs. – Aaron Sep 7 '15 at 21:23
0

It is a bit complex but I'll try to help get things started.

Since the view is just a dynamic collection of content it makes sense to monitor the content for the types of events/changes that affect the view result.

The module you'll need for this is Rules. I see from your profile that you have some experience here.

The Fivestar module doesn't appear to have any Rules integration so you may need to create a custom Rules condition to distinguish comments with votes. (Or maybe not - I'm just not familiar with the module.)

At its simplest, it boils down to triggering an action based on the criteria you have described above. The tricky part is checking the new vote count against the view result so that you can update the field accordingly.

One way you may be able to do this is to do a before-and-after check when a comment is saved or updated. Rules Bonus Pack (in particular the submodule "rules_misc") has some Views-related additions that come in handy here.

A rough outline of a rule that alters (unsets?) the value of the field on "top 3" nodes before the comment is saved.

EVENT
  Before saving a comment (of type X)
ACTION
  Load a node list with Views (offered by Rules Bonus Pack)
  LOOP through list
    Fetch entity by id
    Set a data value (entity-fetched:fieldname)
  END LOOP

After the comment is saved, reset the field value on all "top 3" nodes which presumably have been recalculated based on this new data (the saved/updated comment).

EVENT
  After saving a comment (of type X)
  After updating an existing comment (of type X)
ACTION
  Load a node list with Views
  LOOP through list
    Fetch entity by id
    Set a data value (entity-fetched:fieldname)
  END LOOP

Note: You could do all of this by storing the result somewhere and checking on cron run or when a view is being built or a node is being viewed or what have you, but by attaching the action to the events that affect the result (comment being saved/updated) you ensure the change is implemented without delay.

For the third criteria ("a node is older than 5 days") you can set up another rule that checks a condition during a cron run and alters the field on all nodes that are older than 5 days. This will obviously have some delay (depending on how often your cron runs); maybe there's a better way but I can't think of one at the moment. You would probably use Views Bulk Operations for this. Also look at Rules Scheduler (a submodule of Rules). This isn't an uncommon scenario so a quick internet search should yield several methods/tutorials.

Edit: Added more specifics on how to implement with Rules (and Rules Bonus Pack) when a comment is created/updated.

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.