Thanks for your interest Arbee and Tech-Guy. Here's my further development work, even if it may now be redundant in the age of SS3.1.
Since my last major code post, I've achieved the following:
• Forum Community Members are able to subscribe/unsubscribe at will to any forum.
• Notification emails are sent to all subscribers when a new post or reply is made to a forum.
• Those with a forum rank of Administrator receive notification emails whenever any post is made to any forum, no subscription necessary.
For starters, here's my latest revision of ForumEmailPostDecorator.php:
class ForumEmailPostDecorator extends DataObjectDecorator {
//Email all Forum Administrators and just the Subscribers to the particular forum when a post is made.
//----------------------------------------------------------------------------------------------------
function onAfterWrite() {
// CHECK IF THIS IS A NEW POST. DON'T SEND EMAIL IF THE POST IS BEING MOVED OR EDITED!
if(!$this->owner->LastEdited) {
// CHECK IF THIS POST'S TOPIC ID MATCHES ITS OWN ID. THIS PREVENTS DUPLICATE EMAILS BEING SENT
// WHEN A NEW TOPIC IS CREATED, CAUSED BY THE TWO WRITE STATEMENTS IN FORUM.PHP.
if($this->owner->TopicID != $this->owner->ID) {
// GET ALL MEMBERS WITH THE FORUMRANK OF "COMMUNITY MEMBER"
$commembers = DataObject::get("Member","ForumRank = 'Community Member'", "", "");
// GET ALL MEMBERS WITH THE FORUMRANK OF "ADMINISTRATOR"
$administrators = DataObject::get("Member","ForumRank = 'Administrator'", "", "");
// EMAIL THE COMMUNITY MEMBERS
if($commembers) {
foreach($commembers as $member) {
// ONLY EMAIL MEMBERS SUBSCRIBED TO THIS FORUM
if($member->isSubscribedToForum($this->owner->Forum())) {
$this->createEmail($member);
}
}
parent::onAfterWrite();
}
// EMAIL THE ADMINISTRATORS
if($administrators) {
foreach($administrators as $member) {
$this->createEmail($member);
}
parent::onAfterWrite();
}
}
}
}
//CREATE THE FORUM NOTIFICATION EMAIL
function createEmail($member)
{
error_log("LOG MESSAGE FROM FORUM EMAIL POST DECORATOR LINK IS ".$this->owner->AbsoluteLink());
$email = new Email();
$email->setFrom('webmaster@yourdomain.co.nz');
$email->addCustomHeader('Reply-To', 'no-reply@yourdomain.co.nz');
$email->setTo($member->Email);
$email->setSubject($this->owner->Title . ' | Your Website Name ' . $this->owner->Forum()->Title . ' Forum');
$email->setTemplate('Forum_ModeratorNotificationV2');
$email->populateTemplate(array(
'Recipient' => $member->FirstName,
'AbsoluteLink' => $this->owner->AbsoluteLink(),
'Title' => $this->owner->Title,
'Content' => $this->owner->Content,
'Author' => $this->owner->Author()->Nickname,
'Forum' => $this->owner->Forum()->Title
));
$email->send();
}
}
Next, the updated email template, Forum_ModeratorNotificationV2.ss
<h3>Forum Post Notification: <em>$Forum</em></h3>
<hr />
<table cellpadding="10px">
<tr>
<td bgcolor="#EEE">
<h4><a href="$AbsoluteLink" title="Go to the $Title page" class="$LinkingMode">$Title</a></h4>
<pre>
$Content
</pre>
<p>
<b><em>$Author</em></b>
</p>
<h5><a href="$AbsoluteLink" title="Go to the $Title page" class="$LinkingMode">Click here to reply to this post</a></h5>
</td>
</tr>
</table>
<hr />
<h6 style="font-size:0.8em;">NOTE: This is an automated email, please do not reply. You have received this email because you are subscribed to this forum ($Forum) or you are a Forums Administrator.</h6>
Now to the changes to the Forum module itself. This is where things get really dirty, and I apologise in advance for any offense caused by my neolithic butchering. First some justification:
I decided the easiest way to set up forum email subscriptions was to set up a many_many relationship of Subscribers to Forums, in exactly the same as the way Moderators are controlled. However I soon discovered a serious flaw in my plan: SS2.4 only allows one many_many relationship, so I couldn't just duplicate all the existing Moderators code and use that as the basis of my Subscribers system.
I then attempted to use many_many_extraFields to get around the problem. The plan was to change Moderators to Subscribers, then add a Boolean extraField called Moderator so that anyone who subscribed to a Forum could then be made a Moderator for that forum. However, despite many hours and much lost hair, I could find no way to actually populate my extraField with any data. (Now would be a good time to point out the obvious: I'm no developer, just a designer who's keen and running blind!)
Finally, I decided to ditch the Moderators thing altogether and replace it with Subscribers as the project I was doing this for was an internal company forum system that required very little active moderation, if any.
So, excuses made and reasoning explained, here are my changes to the Forum Module code.
In Forum.php:
• Replace Moderator and Moderators with Subscriber and Subscribers in initial declarations:
static $has_one = array(
//"Moderator" => "Member",
"Group" => "Group",
"Category" => "ForumCategory",
"Subscriber" => "Member"/*--- DBS - Subscriber to forum for emails. ---*/
);
static $many_many = array(
//'Moderators' => 'Member',
'Subscribers' => 'Member' /*--- DBS - Subscribers to forum for emails. ---*/
);
• Add this function before the Forum_Controller:
//---------DBS: Is current member subscribed to this forum?---------
function MemberIsSubscribed ($member = null) {
if(!$member) $member = Member::CurrentMember();
$idList = $this->Subscribers()->getIDList();
return in_array($member->ID, $idList);
}
}
• Add these functions to the end of the Forum_Controller:
/* ---- DBS - Forum Subscription Code --- */
function subscribeToForum() {
$member = Member::CurrentMember();
if(!$member) return false;
$this->dataRecord->Subscribers()->add($member);
Director::redirectBack();
return;
}
function unsubscribeFromForum() {
$member = Member::CurrentMember();
if(!$member) return false;
$this->dataRecord->Subscribers()->remove($member);
Director::redirectBack();
return;
}
In Post.php:
• Add this function to Post (just a duplicate of existing IsModerator function):
/* ---- DBS - Is Subscriber function ---*/
function IsSubscriber(){
return Member::currentUser()==$this->Forum()->Subscriber();
}
In ForumRole.php:
• change the belongs_many_many declaration in extraStatistics function:
'belongs_many_many' => array(
//'ModeratedForums' => 'Forum',
'SubscribedForums' => 'Forum' /*--- DBS - Forums that have been subscribed to. ---*/
),
• replace the existing isModeratingForum function with a Subscriber version:
/*--- DBS - Checks if current user is Subscribed to a forum -----------*/
function isSubscribedToForum($forum) {
$subscriberIds = $forum->Subscribers() ? $forum->Subscribers()->getIdList() : array();
return in_array($this->owner->ID, $subscriberIds);
}
• replace the existing ModeratedForums tab with SubscribedForums in the updateCMSFields function:
$fields->addFieldToTab('Root.SubscribedForums', new CheckboxSetField('SubscribedForums', 'Subscribed forums', ($allForums ? $allForums->map('ID', 'Title') : array())));
Final step is to add some code to ForumHeader.ss so people can subscribe and unsubscribe with a single click:
<% if CurrentMember %>
<% if Categories %>
<% else %>
<p>
<% if MemberIsSubscribed %>
You are subscribed to email notifications for this forum.<br /><a href="{$Link}unsubscribeFromForum" class="unsubscribeEmail">Click here to unsubscribe.</a>
<% else %>
<a class="subscribeEmail" href="{$Link}subscribeToForum">Subscribe to email notifications for this forum.</a>
<% end_if %>
</p>
<% end_if %>
<% end_if %>
(The <% if Categories %> conditional ensures the subscription link doesn't show up on ForumHolder pages, where it would be redundant.)
Phew, I think that's everything! Please feel free to fix up my bodgy work and turn this into a proper module that extends the Forum module. There's a chance I may have missed a few of my mods so please ask if anything appears to be missing.
I believe it should now be possible in SS3.1 to achieve this without replacing the Moderators funtionality as there is now better support for multiple many_many relationships.
Have fun!