We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
  • I've done several multi-context sites, but always with separate domains. What I'm trying to do now is a little different from that and is confusing me, and doesn't jive exactly with anything I've seen on the forums or RTFM.

    Here's my situation: I've got a site (using FURLs) that will have a new context (basically, a new subsection of content) added to it once a year. The contexts all need to be accessed from the same domain, but I want the different contexts to be initialized based on the first piece of the request_uri. For example...

    domain.com/2012/
    domain.com/2011/
    domain.com/2010/


    ...would load the 2012, 2011 and 2010 contexts, respectively. Additionally, once this is set up, I don't want any additional setup to be required outside of adding context settings when a context is added annually (aka, no .htaccess or plugin editing if at all possible).

    The only other hiccup is that I would like the URLs "domain.com" (no URI) and "domain.com/current/" to always route to the newest context. I'm willing to set a system or context setting to pull this off, but again, no .htaccess or plugin editing.

    Is this possible? I've looked into a gateway plugin, Mark Hamstra's ContextRouter plugin, or a little index.php file hack that I've used in the past, but I can't seem to figure out how to get it working. It may be as simple as incorrect context settings, but if that's the case, I could use some troubleshooting help.

    Any ideas? Thanks!
    • Take a look at this set of plugins which I am working on for this exact purpose. It caches each Context's settings globally and uses this cache to switch contexts based on the first segment of the requested URI (or more accurately, the first segment of the request URI, minus the base_url, i.e. the resource's relative URI).

      https://gist.github.com/2a615d1f22e8618845b2

      I plan on formalizing this into a package which can be used to jump start sites like this. Let me know if you have any questions.
      • Talk about a lucky coincidence! What system events do I attach these to?

        EDIT: Sorry, I see OnSiteRefresh in the description now. I'm still not quite understanding how these work, if we could talk through them a little bit more. [ed. note: aladage last edited this post 11 years, 9 months ago.]
        • The plugin.SubfolderContextMapRouter.php should be attached to OnHandleRequest as it needs to switch contexts dynamically based on the request parameters.

          The plugin.ContextMapRefresh.php should be attached to OnSiteRefresh, and any other events you want to trigger an update to the context_map cache partition that is being used by these plugins. For instance, if you wanted to refresh this map anytime a Context was created or it's settings were edited, you could attach the plugin to OnContextSave (though I prefer to be able to defer the changes until I am ready to clear the entire site cache).

          Hope that helps get you started with it...
          • Oops -- your reply came in right as I was gonna say I got it (mostly...more on that in a sec). Your plugins work great; I just wasn't understanding how SubfolderContextMapRouter worked. Attaching it to OnHandleRequest did the trick. I left ContextMapRefresh on OnSiteRefresh, but switching to OnContextSave is a good idea and might work better in my situation.

            I also didn't have my context settings quite right. For anyone else trying this, they look like this now (using "context2012" as an example):

            base_url: /context2012/
            http_host: domain.com
            site_start: (ID of site start for this context)
            site_url: http://domain.com/context2012/

            However, I still have two issues:

            • The first one might be obvious from my example. I don't want the word "context" in that URL segment; I just want the year. The problem is, MODX won't let me save a context with just a number as its key. I don't really care if the context has to have a prefix in its name, but I'd like to translate that somewhere in the plugins. Could you walk me through where you think the best place is to make that edit?
            • I'm still not sure how to handle lack of segment (just domain.com) or domain.com/current. Suggestions there?
            • Quote from: aladage at Jul 12, 2012, 05:22 PM

              However, I still have two issues:

              • The first one might be obvious from my example. I don't want the word "context" in that URL segment; I just want the year. The problem is, MODX won't let me save a context with just a number as its key. I don't really care if the context has to have a prefix in its name, but I'd like to translate that somewhere in the plugins. Could you walk me through where you think the best place is to make that edit?
              • I'm still not sure how to handle lack of segment (just domain.com) or domain.com/current. Suggestions there?
              * Use a context setting (since they are also cached in the map) to do the matching and you don't need to worry about the limitations of context naming. So when looping do a match on the setting value, say you create a uri_segment setting in each context, instead of matching on the context key...

              line 42 of the router becomes something like:
                              if ($pieces[0] == $cSettings['uri_segment']) {


              * You don't need to handle segments that don't match. I assume those will just be Resources in the main web Context.
              • * Use a context setting (since they are also cached in the map) to do the matching and you don't need to worry about the limitations of context naming. So when looping do a match on the setting value, say you create a uri_segment setting in each context, instead of matching on the context key...

                line 42 of the router becomes something like:
                1
                if ($pieces[0] == $cSettings['uri_segment']) {

                Perfect! So simple. I was trying to work from the base_url, but adding a new context setting is such an obvious answer. Had to tweak my other context settings, obviously, but it works great now.

                * You don't need to handle segments that don't match. I assume those will just be Resources in the main web Context.

                Not exactly. What I'm trying to prevent here is people linking to or bookmarking year-specific URLs, when what they really want is a link on their page that will always link to the current year's information. The year-specific URLs are really just for archiving purposes.

                For example, it's currently 2012 (obviously, haha). The URLs domain.com, domain.com/current and domain.com/2012 all need to point to the same "context2012" context. When the 2013 information rolls out, I want domain.com/2012 to continue pointing at "context2012", but domain.com and domain.com/current need to be switched to a new "context2013" context. I think I see what you were hinting at -- I just always keep the "web" context as the current year's context, and duplicate/change context settings to create the archived version -- but if I go that route, how do I make all of those domains resolve correctly without changing the URLS? domain.com/current and domain.com/2013 may point to the same place, but I can't have domain.com/current auto-change its URL to domain.com/2013 when the page loads, or I defeat my whole purpose of having people link to or bookmark domain.com/current. Sorry if that's a little heady -- I'd be glad to skype or give you access to show you exactly what I mean.

                What I'm thinking is, I create a system setting called "current_context", for example. Then, when looping, I check if $pieces[0] is empty or equals current, and if it does, I send it to the context in that system setting. Would that work, and if so, do you think it's the best method?
                • I'm trying my way, and it's not really working. Well, it's working, but it's still changing the URL to the newest context, and not keeping it as domain.com/current. I think I'm close to a solution there, but not quite.
                  • I figured out a workaround that would be acceptable, but isn't perfect. I basically reversed what I said above, so now the latest context has "current" in all of its context settings instead of the year, and then I've got the latest year as the system setting. What that means in practice is, entering domain.com/2012 reroutes to domain.com/current. All of the other years and current still work fine per the plugin's original looping mechanism. The only thing that I haven't figured out is URLs with no segment. Here's where I'm at so far with the plugin: https://gist.github.com/3100976

                    I'd prefer if the URLs didn't change regardless of entering the specific year, but this will at least get the job done. If you can think of a way to not change URLs, please let me know. Thanks!
                      • 44007
                      • 15 Posts
                      Gents,

                      Sorry to dig up an old thread but I've stumbled across this whilst looking for a solution to a similar problem.
                      I have context switching working as I'd like it (also works nicely when MODx is installed in a subdirectory), thank you both for your input/contributions.

                      The issue I'm having is with static page assets, pulling in Javascript, CSS, images etc with a relative URL. For example, each context has a site_url of the form http://www.site.com/modx/contextName/

                      Static assets common to all contexts live at http://www.site.com/modx/js/ and http://www.site.com/modx/css/ etc. Each context has a setting site_url of the form http://www.site.com/modx/context/.

                      Using
                      <base href="[[++site_url]]" />
                      ensures that hyperlinks work correctly but the relative paths for static assets is then wrong as it's adding the 'virtual' context name to the src path. The only solution I can see is to make references to static assets absolute, but this isn't really an elegant solution and causes problems if I move the MODx installation. Alternatively, I leave site_url to that of the MODx installation and prefix each hyperlink with [[*context_key]].

                      Is this an issue you had to find a solution to? Thanks for any thoughts!