We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 9130
    • 171 Posts
    I’m rewriting parts of the TXNewsletters module and need to render the a page html to a variable (as a string) in order to send it out as email. Currently the code is using file_get_contents (with a curl based patch available) but I would like to do it internally in order to have more control over the process and implement some newsletter personalization.
    I’ve read the API and the Document Parser source but could not figure out how to do it.

    I’d appreciate any help.
      • 10449
      • 956 Posts
      I’m not familiar with that module, but you could easily use chunks with placeholders for your HTML, or documents too.

      Useful API functions might be:

      http://wiki.modxcms.com/index.php/API:getChunk
      http://wiki.modxcms.com/index.php/API:parseChunk
      http://wiki.modxcms.com/index.php/API:getPlaceholder
      http://wiki.modxcms.com/index.php/API:getDocumentObject

      Maybe you can even use the getField snippet or Ditto to retrieve document content, but I’m not sure if they work in a module (inside the manager).
        • 9130
        • 171 Posts
        Quote from: ganeshXL at Apr 12, 2009, 09:58 AM

        I’m not familiar with that module, but you could easily use chunks with placeholders for your HTML, or documents too.

        Useful API functions might be:

        http://wiki.modxcms.com/index.php/API:getChunk
        http://wiki.modxcms.com/index.php/API:parseChunk
        http://wiki.modxcms.com/index.php/API:getPlaceholder
        http://wiki.modxcms.com/index.php/API:getDocumentObject

        Maybe you can even use the getField snippet or Ditto to retrieve document content, but I’m not sure if they work in a module (inside the manager).
        I’m already using getChunk/parseChunk where appropriate but in this case I need the html of the full page - template, contents, snippets, chunks and everything.

        I could get things to work by adding a plugin but it’s inefficient and the ways of getting module<->plugin communication to work seem like ugly hacks that should not be necessary.
          • 3806
          • 6 Posts
          Hi,

          I had the same problem with an implementation of a custom sidebar module, where I needed to embed a separate document including template into the main document. My solution was to inherit from the DocumentParser to create a custom parser that created a rendered page including the template. You can see it in action on http://www.tnmcoaching.com/index.php?id=269.

          Currently my solution does not handle snippets properly, but I think it is an issue with the number of passes that my custom parser does. However this it not a problem currently for me, so I won’t look into this issue.
          Include the following code, for instance in document.parser.class.inc.php and then you can get a page by calling.


          parser = new SidebarParser( $modx->db , $id );
          $page = $parser->executeParser();
          


          where id is the id of the page that you want to render.

          Let me know if it works.

          Cheers, Niels


          
          class SidebarParser extends DocumentParser {
          
          	public $mDocId = "";
          
              function SidebarParser( $db , $docId ) {
                  $this->db = $db;
                  $this->mDocId = $docId;
                  //echo $this->mDocId;
          		$this->dbConfig= & $this->db->config; // alias for backward compatibility
                  $this->jscripts= array ();
                  $this->sjscripts= array ();
                  $this->loadedjscripts= array ();
                  // events
                  $this->event= new SystemEvent();
                  $this->Event= & $this->event; //alias for backward compatibility
                  $this->pluginEvent= array ();
                  // set track_errors ini variable
                  @ ini_set("track_errors", "1"); // enable error tracking in $php_errormsg
              }
          
          
          	
          
          function getDocumentMethod() {  
          		return "id"; 
          	} 
          	
          	function getDocumentIdentifier($method) { 
          		return $this->mDocId;  
          	}
          
            
          
              function prepareResponse() {
          
          	//echo "prepare";
          
                  // we now know the method and identifier, let's check the cache
                  $this->documentContent= $this->checkCache($this->documentIdentifier);
                  
          
          	//echo "prepare2";
          
          	  /*if ($this->documentContent != "") {
                      // invoke OnLoadWebPageCache  event
                      $this->invokeEvent("OnLoadWebPageCache");
                  } else {*/
                      // get document object
                      //echo $this->documentMethod . $this->documentIdentifier;
          
          		$this->documentObject= $this->getDocumentObject($this->documentMethod, $this->documentIdentifier);
          
                      // write the documentName to the object
                      $this->documentName= $this->documentObject['pagetitle'];
          
                      // validation routines
                      if ($this->documentObject['deleted'] == 1) {
                          	//echo "error";
          
          			$this->sendErrorPage();
                      }
          
          		//echo "template fetch";
          
                      // get the template and start parsing!
                      if (!$this->documentObject['template'])
                          $this->documentContent= "[*content*]"; // use blank template
                      else {
                          $sql= "SELECT * FROM " . $this->getFullTableName("site_templates") . " WHERE " . $this->getFullTableName("site_templates") . ".id = '" . $this->documentObject['template'] . "';";
                          $result= $this->dbQuery($sql);
                          $rowCount= $this->recordCount($result);
                          if ($rowCount > 1) {
                              $this->messageQuit("Incorrect number of templates returned from database", $sql);
                          }
                          elseif ($rowCount == 1) {
                              $row= $this->fetchRow($result);
                              $this->documentContent= $row['content'];
                          }
                      //}
          
                      // invoke OnLoadWebDocument event
                      //$this->invokeEvent("OnLoadWebDocument");
          
          		//echo "before parse";
          		//echo $this->documentContent;
                      // Parse document source
                      $this->documentContent = $this->parseDocumentSource($this->documentContent);
          		
          		//echo $this->documentContent;
          
                      // setup <base> tag for friendly urls
                      //			if($this->config['friendly_urls']==1 && $this->config['use_alias_path']==1) {
                      //				$this->regClientStartupHTMLBlock('<base href="'.$this->config['site_url'].'" />');
                      //			}
                  }
                /*  
          	register_shutdown_function(array (
                      & $this,
                      "postProcess"
                  )); // tell PHP to call postProcess when it shuts down
          */
                  //$this->outputContent();
                  //$this->postProcess();
              }
          
          
            function sendForward($id, $responseCode= '') {
                  if ($this->forwards > 0) {
                      $this->forwards= $this->forwards - 1;
                      $this->documentIdentifier= $id;
                      $this->documentMethod= 'id';
                      $this->documentObject= $this->getDocumentObject('id', $id);
                      //if ($responseCode) {
                      //    header($responseCode);
                      //}
                      $this->prepareResponse();
                      //exit();
                  } else {
                      //header('HTTP/1.0 500 Internal Server Error');
                      //die('<h1>ERROR: Too many forward attempts!</h1><p>The request could not be completed due to too many unsuccessful forward attempts.</p>');
                  }
              }
          
          
              function executeParser() {
                  //error_reporting(0);
                  if (version_compare(phpversion(), "5.0.0", ">="))
                      set_error_handler(array (
                          & $this,
                          "phpError"
                      ), E_ALL);
                  else
                      set_error_handler(array (
                          & $this,
                          "phpError"
                      ));
          
                  $this->db->connect();
          
                  // get the settings
                  if (empty ($this->config)) {
                      $this->getSettings();
                  }
          
                  // IIS friendly url fix
                  if ($this->config['friendly_urls'] == 1 && strpos($_SERVER['SERVER_SOFTWARE'], 'Microsoft-IIS') !== false) {
                      $url= $_SERVER['QUERY_STRING'];
                      $err= substr($url, 0, 3);
                      if ($err == '404' || $err == '405') {
                          $k= array_keys($_GET);
                          unset ($_GET[$k[0]]);
                          unset ($_REQUEST[$k[0]]); // remove 404,405 entry
                          $_SERVER['QUERY_STRING']= $qp['query'];
                          $qp= parse_url(str_replace($this->config['site_url'], '', substr($url, 4)));
                          if (!empty ($qp['query'])) {
                              parse_str($qp['query'], $qv);
                              foreach ($qv as $n => $v)
                                  $_REQUEST[$n]= $_GET[$n]= $v;
                          }
                          $_SERVER['PHP_SELF']= $this->config['base_url'] . $qp['path'];
                          $_REQUEST['q']= $_GET['q']= $qp['path'];
                      }
                  }
          
                  // check site settings
          	/*        
          if (!$this->checkSiteStatus()) {
                      header('HTTP/1.0 503 Service Unavailable');
                      if (!$this->config['site_unavailable_page']) {
                          // display offline message
                          $this->documentContent= $this->config['site_unavailable_message'];
                          $this->outputContent();
                          exit; // stop processing here, as the site's offline
                      } else {
                          // setup offline page document settings
                          $this->documentMethod= "id";
                          $this->documentIdentifier= $this->config['site_unavailable_page'];
                      }
                  } else {*/
                      // make sure the cache doesn't need updating
                      $this->checkPublishStatus();
          
                      // find out which document we need to display
                      $this->documentMethod= $this->getDocumentMethod();
                      $this->documentIdentifier= $this->getDocumentIdentifier($this->documentMethod);
                  //}
          
                  if ($this->documentMethod == "none") {
                      $this->documentMethod= "id"; // now we know the site_start, change the none method to id
                  }
                  if ($this->documentMethod == "alias") {
                      $this->documentIdentifier= $this->cleanDocumentIdentifier($this->documentIdentifier);
                  }
          
                  if ($this->documentMethod == "alias") {
                      // Check use_alias_path and check if $this->virtualDir is set to anything, then parse the path
                      if ($this->config['use_alias_path'] == 1) {
                          $alias= (strlen($this->virtualDir) > 0 ? $this->virtualDir . '/' : '') . $this->documentIdentifier;
                          if (array_key_exists($alias, $this->documentListing)) {
                              $this->documentIdentifier= $this->documentListing[$alias];
                          } else {
                              $this->sendErrorPage();
                          }
                      } else {
                          $this->documentIdentifier= $this->documentListing[$this->documentIdentifier];
                      }
                      $this->documentMethod= 'id';
                  }
          
                  // invoke OnWebPageInit event
                  $this->invokeEvent("OnWebPageInit");
          
                  // invoke OnLogPageView event
                  if ($this->config['track_visitors'] == 1) {
                      $this->invokeEvent("OnLogPageHit");
                  }
          
                  $this->prepareResponse();
          
          	return $this->documentContent;
              }
          
          
          
          }
          
          
            • 22303 MODX Staff
            • 10,725 Posts
            As an aside, this is something that MODx 2.0.0 (a.k.a. Revolution) provides easily via the new OO API, e.g.
            <?php
            // Get a MODx Resource by id
            $resource = $modx->getObject('modResource', 12);
            
            // See modResponse::outputContent() for additional details/ideas
            // Process and return the cacheable content of the Resource
            $output = $resource->process();
            
            // Determine how many passes the parser should take at a maximum
            $maxIterations= intval($modx->getOption('parser_max_iterations', $scriptProperties, 10));
            
            // Process the non-cacheable content of the Resource, but leave any unprocessed tags alone
            $modx->parser->processElementTags('', $output, true, false, '[[', ']]', array(), $maxIterations);
            
            // Process the non-cacheable content of the Resource, this time removing the unprocessed tags
            $modx->parser->processElementTags('', $output, true, true, '[[', ']]', array(), $maxIterations);
            
            // Use the $output however you like...
            ?>

            You can also do similar things (and much more) with any kind of Element, from a Template Variable to a Chunk to a Snippet.
            NOTE: In MODx 2.0+, Documents are referred to as Resources (as in "web resources", since they can represent more than just Documents, i.e. web services, AJAX connectors, etc.).
              • 10378
              • 375 Posts
              Quote from: opengeek at Jun 10, 2009, 09:46 PM
              As an aside, this is something that MODx 2.0.0 (a.k.a. Revolution) provides easily via the new OO API, e.g.
              <!--?php
              // Get a MODx Resource by id
              $resource = $modx--->getObject('modResource', 12);
              
              // See modResponse::outputContent() for additional details/ideas
              // Process and return the cacheable content of the Resource
              $output = $resource->process();
              
              // Determine how many passes the parser should take at a maximum
              $maxIterations= intval($modx->getOption('parser_max_iterations', $scriptProperties, 10));
              
              // Process the non-cacheable content of the Resource, but leave any unprocessed tags alone
              $modx->parser->processElementTags('', $output, true, false, '[[', ']]', array(), $maxIterations);
              
              // Process the non-cacheable content of the Resource, this time removing the unprocessed tags
              $modx->parser->processElementTags('', $output, true, true, '[[', ']]', array(), $maxIterations);
              
              // Use the $output however you like...
              ?>

              You can also do similar things (and much more) with any kind of Element, from a Template Variable to a Chunk to a Snippet.
              NOTE: In MODx 2.0+, Documents are referred to as Resources (as in "web resources", since they can represent more than just Documents, i.e. web services, AJAX connectors, etc.).

              Hi Jason,

              we just tried to use your script to render a simple resource to a variable and it works perfect - except that an embedded getResources snippets isn't processed! The getResources call simply is replaced with an empty string.

              How can we force the script to also render snippets?

              We also had a look at your renderResources snippet - but we can't find a reference on how to do this.

              Could you please give us a hint?

              Thanks in advance,
              Martin
                Freelancer @bitego http://www.bitego.com
                ---
                GoodNews - one of the most advanced and integrated Group Mailer premium add-ons for MODX Revolution!
                More infos here: http://www.bitego.com/extras/goodnews/
                • 22303 MODX Staff
                • 10,725 Posts
                The code in renderResources should do it. If it is not rendering via renderResources, then it's probably not possible due to script dependencies. You can attempt to solve those dependencies, as renderResources does with setting things like $modx->resourceIdentifier and $modx->resource to match the Resource you are processing.
                  • 10378
                  • 375 Posts
                  Quote from: opengeek at Dec 08, 2012, 07:45 AM
                  The code in renderResources should do it. If it is not rendering via renderResources, then it's probably not possible due to script dependencies. You can attempt to solve those dependencies, as renderResources does with setting things like $modx->resourceIdentifier and $modx->resource to match the Resource you are processing.

                  Thank you Jason,

                  I will have a second look at renderResources.

                  Greetings,
                  Martin
                    Freelancer @bitego http://www.bitego.com
                    ---
                    GoodNews - one of the most advanced and integrated Group Mailer premium add-ons for MODX Revolution!
                    More infos here: http://www.bitego.com/extras/goodnews/