Please upgrade here. These earlier versions are no longer being updated and have security issues.
HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

Help making a quick plugin

Hello there! I am interested in making a plugin which will display a DIV after the category name if it has new posts (essentially the words 'NEW' but styled.) Any thoughts on how to go about this? I was thinking of making a theme hook and finding out the category name loader (the event that draws the category name), and check if the category has new posts (I know they have a property .read, although I'm not sure how I would check this.) Would this be the right way to go about doing this? Thanks :chuffed:


  • R_JR_J Ex-Fanboy Munich Admin

    First find out where in the code happens what you like to change. Then look for any FireEvent() calls before or after this and see if the code could be changed by that.
    I haven't understood where exactly you want to insert something. And maybe it could be done with CSS.

    If it is the categories module you like to change, you have to recreate it completely. There are no events fired.
    If you like to change, you already have all the info you need and might be able to achieve what you like with CSS.

  • Category view has plenty of hooks you can use, category module you can override.

    grep is your friend.

  • HazuluHazulu New
    edited March 2015

    I have located where I want to render the DIV. CategoriesController_AfterCategoryTitle_Handler How would I go about creating if-statements to figure out if $sender is 'read'? What i want to do visually is this: to notify people of new activity within the forum.

  • Is there no simple way for me to tell if the Category being sent is Read, through checking a property (maybe something inside the $Sender which I can point to and check such as $Sender->EventArguments['Read'] ) ? Is there no simple way to check the Css from $sender to see if it has Read as a style property? In the plugin you sent me it seems to be counting the amount of unread comments through the discussions, but it's being sent to the discussion level. If I were to do a similar method as they did, I would have to send the $Sender from CategoriesController_AfterCategoryTitle_Handler to the Discussions Controller and check the posts, but can I send the result of whether or not there are new posts back to the Category Controller so that I can render my DIV accordingly?

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    Is there no simple way to check the Css from $sender to see if it has Read as a style property?

    By using a web inspector and inspecting the source, maybe if you can create a screenshot of what you want to do.

    The result might be the category marked as unread with a "New" icon or text

    Because the actual thing being read is the discussion not the category is why only discussions are marked read.

  • I posted a screenshot earlier of what I'd like to do. (The New Symbol)

    What I was hoping was having it so when you view all the new threads / comments then the new text will hide. I'm not sure if Vanilla innately supports this or if it's something I would have to make myself and implement. And I am not even sure at the least bit how I would do that.

    If the above is not possible then I guess I could always Draw the text after the category title and hide it with css for .read (when the category is marked as read.)

    Also, is there any way to make it so that the categories are marked as read once you actually view the new material inside? It seems kind of arbitrary making it so you have to toggle the category as read.

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    yes there are several plugins just enter "Read" in the search for addons

  • HazuluHazulu New
    edited March 2015

    O.o ; There are 2 plugins that are actually related to Read discussions from that entire list of Addons. Also, None of those are what I wanted, and I can't gain anything from them because I wanted the category to be marked as read automatically when everything inside is opened (when there is no new content.) Also, I'm still unsure of what to do to achieve the text being drawn depending if there are new posts or not.

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    I wanted the category to be marked as read

    A category can't be marked as read because it is the discussions that are read. You may be able to create a plugin which marks the Category as Read with an icon or something after all the discussions in the category are read. A category is a group of discussions classified as something specific.

  • HazuluHazulu New
    edited March 2015

    @vrijvlinder said:

    How would I go about toggling the icon next to the category name when the content inside it is all read? I looked at the plugin you sent me, and I managed to come up with this:

    for some reason hello is not being drawn, even when logged out (when everything is marked as unread.)
    if I change it to < then the text is being drawn, which is very confusing. I also tried drawing the value of unread, and apparently it's empty.

  • R_JR_J Ex-Fanboy Munich Admin

    As far as I know, there is no new/unread information in the categories. There is not even a function that will do that work for you in the CategoryModel.
    In Vanilla the information if a discussion is new is done by looking if DiscussionID is in table UserDiscussion. If not, the discussion is new. If yes the difference between Discussion.CountComments - UserDiscussion.CountComments is shown as the number of new comments.

    So in order to mimic that behaviour for a group of discussions (all discussions in a category), you can do something like that:

    Number of not new Discussions:

    SELECT count(DiscussionID)
    FROM UserDiscussion
    WHERE UserID = $UserID


    SELECT c.CategoryID, c.CountDiscussions - count(ud.DiscussionID) AS NewDiscussionCount
    FROM Discussion d
    LEFT JOIN Category c ON d.CategoryID = c.CategoryID
    LEFT JOIN UserDiscussion ud ON d.DiscussionID = ud.DiscussionID
    WHERE ud.UserID = $UserID
    AND c.CategoryID = $CategoryID
    1. You can omit the permission check if this function is not available with some external function call, but I would include it nevertheless!
    2. Table UserCategory has a field DateMarkedRead that you have to include (d.InsertDate > uc.DateMarkedRead) in order not to have wrong values for categories that have been marked as read.

    For unread discussions, you have to add up the d.CountComments like that:

    SELECT c.CategoryID, count(d.CountComments) - count(ud.CountComments) AS UnreadDiscussionCount
    FROM Discussion d
    LEFT JOIN Category c ON d.CategoryID = c.CategoryID
    LEFT JOIN UserDiscussion ud ON d.DiscussionID = ud.DiscussionID
    WHERE ud.UserID = $UserID
    AND c.CategoryID = $CategoryID

    This has just been brainstorming. The SQLs need some work to run. And I think this wouldn't scale on larger sites but all in all this should be a way to get the information you like to display.

    In order to get a better performance, you might try adding a column CountComments and CountDiscussions to UserCategory which show the count of read discussions/comments and is updated along the UserDiscussion table.

  • HazuluHazulu New
    edited March 2015

    Wow thanks for the amazing response! I'll definitely fiddle around with that and let you know how it goes. Thank you for explaining it as well as you did it definitely helps me understand how it works. On a side note, by any chance do you know how I could make it so if a user is online when you're reading a discussion then I can draw a div on their avatar which would let the reader know the poster is online? Something along the lines of Xenforo's.

  • R_JR_J Ex-Fanboy Munich Admin

    It's a pleasure. Please send a follow up if you have your plugin ready. I think it would be a very nice addition! And if you need any more advice, just ask.

    By the way: I have written plain SQL because it is easier at this place, but you should definitely use the query builder.

    Concerning that online flag, look at those plugins:
    I haven't checked it, but I bet you can get a list of logged in users by looking at that code. Then you only have to check if the user is in that list. If yes, give him an online icon, if not, an offline icon.

    See here: I do not know if that is working with Vanilla 2.1 and it depends on WhosOnline. Maybe you can use that without reinventing the wheel.

    <Brainy Smurf>
    Something more general: I think it is good practice to strive for one problem per discussion. Ask not for making a plugin but for the real problem: "How to check Category for new discussions" and "How to show online flag on user picture" or something like that so that other people can find hints for similar problems more easily.</Brainy Smurf>

  • HazuluHazulu New
    edited March 2015

    Alright, I will probably hold off on that for now as I think there are some other things I'd like to tackle before I get into that. But when I do work on it I will definitely follow up with you.

    And thank you so much for the onlineusers plugin link, it turns out that even though it relies on the WhosOnline plugin, WhosOnline uses the same exact tables as OnlineNow so all I had to do was replace some names and change the required plugin. Unfortunately what I am trying to achieve with this plugin apparently requires specific placement as the default vanilla skin does not have an avatar container (and changing it to work on mine won't allow others to use it.) The only other thing I could think of is adding in settings with offsets for easy access. Then again I did take the css from Xenforo for the style of the online circle and pulse.(I just really wanted to see it work, I will tweak the css later on to give it my own flair.) If you couldn't tell already I am trying to make my forum look and feel as close to Xenforo as possible as I just love it so much. I also plan on creating a version of the UI.X skin that will be available for all at vanilla. Also any plugins I do work on will be released here for others that want to do the same as me. (Only problem is I am mainly a front-end guy, so lately I've been out of my comfort zone :proud:)

  • R_JR_J Ex-Fanboy Munich Admin

    I guess that means you have changed the core files, did you? Do you have a reason to finish your work as soon as possible? If yes, changing the core might be a okay, but you will have to do a lot of clean up afterwards.
    If you do not have a gun pointing at your head, I'd advice to take your time and ask for help on how to do things properly ;)

    I have no idea on how the XF community is, but if you ask here for help, you'll almost always get nice ideas on how reach your goal.

    So when you've inserted some kind of div somewhere, you are on the wrong track. You might have seen that the UserPhoto is inserted with UserPhoto($Author). ÙserPhoto()` is a function that you can override. The advantage on overriding compared to changing the core is, that you will be able to update easily. Version 2.2 is on its way and it has some nice features, you certainly don't want to miss because you've changed the core and cannot update ;)

    Even better than overriding is using hooks.

    Option 1 is to replace function "UserPhoto()" with your own version (that would not need much more than a little copy & paste).

    Option 2, using a hook, is to be prefered. So look out for any FireEvent() calls in the code you look at. Well, there are none. But look at that piece of code inside the UserPhoto function:

          $FullUser = Gdn::UserModel()->GetID(GetValue('UserID', $User), DATASET_TYPE_ARRAY);
          $UserCssClass = GetValue('_CssClass', $FullUser);
          if ($UserCssClass)
             $LinkClass .= ' '.$UserCssClass;

    There is a call to the UserModel and in nearly all GetSomething function calls of a model, there are FireEvent(BeforeGetSomething) and FireEvent(AfterGetSomething) calls. In the UserModels GetID function we have a FireEvent(AfterGetID).
    And the User we get from GetID might include a _CssClass which is added to the user photo... HEUREKA!

    Do you have made a custom theme folder? If not, do so! Create a file called "class.yourthemenamethemehooks.php" and insert that:

    <?php defined('APPLICATION') or die;
    // you have to change that:
    class YourThemeNameThemeHooks implements Gdn_IPlugin {
         * Adds a class to the User object, depending on the online/offline status.
         * @param  object $sender UserModel.
         * @return void.
        public function userModel_afterGetID_handler ($sender) {
            // Here's the part you have to work with
            $userIsOnline = true; // or false, based on the routine you already copied
            // know lets transform our result to a class name
            if ($userIsOnline === true) {
                $cssClass = ' UserPhotoOnline';
            } else {
                $cssClass = ' UserPhotoOffline';
            // LoadedUser can be object or array, _CssClass may or may not be set.
            // That's why we need some "if" spaghetti here :-/
            $user = $sender->EventArguments['LoadedUser'];
            if (is_array($user)) {
                if (isset($sender->EventArguments['LoadedUser']['_CssClass'])) {
                    $sender->EventArguments['LoadedUser']['_CssClass'] .= $cssClass;
                } else {
                    $sender->EventArguments['LoadedUser']['_CssClass'] = trim($cssClass);
            } elseif (is_object($user)) {
                if (isset($sender->EventArguments['LoadedUser']->_CssClass)) {
                    $sender->EventArguments['LoadedUser']->_CssClass .= $cssClass;
                } else {
                    $sender->EventArguments['LoadedUser']->_CssClass = trim($cssClass);
        // needed, but you do not have to change anything
        public function setup () {
            return true;
        // needed, but you do not have to change anything
        public function onDisable() {
            return true;

    You now get an additional class that you can simply style like that .UserPhotoOnline {border:3px solid green}

    Although this might look awefully complicated at first sight, read it a few times and you'll see that there's not much behind it. And believe me: solving your problem that way pays out on the long run!

  • Oh man, I would never edit the core. I just happen to have a lot of custom views, with a changed html layout (in my theme.) The only reason that I had to do this was because I wanted to change the layout of vanilla, and I couldn't achieve the effect I wanted with the divs vanilla has available.

    "So when you've inserted some kind of div somewhere, you are on the wrong track."
    Should I still try to avoid editing the views then? (custom views in the theme folder) Such as the default view and the discussions view to change the comment layout.

    And I can't wait for 2.2, in all honesty the thing I am most looking forwards to is the editor :).

    I actually didn't know that I could even hook into those methods and add classes and divs to them. Does this mean that I could potentially hook into anything and change the way it is displayed, more specifically the containing divs or classes? Thank you for all your help by the way, this is definitely some interesting stuff.

  • R_JR_J Ex-Fanboy Munich Admin

    @Hazulu said:
    Oh man, I would never edit the core.

    Sorry for my suspicion ;)

    @Hazulu said:
    "So when you've inserted some kind of div somewhere, you are on the wrong track."
    Should I still try to avoid editing the views then?

    In my opinion, you should always try to change things in that order

    Custom views
    Core changes

    CSS is not invasive at all => good!
    If you can write a plugin you can write theme hooks and vice versa.
    Views might implement new features in new Vanillaversions. So if you have overriden them, the new feature is not available in your theme.
    If you found a critical error or you absolutely need to change something that could not achieved with the above, you might have to change the core. But do it "right": insert a FireEvent call and pass it the parameters you need. That way your chances to recreate your changes after an update are very high. And if you think there should be a FireEvent at that place, do a pull request at GutHub.

    @Hazulu said:
    I actually didn't know that I could even hook into those methods and add classes and divs to them. Does this mean that I could potentially hook into anything and change the way it is displayed, more specifically the containing divs or classes?

    Maybe it is not possible at all places, but it is definitely worth a try! Create a discussion "Several questions for custom theme". Or create one discussion per view that you would like to change.
    With the time you will see the pattern and manage to answer your questions by yourself.

Sign In or Register to comment.