On March 26, 2019 we launched new MODX Forums. Please join us at the new MODX Community Forums.
Subscribe: RSS
  • Hello all. Prepare for a book here. It's longer than I anticipated.

    Using Revolution (2.2.4-pl) I recently started developing a redesign based on an existing site on Evolution (1.0.4). Long before I got to this point, I knew I wanted to utilize contexts in Revolution. In all of the research I did in implementing contexts, most everything seemed to be about a different implementation I was looking for – until I found this thread.

    After spending a little time understanding the suggestions in a post by user "bitbox" I was able to engineer a method to achieve what I was after.



    The existing site that I am working from has several "versions" using what we'll call "pseudo-subdirectories". I use this term as there are no physical directories, but friendly URLs based on the document structure in the site tree. Each version is intended for users based in a different locale. Example site tree:


    ROOT
    |
    +-- Site Start
    +-- United States (us)
    +-- Canada (ca)
    +-- Puerto Rico (pr)


    Each country has it's own Modx container (alias in parenthesis above) and is accessed by using the URLs: www.domain.com/us, www.domain.com/ca, www.domain.com/pr. I also have created a built-in redirection using GeoIP to direct users to the proper "version". This is in the form of a Snippet which is called from the document "Site Start".

    I want to follow the same structure in the site tree for Revolution, but keep each countries version within it's own context. While this all might sound similar to those using Babel for multi-lingual sites, the difference is that only the content differs from site to site. I am using English as the language across the board.



    I learned that making this work with with Revolution could be done in a number of different ways. I think I spent enough time to figure out a solid approach while taking into account the factors of complexity in configuration, analytics, search engine optimization, etc.

    Here is a conceptual flow for ways the site would be accessed:

    Scenario A

    • Visitor accesses site at root level: "www.domain.com"
    • Touches file ".htaccess", no rules for this, redirected to "index.php?q=$1"
    • Touches file "index.php" and loads site at default context (web)
    • Touches custom plugin for routing traffic, no rules for this, redirected to site start document for context "web"
    • Loads site start document for context "web".
    • Document is configured as "Weblink", redirected to site start document for context "us"

    Scenario B

    • Visitor accesses site at location specific level: "www.domain.com/us"
    • Touches file ".htaccess", specific rules for path "/us", redirected to "index.php?c=$1&q=$2"
    • Touches file "index.php?c=us" and loads site at default context (web)
    • Touches custom plugin for routing traffic, specific rules for country "us", switches to context "us"
    • Loads site start document for context "us"



    So, what did I have to create/modify?

    • Apache file for site/virtual host (required for using GeoIP, optional otherwise)
    • Apache file ".htaccess"
    • Modx Contexts for each unique site
    • Custom Modx snippet for routing traffic to contexts

    That's it. I didn't have to create physical directories or duplicate any aspect of Modx. The real magic happens with the ".htaccess" file and the custom snippet I created.

    This method can also be used with multiple top-level domains, independent or simultaneously of the "pseudo-subdirectories". [ed. note: thomasgrant last edited this post 7 years, 11 months ago.]
    • Configuring Modx Revolution with Multiple Contexts using Pseudo-subdirectories

      I've included as many comments as I could to make this easy to follow for those with beginner-to-medium experience. Depending on your environment, additional/alternate configuration may be required in using GeoIP properly. Such an example would be in a hosted environment with Plesk.

      I think it would make most sense to beginners to configure in the following order:

      • Apache file for site/virtual host (required for using GeoIP, optional otherwise)
      • Apache file ".htaccess"
      • Custom Modx snippet for routing traffic to contexts
      • Modx Contexts for each "pseudo-subdirectory or unique TLD

      If anyone needs assistance with using my method, feel free to contact me.

      Apache file for site/virtual host
      # GeoIP API/database
      <IfModule mod_geoip.c>
        GeoIPEnable On
        GeoIPDBFile "/var/lib/GeoIP/GeoIP.dat"
      </IfModule>
      


      Apache file ".htaccess"
      # Modx Friendly URLs (other contexts)
      #
      # To allow for proper context switching using pseudo-subdirectories, use the following 
      # rules in addition to the default rule. Parameters will need to match the settings 
      # within the Gateway plugin.
      #
      # Global favicon.ico file; for all contexts
      RewriteCond %{HTTP_HOST} ^www.domain.com [NC]
      RewriteRule ^(us|ca|pr)/favicon.ico$ favicon.ico [QSA,L]
      #
      # Global assets directory; for all contexts
      RewriteCond %{HTTP_HOST} ^www.domain.com [NC]
      RewriteRule ^(us|ca|pr)/assets(.*)$ assets$2 [QSA,L]
      #
      # An additional parameter for the country will be written to the URL
      # c -> the requested context
      # q -> the requested page alias (default)
      #
      # ex. www.domain.com/us/contact -> www.domain.com/index.php?c=us&q=contact
      RewriteCond %{HTTP_HOST} ^www.domain.com [NC]
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteRule ^(us|ca|pr)/?(.*)$ index.php?c=$1&q=$2 [QSA,L]
      #
      #
      # Modx Friendly URLs (web context)
      #
      # ex. www.domain.com/404 -> www.domain.com/index.php?q=404
      RewriteCond %{REQUEST_FILENAME} !-d
      RewriteCond %{REQUEST_FILENAME} !-f
      RewriteRule ^(.*)$ index.php?q=$1 [QSA,L]
      


      Custom Snippet for Context Routing

      NOTE: System Event "OnHandleRequest" for this plugin MUST be enabled.
      
      // If current context IS NOT "mgr"
      if ($modx->context->get('key') != 'mgr') {
      
        // Which domain is being used
        switch ($modx->getOption('http_host')) {
      
          // If "www.microsite.com" is being used
          case 'www.microsite.com':
      
            // Assign name of context for this domain to a variable
            $context = 'microsite';
      
            /* Fallback if "site_url" system setting is not defined for context */
      
              // Get existing value of system setting "site_url" for this context
              $editSetting = $modx->getObject('modContextSetting', array('context_key' => $context, 'key' => 'site_url'));
      
              // Set new value to http://www.domain.com/
              // "{url_scheme}" is equal to either "http://" or "https://"
              // "{http_host}" is equal to top-level domain name without path or trailing slash
              $editSetting->set('value', '{url_scheme}{http_host}' .  '/');
      
              // Save new value to database
              $editSetting->save();
      
            // Refresh cache, only of settings for this context
            $refreshOptions = array('context_settings' => array('contexts' => array($context)));
            $modx->cacheManager->refresh($refreshOptions);
      
            // Switch to this context
            $modx->switchContext($context);
      
            break;
      
          // If "www.domain.com" is being used
          default:
      
            // Which "pseudo-subdirectories" is being used
            switch ($_REQUEST['c']) {
      
              // www.domain.com/us
              case 'us':
                $modx->switchContext('us');
                break;
      
              // www.domain.com/ca
              case 'ca':
                $modx->switchContext('ca');
                break;
      
              // www.domain.com/pr
              case 'pr':
                $modx->switchContext('pr');
                break;
      
              // www.domain.com
              default:
                $modx->switchContext('web');
                break;
            }
      
            // Unset parameter "c"
            unset($_GET['c']);
        }
      }
      


      Context Settings for Pseudo-subdirectories

      Setting: Site URL

      • Key: site_url
      • Name: Site URL
      • Value: {site_url}us/

      Setting: Base URL

      • Key: base_url
      • Name: Base URL
      • Value: {base_url}us/

      Setting: Language

      • Key: cultureKey
      • Value: en

      Setting: Site Start

      • Key: site_start
      • Value: (document id here)

      Context Settings for Unique TLD

      Setting: Site URL

      • Key: site_url
      • Name: Site URL
      • Value: {url_scheme}www.microsite.com/

      Setting: Base URL

      • Key: base_url
      • Name: Base URL
      • Value: {base_url}

      Setting: Language

      • Key: cultureKey
      • Value: en

      Setting: Site Start

      • Key: site_start
      • Value: (document id here)

      That's it folks. [ed. note: thomasgrant last edited this post 7 years, 11 months ago.]
      • I realize that I did not yet include details necessary to utilize GeoIP when routing to contexts. I have not yet added this to my own code as I am still developing this into my site redesign.

        I expect to share the additional information for this within the next day or two.
        • Quote from: nklsf at Jul 08, 2010, 01:53 PM
          What i want to achieve: Having several document trees, seperated by contexts... the approach worked fine untill i have to use makeUrl for php need

          To make generated url (makeURL or ~) consistent across context, I found that changing system setting link_tag_scheme to full solve the problem. Don't forget to set site_url as {site_url}SUBCONTEXT/ in each additional context. For example:


          • {site_url}fr/ for French
          • {site_url}id/ for Bahasa

          Instead of using plugin as mentioned earlier in this thread, we also could use physical folder to route the request to specific context. For example, create "fr" folder and copy 2 files: index.php and .htaccess files from MODx root directory.

          *** note: do not use both approach, use only plugin or folder approach ***

          Make some changes to fr/index.php
          //line 38 -> change @include(dirname(__FILE__) . '/config.core.php');
          @include(dirname(dirname(__FILE__)) . '/config.core.php');
          //line 68 -> change $modx->initialize('web');
          $modx->initialize('fr');
          


          Make some changes to fr/.httacces. We only need 5 lines below:
          RewriteEngine On
          RewriteBase /fr/
          RewriteCond %{REQUEST_FILENAME} !-d
          RewriteCond %{REQUEST_FILENAME} !-f
          RewriteRule ^(.*)$ index.php?q=$1 [L,QSA]
          


          Cheers,
          *) I'm using MODx 2.2.5-pl Traditional [ed. note: lokamaya last edited this post 7 years, 7 months ago.]
            zaenal.lokamaya