1

Ok, just thinking out loud and trying to work out the best way to achieve something. I have a community site with roughly 25k users.

I would like to create a way to send messages to those users within the front end of the site. This might be, for example, a notification of a new entry based on a set of criteria or even a message from the site admin to every user advising of a new feature.

The user should be able to view the message, which marks it as read and have the ability to delete it. All messages would live in a notifications page.

I’m just wondering if this is something that’s possible to achieve using Craft (via a plugin) or are there other services that are better suited to this. I can’t find anything online, everything seems geared towards push notifications which is slightly different to what I’m after.

Any thoughts as I can’t quite get my head around a way to achieve this.

Thanks!

  • I don't know if something like that exists since I don't really use plugins from others but I can write the code for you if you like. You only need one record, a controller, a variable and a few lines of code. You can use the "secure" way and insert a new record in your db everytime a user clicks on dont show it again or - if you are really really lazy - you can create a cookie show only messages that are not older than X days and not marked in the cookie... I would prefer the first method – Robin Schambach Dec 9 '17 at 1:36
  • Hi Robin. If you could give an example of the code that would be great. I agree the first way would be best. Having done little in plugin dev, I’m struggling to work out how to start this off! Thanks! – shorn Dec 9 '17 at 8:49
2

I created a simple plugin for you to start. Note that is not a ready-to-use plugin so you'll have to change the things you need. This is just meant to be a starting point for you. You can use the code and change it how you like it but mostly it is for learning purposes. So please don't expect it to be "finished" since I don't know your needs and your structure. The most important thing: my css/design skills are awful so I did not style anything.. you have to do it on your own

Feel free to say what I could/should change for you.

So here it is Usernotifications

So let's go through it:
My idea was to create a section called usernotifications (you don't have to do it by yourself, it is created onAfterInstall and can be changed later) that has different entry types for different messages and purposes. If you want to change the section handle make sure to change the $criteria->section = 'usernotifications'; in my service. This way you can create messages/notifications how you like and make them really dynamic. Please read this for some ideas and instructions Overview

Craft renders all those entries unless the user dismisses them or if they are too old. Check my service for the logic.

The Controller:
has two methods, the first is actionRemoveNotificationto remove a message/notification for a user. So you'll display a dismiss button and as soon as someone clicks it, you create a record in your database with the userId and the entryId, so you know which user removed a notification.

/**
 * Remove a notification for a user 
 */
public function actionRemoveNotification(){
    $this->requirePostRequest();
    $this->requireAjaxRequest();

    $response = [
        'success'   => false,
        'message'   => 'could not find entry'
    ];
    if($entryId = craft()->request->getParam('id')){
        $userId = craft()->userSession->getUser()->id;

        $record = UsernotificationsRecord::model()->find('entryId = :entryId AND userId = :userId', array(
            'entryId'   => $entryId,
            'userId'    => $userId
        ));
        if($record){
            // user already removed the message... there must be something wrong or he/ she cheated :P
            // you can actually ignore this... just wanted to show you how to search for entries^^
        }else{
            $record  = new UsernotificationsRecord();
        }

        $record->userId = $userId;
        $record->entryId = $entryId;

        if($record->save()){
            $response['success'] = true;
            $response['message'] = 'notification removed for user';
         }else{
            $response['message'] = 'could not save record';
            $response['errors'] = $record->getErrors();
        }
    }

    $this->returnJson($response);
}

The service:
The service should return all notifications for the current User or nothing at all if the user is not logged in

/**
 * Get all notifications for the current user
 *
 * @return string
 */
public function getAllNotificationsForUser(){
    // check if user is logged in...
    if(!craft()->userSession->getUser()){
        return false;
    }

    // fetch all removed notifications of the user to not fetch them in our query
    $removedNotifications = craft()->db->createCommand()
        ->select('entryId')
        ->from('usernotifications')
        ->where(['userId' => craft()->userSession->getUser()->id])
        ->queryColumn();

    $criteria = craft()->elements->getCriteria(ElementType::Entry);
    $criteria->section = 'usernotifications';
    // user should not be overwhelmed with too many notification when they didn't log in for too long
    // so show only notifications 14 days ago, you can change this length or remove it if you want
    // but make sure to change the value in the task as well.
    // you could also create settings for the plugin where you can store how long
    // then entries should be displayed
    $someDateInThePast = date('U', strtotime("-14 days"));

    $criteria->postDate = "> " . $someDateInThePast;
    // exclude the ids of the removed notifications
    if($removedNotifications){
        $criteria->id = 'and, not ' . implode(', not ', $removedNotifications);
    }

    return $criteria->find();
}

Your Variable
In your variable you'll get the html for those notifications, you can find the templates in templates/entries/entrytypes

public function getAllNotificationsForUser(){
    $html = '';
    $entries = craft()->usernotifications->getAllNotificationsForUser();
    if($entries){
        // I get a deprecated hint here, but the solution stated in craft throws
        // an exception... So I'm using this one
        $oldPath = craft()->path->getTemplatesPath();
        $newPath = craft()->path->getPluginsPath() . 'usernotifications/templates';
        craft()->path->setTemplatesPath($newPath);
        $html = craft()->templates->render('entries/index.twig', array(
            'entries' => $entries
        ));
        craft()->path->setTemplatesPath($oldPath);
    }
    return $html;
}

I guess these are the most important parts, you can check the rest in my git repo and ask/request whatever you like.

You can render the entries with

{% set notifications = craft.usernotifications.getAllNotificationsForUser() %}
{{ notifications|raw }}

Before I forget it: I created a task to remove too old records. You can access it via /admin/actions/usernotifications/removeOldRecords

| improve this answer | |
  • Robin, this looks great. I certainly think there’s enough there for me to start implementing this and testing it out. It makes sense to me as well, which is encouraging! I’ll report back soon the one way I might look to expand on this would be to move the notification to its own element type. Ideally I’d like other plugins/actions to trigger the creation of a message as well, as it would be handy to automate things a little. This looks like a great starting point 👍 – shorn Dec 9 '17 at 17:08
  • You are welcome. Creating custom element types could be a tricky in craft 2 since it's not that easy to create different types of those thus you'll probably only be able to have one form for all notifications unless you create 2 elements: the sections and the entries in them. I made a formbuilder for craft 2+3 to create dynamic elements so I know what I'm talking about. If you think it's handy - go for it. We can help you in this board with everything and for learning purposes it's a great task but it might not be worth it. Btw please use git for references I committed changes few hours ago – Robin Schambach Dec 9 '17 at 17:44
1

I don't know what your timeline is for this plugin but I did read this article from Andrew Fairlie where he introduces a craft plugin that he is developing. The article was written quite a while ago and I don't think he has ever released it. You could try and reach out to him to see if you can use the plugin or even take over its development in the case it has stalled. It seems to do exactly what you are asking for including the "mark as read function" as well as a couple of things on the side.

It obviously also depends on if you are comfortable with using other people's plugins or if you specifically want to write your own....

This is the article:

https://medium.com/the-feelings/introducing-notification-centre-for-craft-cms-38d453af5222

| improve this answer | |

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.