HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

Can I replace functions in class.dispatcher.php?

I know that class will be trying to be as lean as possible for speed sake and scalability.

But, I would like to grab a url, do some logic and send it off.

For discussions with no ID in the url, it would take the url and match it against the Discussion Table (oh speed!)

Any ideas?


  • Options
    charrondevcharrondev Developer Lead (PHP, JS) Montreal Vanilla Staff

    I think you hook on the discussions controller and handle it there. We definitely have controllers that look up by URL slug (I know we have one for categories.

    the thing is you do an add on for that you’ll want to store the slug in the DB in an indexed column.

    There wouldn’t be any performance concerns with that, but you may have uniqueness concerns (what if you have 2 discussions with the same title?)

  • Options

    what if you have 2 discussions with the same title?

    Oh, that will never happen here. All titles are nicely curated, and new ones are rejected if there is an existing match in the DB.

    I think you hook on the discussions controller and handle it there. We definitely have controllers that look up by URL slug (I know we have one for categories.

    Oh wow this is super promising ... I will go digging for how to accomplish this. Perhaps someone will beat me to it.


  • Options

    This was a terribly awesome fun exercise. I did not expect that with just a few lines of code I could implement some hot magic.

    I completely re-fabricated my own url system. Just wowwwwwww!

    Now, to make sure the codes/procedure are thought-through and super efficient and scalable.


    1. In fact absolutely no DiscussionID in the url
    2. No storing of a million route rules in the config.php (my former bane and nightmare)
    3. Fast and true process
    4. I can now have all kinds of blog/article style sites alongside my forum. Some discussions shall have the native url system others shan't.

    What I did, in a tortoise shell...

    1. Created a DiscussionUrl column in Discussion Table
    2. Ran a PHP script to go through (should handle duplicates) all existing Discussions to sanitize/save their urls into the new column using Gdn_Format::url()
    3. Attached a script to discussion beforeSave event to make sure a sanitized url is always saved to the new column - checks and warns for duplicates as well.
    4. Created a new route to point to cleanurl/$1
    class CleanUrlPlugin extends Gdn_Plugin {
    public function rootController_CleanUrl_create($sender, $args) {
        $testDiscussionUrl = $args[1]; //the first in url check order in cleanurl/$1/$2]
        if($discussion = Gdn::sql()->select('*')->from('Discussion')->where('DiscussionUrl', $testDiscussionUrl)->get()->firstRow(DATASET_TYPE_ARRAY)){
            $discussionID = $discussion['DiscussionID'];
            // $finalDestination = 'discussion/' . $testDiscussionID;
            $finalDestination = 'discussion/' . $discussionID;
            return Gdn::dispatcher()->dispatch();

    I will share further thoughts on this ...

  • Options
    R_JR_J Ex-Fanboy Munich Admin

    You have replaced "/discussion/123/some-title" with "/cleanurl/some-title"? I don't understand where there is an improvement. I thought you were aiming for either example.com/discussion/some-title or directly /some-title

    I think "discussion" is preferable over "cleanurl" because the word discussion bears a content related meaning while cleanurl does not and therefore seo wise is inferior

  • Options
    R_JR_J Ex-Fanboy Munich Admin

    You should set an index on the DiscussionUrl column to make searches more efficient.

            ->column('DiscussionUrl', 'varchar(191)', true, 'index')

    And I would cache search results. Do a full text search for "Gdn::cache()->get(" to find examples.

  • Options

    Thanks @R_J yes I already indexed it, as per charrondev's post

    No! cleanurl/ is never seen, or accessed directly by the user, it is just a routing endpoint.

    example.com/whatever/my-fancy-newdiscussion is internally routed to cleanurl/$2

    I have a config setting:

     $c('plugin.DefaultUrlPattern') // defaults to '{categoryName}/{discussionName}/{discussionID}'

    With this pattern I can have this result sitewide (every instance where this change is required is affected)

    1. example.com/anyprefix/some-title/anySuffix
    2. example.com/categoryName/some-title
    3. example.com/123/categoryName-some-title
    4. example.com/some-title
    5. example.com/d/some-title
    6. example.com/some-title.html
    7. example.com/discussion/some-tlte/123
    8. example.com/d/some-title-x.sdfr (where sdfr= is base64encode of the discussion ID like in medium.com)

    Basically, any format thinkable has now become possible.

    I will dig up something about that gdn cache, thanks a lot for that. I need that and every optimization possible, just in case.

  • Options
    edited September 2019

    In the future I plan to make this mimic some other CMS's approach, using a so-called feature called "freeze_url".

    In that case, the Discussion Table will have a column for its frozen url, and the data will be in the pattern such as flexible as {categoryName}/{discussionName}/{discussionID} and the default behavior would be according to a category group setting or the normal Vanilla pattern of discussion/123/some-title

Sign In or Register to comment.