We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 17577
    • 6 Posts
    I posted this in the wrong forum. If a moderator is reading this, can you move this to the correct forum (MODx Community Forums » Development & Coding » In Development).

    Below is an simple enhancement to the 404 Error page using a plug-in and snippet. It makes use of AjaxSearch and Wayfinder add-ons.

    The plug-in is a modified version of the Page-Not-Found Redirector from here (thanks so much!).

    The plug-in will log send a message to the configured users "messages" console in the management. It will then pass the "missing" document ID to the snippet. which will perform a search and present the results on the 404 error page. The Wayfinder snippet provides a simple sitemap.

    The plug-in:
    Description: Redirects a user to the specified 404 page with the parsed URI as a search string. Sends a message to a specified user.
    System Events: OnPageNotFound
    Config: String: &pg=Error Page;int; &mid=Mail To;string;
    $e = &$modx->Event;
    
    switch ($e->name) {
      case "OnPageNotFound":
        if(!$pg) $modx->sendErrorPage();
      else {
      
        //Parse out the requested page.
        $docid = str_replace("/", "", $_SERVER['REQUEST_URI']);
        
        //Determine if the friendly URLS are in use.
        if ($modx->config['friendly_urls'] == 1 && $docid != '') {
        
          //Get the configured friendly URL suffix.
          $docidSuffix = $modx->config['friendly_url_suffix'];
        
          //In order to search for aliases, we need to remove the friendly URL suffix.
          if(stristr($docid,$docidSuffix)) {
            $docid = str_replace($docidSuffix, "", $docid);
          }
        }
      
        if ($mid) {
          //Prepare the message parameters and send the alert.
          $subject = "Page not found";
          $msg = "Someone tried to access document id $docid";
          $modx->sendAlert("Error",$mid,0,$subject,$msg,0);
        }
      
        //Build the URL with the search parameter.
        $url=$modx->makeUrl($pg,'','&AS_search='.$docid);
    	
        //Redirect to the 404 page.	
        $modx->sendRedirect($url);
        exit;
      }
    
      break;
    
      default :
      return; // stop here
      break;
    }
    


    The Snippet:
    Description: Adds a search for missing documents and sitemap to the 404 page.
    Paste the code below into a new snippet. Name the Snippet 404Error
    <?php
    if ($_GET['AS_search'] != '') {
    
      $search = $_GET['AS_search'];
      $response = '<p><strong>The requested page "'.$search.'" could not be found.</strong></p>';
      $response .= '<p>We are sorry, but we could not find the page you were looking for.  The page may have been moved to a new location.</p>';
      $response .= '<p>Below are the results for the closest matches.  A site map has also been provided beneath the match results.</p>';
    
    } else {
    
      $response = '<p><strong>The requested page could not be found.  A site map has also been provided below.</strong></p>';
    
    }
    
    return $response;
    ?>
    


    Your Error Page:
    Copy and paste the code below into the 404 page you have defined in the configuration. (Tools->Configuration. Click the Site Tab. Look in the Error page setting.:
    [!404Error!]
    
    [!AjaxSearch? &AS_showForm=`0` &ajaxSearch=`0` &AS_showResults=`1`!]
    
    <h4>Site Map</h4>
    [[Wayfinder? &startId=`0` &showDescription=`1`]]
    
      It&#39;s never just a game if you&#39;re winning.
      • 27330
      • 884 Posts
      love the idea. however the ajaxsearch returns
      "Please enter a search term to begin your search."

      the sitemap and plugin error text works fine.
        • 17577
        • 6 Posts
        Hmm...

        I’ve changed the plugin slightly. Replaced the $rep with $mid in the parameters:

        The plugin:
        Description: Redirects a user to selected document and sends a message
        System Events: OnPageNotFound
        Config: String: &pg=Error Page;int; &mid=Mail To;string;
        $e = &$modx->Event;
        
        switch ($e->name) {
          case "OnPageNotFound":
            if(!$pg) $modx->sendErrorPage();
          else {
            if ($mid) {
              // send a message to a local account
              $docid = $modx->documentIdentifier;
              $subject = "Page not found";
              $msg = "Someone tried to access document id $docid";
              $modx->sendAlert("Error",$mid,0,$subject,$msg,0);
            }
            $url=$modx->makeUrl($pg,'','&AS_search='.$docid);
            $modx->sendRedirect($url,0,REDIRECT_REFRESH);
            exit;
          }
        
          break;
        
          default :
          return; // stop here
          break;
        }
        


        Make sure you’re copying the entire source above as it is ’trapped’ in the scroll.

        I just tested it on a base install of Modx with Friendly URLs on, and Ajaxsearch 1.8.1 I can’t replicate the problem you’re having. Can you turn on the debug:
        [!ajaxSearch? &AS_showForm=`0` &ajaxSearch=`0` &debug=`3` &AS_showResults=`1`!]

        for ajaxSearch and post the log?
          It&#39;s never just a game if you&#39;re winning.
          • 27330
          • 884 Posts
          [29-Nov-08 10:27:30]  AjaxSearch 1.8.1 - Php5.2.6 - MySql 4.1.25-Debian_mt1
          [29-Nov-08 10:27:30]  AjaxSearch - Configuration file default : 
          <?php
          // For a global parameter initialisation use the following syntax $__param = 'value';
          // To overwrite parameter snippet call use $param = 'value';
          
          // StripInput user function. 
          // Uncomment and complete the core function and choose your own function name
          // string functionName(string searchstring)
          // functionName : name of stripInput function passed as &stripInput parameter
          // searchstring : string php variable name as searchString input value
          // advSearch : string advSearch variable as advSearch parameter and return value
          // return the filtered searchString value
          /*
          function myStripInput($searchString, &$advSearch){
            $advSearch = 'exactphrase';
            return $searchString;
          }
          */
          // StripOutput user function
          // Uncomment and complete the core function and choose your own function name
          // string functionName(string results)
          // functionName : name of stripOutput function passed as &stripOutput parameter
          // results : string php variable name as results
          // return the filtered results
          /*
          function myStripOutput($results){ 
          
            return $results;
          }
          */
          // searchWordList user function
          // Uncomment and complete the core function and choose your own function name
          // string functionName()
          // functionName : name of searchWordList function passed as &searchWordList parameter
          // return a comma separated list of words
          /*function searchWordList($params){ 
          
            switch($params[0]){ 
              case '61':
                $list = "primary,school,education,children,teacher,africa,litteracy,bicycle";
                break;         
              case '62':
                $list = "primaire,école,éducation,enfants,professeur,afrique,littérature,bicyclette";
                break; 
            }
            return $list;
          }
          */
          ?>
          [29-Nov-08 10:27:30]  AjaxSearch - User configuration - Before parameter checking : Array
          (
              [config] => default
              [version] => 1.8.1
              [debug] => 3
              [language] => english
              [ajaxSearch] => 0
              [advSearch] => oneword
              [whereSearch] => content|tv
              [subSearch] => 5,1
              [withTvs] => 
              [order] => publishedon,pagetitle
              [rank] => pagetitle:100,extract
              [minChars] => 3
              [AS_showForm] => 0
              [resultsPage] => 0
              [grabMax] => 10
              [extract] => 1:content,description,introtext,tv_content
              [extractLength] => 200
              [extractEllips] => ...
              [extractSeparator] => <br />
              [formatDate] => d/m/y : H:i:s
              [highlightResult] => 1
              [pageLinkSeparator] =>  | 
              [AS_landing] => 
              [AS_showResults] => 1
              [idType] => parents
              [parents] => 
              [documents] => 
              [depth] => 10
              [hideMenu] => 2
              [hideLink] => 1
              [filter] => 
              [tplLayout] => @FILE:assets/snippets/ajaxSearch/templates/layout.tpl.html
              [tplResults] => @FILE:assets/snippets/ajaxSearch/templates/results.tpl.html
              [tplResult] => @FILE:assets/snippets/ajaxSearch/templates/result.tpl.html
              [tplPaging] => @FILE:assets/snippets/ajaxSearch/templates/paging.tpl.html
              [stripInput] => defaultStripInput
              [stripOutput] => defaultStripOutput
              [searchWordList] => 
              [breadcrumbs] => 0
              [tvPhx] => 0
              [clearDefault] => 0
              [jsClearDefault] => assets/snippets/ajaxSearch/js/clearDefault.js
          )
          
          [29-Nov-08 10:27:30]  AjaxSearch - tplResult template @FILE:assets/snippets/ajaxSearch/templates/result.tpl.html : <div class="[+as.resultClass+]">
            <a class="[+as.resultLinkClass+]" href="[+as.resultLink+]" title="[+as.longtitle+]">[+as.pagetitle+]</a>
          [+as.descriptionShow:is=`1`:then=`
            <span class="[+as.descriptionClass+]">[+as.description+]</span>
          `+]
          [+as.extractShow:is=`1`:then=`
            <div class="[+as.extractClass+]"><p>[+as.extract+]</p></div>
          `+]
          [+as.breadcrumbsShow:is=`1`:then=`
            <span class="[+as.breadcrumbsClass+]">[+as.breadcrumbs+]</span>
          `+]
          </div>
          [29-Nov-08 10:27:30]  AjaxSearch - tplResults template@FILE:assets/snippets/ajaxSearch/templates/results.tpl.html : [+as.noResults:is=`1`:then=`
            <div class="[+as.noResultClass+]">
              [+as.noResultText+]
            </div>
          `:else=`
            <p class="ajaxSearch_resultsInfo">[+as.resultInfoText+]</p>
            [+as.paging+]
            [+as.listResults+]
            [+as.paging+]
          `+]
          [29-Nov-08 10:27:30]  AjaxSearch - tplResult template@FILE:assets/snippets/ajaxSearch/templates/layout.tpl.html : [+as.showForm:is=`1`:then=`
          <form [+as.formId+] action="[+as.formAction+]" method="post">
              <fieldset>
          		<input type="hidden" name="advSearch" value="[+as.advSearch+]" />
              <label for="ajaxSearch_input">
                <input id="ajaxSearch_input" class="cleardefault" type="text" name="search" value="[+as.inputValue+]"[+as.inputOptions+] />
              </label>
              <label for="ajaxSearch_submit">
                <input id="ajaxSearch_submit" type="submit" name="sub" value="[+as.submitText+]" />
              </label>
              </fieldset>
          </form>
          `+]
          [+as.showIntro:is=`1`:then=`
          <p class="ajaxSearch_intro" id="ajaxSearch_intro">[+as.introMessage+]</p>
          `+]
          [+as.showResults:is=`1`:then=`
          [+as.results+]
          `+]
          
          
            • 17577
            • 6 Posts
            It appears that [tt]$modx->documentIdentifier[/tt] now only works with integers.
            So, if I entered a non-existent URL of http://mysite.com/111 the plug-in would pass the search string using the [tt]$modx->documentIdentifier[/tt].
            But, if I entered http://mysite.com/oldpage.html the [tt]$modx->documentIdentifier[/tt] wouldn’t pass the string (oldpage.html).

            It would return a string in the production site I was using, but in my dev site, only integers would be passed as search strings. Weird.

            I’ve scrapped the [tt]$modx->documentIdentifier[/tt], and parsed the requested page using the [tt]REQUEST_URI[/tt].
            Here is the change to the plugin that is working on my dev site. Hope this helps. Thanks for the feedback.

            Plugin change:
            $e = &$modx->Event;
            
            switch ($e->name) {
              case "OnPageNotFound":
                if(!$pg) $modx->sendErrorPage();
              else {
                if ($mid) {
                  // send a message to a local account
                  $docid = curPageName();
                  $subject = "Page not found";
                  $msg = "Someone tried to access document id $docid";
                  $modx->sendAlert("Error",$mid,0,$subject,$msg,0);
                }
                $url=$modx->makeUrl($pg,'','&AS_search='.$docid);
                $modx->sendRedirect($url);
                exit;
              }
            
              break;
            
              default :
              return; // stop here
              break;
            }
            
            function curPageName() {
              $curPage = str_replace("/", "", $_SERVER['REQUEST_URI']);
              return $curPage;
            }
            
              It&#39;s never just a game if you&#39;re winning.
              • 27330
              • 884 Posts
              Sorry Ltd, same results. maybe it’s my env and someone else will get it working. can be great enhancement for 404 indeed. can’t wait to see more feedback from others.

              mind posting a screenshot how it look on your dev box?
                • 17577
                • 6 Posts
                You can try it on the dev site here.

                Enter a phony URL:
                http://www.travisdahlgren.com/1234.html or http://www.travisdahlgren.com/modx

                or a URL to an existing page that is out of the structure:
                http://www.travisdahlgren.com/menus.html

                I’ve also updated the plugin to parse out .html so that searches will match aliases.

                Plug-in:
                $e = &$modx->Event;
                
                switch ($e->name) {
                  case "OnPageNotFound":
                    if(!$pg) $modx->sendErrorPage();
                  else {
                  
                    //Parse out the requested page.
                    $docid = str_replace("/", "", $_SERVER['REQUEST_URI']);
                    
                    //Determine if the friendly URLS are in use.
                    if ($modx->config['friendly_urls'] == 1 && $docid != '') {
                    
                      //Get the configured friendly URL suffix.
                      $docidSuffix = $modx->config['friendly_url_suffix'];
                    
                      //In order to search for aliases, we need to remove the friendly URL suffix.
                      if(stristr($docid,$docidSuffix)) {
                        $docid = str_replace($docidSuffix, "", $docid);
                      }
                    }
                  
                    if ($mid) {
                      //Prepare the message parameters and send the alert.
                      $subject = "Page not found";
                      $msg = "Someone tried to access document id $docid";
                      $modx->sendAlert("Error",$mid,0,$subject,$msg,0);
                    }
                  
                    //Build the URL with the search parameter.
                    $url=$modx->makeUrl($pg,'','&AS_search='.$docid);
                	
                    //Redirect to the 404 page.	
                    $modx->sendRedirect($url);
                    exit;
                  }
                
                  break;
                
                  default :
                  return; // stop here
                  break;
                }
                
                  It&#39;s never just a game if you&#39;re winning.
                  • 27330
                  • 884 Posts
                  looks neat. did anyone else try it yet?

                  BTW I was thinking I saw something like this before, I even asked about it here couple weeks ago. http://modxcms.com/forums/index.php?topic=29460.0

                  :)

                    • 17577
                    • 6 Posts
                    Thanks.

                    The plug-in is tested on 0.9.6.2 with Ajaxsearch 1.8.1 for those that need to know.

                    I think it would benefit to have the plug-in search against the current aliases and forward the page if a match is found. If it couldn’t find the match, produce the search results page.

                    The messages could also do with some sort of filtering as they produce messages from all site 404 errors generated by the server (css, js, malformed URLS, etc). Fills up the inbox quickly.

                    Stay tuned grin

                      It&#39;s never just a game if you&#39;re winning.
                      • 20413
                      • 2,877 Posts
                      So it works either with numbers (ids) or aliases but not both way?


                      Well, Thanks for sharing this!  smiley

                        @hawproductions | http://mrhaw.com/

                        Infograph: MODX Advanced Install in 7 steps:
                        http://forums.modx.com/thread/96954/infograph-modx-advanced-install-in-7-steps

                        Recap: Portland, OR (PDX) MODX CMS Meetup, Oct 6, 2015. US Bancorp Tower
                        http://mrhaw.com/modx_portland_oregon_pdx_modx_cms_meetup_oct_2015_us_bancorp_tower