We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 34162
    • 1 Posts
    Hi folks,

    as a bloody newbie I tried to write a module which replaces pages by switching their ids.
    Reason: Sometimes I want to edit the content of some pages without unpublishing the current version (no "instant-publishing" wanted, due to work-time restrictions and approval-issues),
    and I want to publish the changed pages without changing the document ids, since I use TVs which refer to a document via its ID.
    Now - here’s my "not-even-alpha" code. It works, which means, it does indeed switch the ids, and the result is as needed: new content at the old place - but there’s a nice collection of problems left:
    1. it pops up a runtime-error, claiming that "srcpg" or "trgpg" respectively are not valid indices. No idea why, since it uses these params properly.
    2. I have no idea how to terminate the module’s execution correctly, i.e. returning to the previous view and redrawing the document-tree.
    3. It looks extremely ugly - how can I use all that css, which makes the appearance of the form a real pleasure in the event-log view - compared to the original?

    So, any help or hints for a clueless newbie would be highly appreciated... tongue

    $opcode = isset($_POST['opcode']) ? $_POST['opcode']:'';
    $src = $_POST['srcpg'];
    $trg = $_POST['trgpg'];
    
    
    // action directive
    switch($opcode) 
    {
    case 'verify':
    // verify code here
    echo 'verify action '.$src.' '.$trg.'<br />';
    $s = $modx->getDocument($src);
    $t = $modx->getDocument($trg);
    
    $sql = "SELECT MAX(id) FROM ".$modx->getFullTableName("site_content");
    $result = $modx->db->query($sql);
    $row = $modx->fetchRow($result);
    $maxID = $row['MAX(id)']+1;
    echo 'next id: '.$maxID;
    $sql = "UPDATE ".$modx->getFullTableName("site_content")." SET id = ".$maxID." WHERE id = ".$src;
    $result = $modx->db->query($sql);
    print_r ($result);
    $sql = "UPDATE ".$modx->getFullTableName("site_content")." SET id = ".$src." WHERE id = ".$trg;
    $result = $modx->db->query($sql);
    $sql = "UPDATE ".$modx->getFullTableName("site_content")." SET id = ".$trg." WHERE id = ".$maxID;
    $result = $modx->db->query($sql);
    break;
    
    
    
    default: // display module page
    echo '<html>';
    echo '<head></head>';
    echo '<body>';
    echo '<script language="JavaScript" type="text/javascript">';
    echo ' function postForm(opcode){';
    echo ' document.module.opcode.value=opcode;';
    echo ' document.module.submit();';
    echo ' }';
    echo '</script>';
    echo '<form name="module" method="post">';
    echo '<input name="opcode" type="hidden" value="" />';
    echo '<h1>Replace Page</h1>';
    echo '<h3>replace Pages by switching their IDs</h3>';
    echo 'Source: <input title="Source" name="srcpg" type="text" size="10" value="" />';
    echo 'Target: <input title="Target" name="trgpg" type="text" size="10" value="" />';
    echo '<hr />';
    echo '<a href="javascript:;" onclick="postForm(\'verify\');return
    false;">Replace</a>'; 
    echo '<a href="javascript:;" onclick="postForm(\'\');return
    false;"> </a>'; 
    echo '</form>';
    echo '</body>';
    echo '</html>';
    break;
    
    } 
      • 26435
      • 1,193 Posts
      cool idea man! laugh
      thanks for posting that.

      -sD-
        Husband, Father, Brother, Son, Programmer, Atheist, Nurse, Friend, Lover, Fighter.
        All of the above... in no specific order.


        I send pointless little messages
        • 10487 MODX Staff
        • 1,535 Posts
        Hi ppaul,

        Good start you’ve made on the module. smiley To answer some of your questions:

        1. Check for the existence of the $_POST variables for srcpg and trgpg when assigning them to variables at the source of the module.
        $src = isset($_POST['srcpg']) ? $_POST['srcpg'] : false;
        $trg = isset($_POST['trgpg']) ? $_POST['trgpg'] : false;


        You can have some error-checking before trying use them as well if you wanted an extra level of validation:
        if ($srcpg && $trgpg) {
          $s = $modx->getDocument($src);
          $t = $modx->getDocument($trg);
        
          ... rest of code ...
        }


        2. What I would do in this situation is to output either a success or failure at the end of the update routine and then have a link back to the first screen. The link back is just something that would result in the default case of the switch statement being executed, eg:

        echo '<form name="module" method="post">';
        echo '<input name="opcode" type="hidden" value="" />';
        echo '<a href="javascript:;" onclick="postForm(\'firstpage\');return false;">Back</a>'; 
        echo '</form>';


        Here is an example of a link that would refresh the document tree:
        <a href="javascript:;" onclick="parent.menu.updateTree();">Refresh Tree</a>


        You could use the javascript from the onclick event above and use it in the onload event of the <body> tag if you have detected that an update has been made (by checking for the opcode ’firstpage’ from above):
        <body onload="parent.menu.updateTree();">


        3. Check out one of my existing modules (Document Template Changer or Polls module) and see how I’ve used the modx css in them to style the output - it will be easier than me making a hash of explaining it here smiley

        Hope that helps,
        Garry

          Garry Nutting
          Senior Developer
          MODX, LLC

          Email: [email protected]
          Twitter: @garryn
          Web: modx.com
          • 10487 MODX Staff
          • 1,535 Posts
          Oh, one more thing I just thought about is that you may need to sychronise the cache as well. wink

          The code below will do that, call it after you have finished the SQL updates:
          // sychronise the cache
          $basePath = $modx->getConfig('base_path');
          include_once $basePath."manager/processors/cache_sync.class.processor.php";
          $sync = new synccache();
          $sync->setCachepath($basePath."assets/cache/");
          $sync->setReport(false);
          $sync->emptyCache();
            Garry Nutting
            Senior Developer
            MODX, LLC

            Email: [email protected]
            Twitter: @garryn
            Web: modx.com
            • 34162
            • 1 Posts
            GREAT! 1 post in the forum may save hours of trial and error wink
            Thanks a lot to all who replied, esp. Garry for his in-depth examples and explanations.

            ppaul
              • 34162
              • 1 Posts
              Sorry that I have to come back to this topic with some more questions:
              1. Since I use that <form> elements, print_r ($variable) does not render any output any more, making debugging a real pain. Why is this?
              2. I do not want to do too much error-checking here, but I do want to check the ->getDocument call for success. How can I check, whether getDocument returned a valid document-handle or not? I found no way to look into the vars I assign the results of this call to.
              $s = $modx->getDocument($src);

              What contains $s in the case of success, respectively in the case of failure (i.e. $src not being a valid docID)??
              As far as I can see MODx does no error-checking of this type. It just throws an error-event if it cannot parse code due to syntax-errors.
              But there are more kinds of errors than missing ";" rolleyes
              3. I guess my first module will undermine the user-access-rights, so do I have to deal with this stuff too?
                • 34162
                • 1 Posts
                Thanks to BBEdit I can trace the different functions of the manager.
                And what do I find for "getDocument"?
                1. By default it displays only published documents. Strange, since there are of course operations also on unpublished documents.
                (And that’s why my variables stayed empty as mentioned in my previous post >:() The replacepage-module I have in mind will usually replace a published page with an unpublished one.
                As far as I understand it the "published" param has only two values: 1 for published and 0 for unpublished - but what if I want all documents, regardless of their published-status??
                2. "getDocument" itself calls "getDocuments" (I would have expected it to be just the other way round laugh)
                3. "getDocuments" adds some other parameters, creates a join with document_groups, checks permissions and calls:
                4. "dbQuery" which translates itself to db->query, so it is here where my module jumps in, omitting all permission-restrictions! That’s not exactly what I intended... shocked but that’s most likely why this function is recommended for "internal use only"...
                5. "query" does some db-logging, calls mysql_query and pops out an error-message if there is one.

                Hmm, having seen this I’m happy to know that this will be rewritten.
                But what to do in the meantime?

                And I still have no answer to my initial question: How can I detect whether the ID param passed to "getDocument" is valid??
                As far as I can see now, the destination variable remains plain empty if: a doc with the ID does not exist or exists but is not published.
                So I will have to work on level "4" mentioned above. I wonder how anyone (except the foundation members) have ever managed to write a module. Well, there aren’t so many at all, guess now I know why...
                  • 34162
                  • 1 Posts
                  So: here we go:
                  // ###########################################
                  // ReplacePage                                  #
                  // ###########################################
                  // Replaces a page (target) with another one (source) by switching their IDs and keeps the published state of the target.
                  // Useful if you have made copies of published pages for further editing
                  // and want to publish the edited versions without changing the id,
                  // since a different id would make it necessary to edit all TV values using this id
                  // like @document bindings.
                  // This module does not respect user access-rights (not my fault, really!)
                  // so be careful providing executing rights for this module!
                  // For questions or comments look for "ppaul" in the modx-forums 
                  // feel free to use and improve this module
                  // according to your needs! 
                  
                  $opcode = isset($_POST['opcode']) ? $_POST['opcode']:'';
                  $src = isset($_POST['srcpg']) ? $_POST['srcpg'] : false;
                  $trg = isset($_POST['trgpg']) ? $_POST['trgpg'] : false;
                  $tb_prefix = $modx->db->config['table_prefix'];
                  $theme = $modx->db->select('setting_value', $tb_prefix . 'system_settings', 'setting_name=\'manager_theme\'', '');
                  $theme = $modx->db->getRow($theme);
                  $theme = ($theme['setting_value'] <> '') ? $theme['setting_value'] : 'MODx';
                  $error = '';
                  
                  
                  // action directive
                  switch($opcode) 
                  {
                  case 'replace':
                  // verify page existence
                  $errmsg = false;
                  $succmsg = false;
                  $sql = 'SELECT id, pagetitle, published FROM '.$modx->getFullTableName("site_content").' WHERE id = '.$src;
                  $result = $modx->db->query($sql);
                  $srow = $modx->fetchRow($result);
                  if ($srow['id'] == '')
                  {$errmsg = 'page '.$src.' does not exist!';}
                  else
                  {$succmsg = $srow['pagetitle'].' was replaced by ';}
                  $sql = 'SELECT id, pagetitle, published FROM '.$modx->getFullTableName("site_content").' WHERE id = '.$trg;
                  $result = $modx->db->query($sql);
                  $trow = $modx->fetchRow($result);
                  if ($trow['id'] == '')
                  {$errmsg .= '<br />page '.$trg.' does not exist!';}
                  else
                  {$succmsg .= '<br />'.$trow['pagetitle'];}
                  
                  echo '<html>';
                  echo '<head>';
                  echo '<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/style.css" />';
                  echo '<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/coolButtons2.css" />';
                  echo '</head>';
                  echo '<body style="margin:30px" onload="parent.menu.updateTree()";>';
                  if (!$errmsg)
                  {
                  $sql = "SELECT MAX(id) FROM ".$modx->getFullTableName("site_content");
                  $result = $modx->db->query($sql);
                  $row = $modx->fetchRow($result);
                  $maxID = $row['MAX(id)']+1;
                  // exchange the ids
                  $sql = "UPDATE ".$modx->getFullTableName("site_content")." SET id = ".$maxID." WHERE id = ".$src;
                  $result = $modx->db->query($sql);
                  $sql = "UPDATE ".$modx->getFullTableName("site_content")." SET id = ".$src." WHERE id = ".$trg;
                  $result = $modx->db->query($sql);
                  $sql = "UPDATE modx_site_content SET id = ".$trg." WHERE id = ".$maxID;
                  $result = $modx->db->query($sql);
                  // exchange the published state too
                  $sql = "UPDATE ".$modx->getFullTableName("site_content")." SET published = ".$srow['published']." WHERE id = ".$src;
                  $result = $modx->db->query($sql);
                  $sql = "UPDATE ".$modx->getFullTableName("site_content")." SET published = ".$trow['published']." WHERE id = ".$trg;
                  $result = $modx->db->query($sql);
                  echo $succmsg;
                  }
                  else
                  {echo $errmsg;}
                  
                  echo '<br /><form name="back" method="post"><input type="submit" name="back" value="Back" /></form>';
                  
                  echo '</body>';
                  echo '</html>';
                  break;
                  
                  
                  case 'verify':
                  
                  $sql = 'SELECT id, pagetitle FROM '.$modx->getFullTableName("site_content").' WHERE id = '.$src;
                  $result = $modx->db->query($sql);
                  $row = $modx->fetchRow($result);
                  if ($row['id'] == '')
                  {echo 'page '.$src.' does not exist!';}
                  else
                  {echo $row['pagetitle'];}
                  $sql = 'SELECT id, pagetitle FROM '.$modx->getFullTableName("site_content").' WHERE id = '.$trg;
                  $result = $modx->db->query($sql);
                  $row = $modx->fetchRow($result);
                  if ($row['id'] == '')
                  {echo 'page '.$trg.' does not exist!';}
                  else
                  {echo $row['pagetitle'];}
                  
                  break;
                  
                  default: // display module page
                  
                  
                  echo '<html>';
                  echo '<head>';
                  echo '<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/style.css" />';
                  echo '<link rel="stylesheet" type="text/css" href="media/style/' . $theme . '/coolButtons2.css" />';
                  echo '<script language="JavaScript" type="text/javascript">';
                  echo ' function postForm(opcode){';
                  echo ' document.module.opcode.value=opcode;';
                  echo ' document.module.submit();';
                  echo ' }';
                  echo '</script>';
                  echo '</head>';
                  echo '<body style="margin:80px">';
                  echo '<form name="module" method="post">';
                  echo '<input name="opcode" type="hidden" value="" />';
                  echo '<h1>Replace Page</h1>';
                  echo '<h3>replace Pages by switching their IDs</h3>';
                  echo 'Source ID: <input title="Source" name="srcpg" type="text" size="10" value="" />';
                  echo 'Target ID: <input title="Target" name="trgpg" type="text" size="10" value="" />';
                  echo '</form><br /> (hint: source is usually unpublished, target is usually published)';
                  echo '<hr />';
                  echo '<a href="javascript:;" onclick="postForm(\'replace\');return
                  false;"><input type="submit" name="replace" value="Replace" onclick="postform(\'replace\');return false;" /></a>';
                  echo '</form>';
                  echo '</body>';
                  echo '</html>';
                  break;
                  
                  } 

                  This is, I guess, the best I could do. And the code could be shorter and more elegant, but then also more dense and more difficult to deal with.
                  I will put this into the download repository, since I think it’s doing a useful job and provides a little help for the missing versioning-features of MODx 0.9
                    • 7923
                    • 4,213 Posts
                    Great work Paul! Congrats on your first module! looking forward to see many more in the future wink


                      "He can have a lollipop any time he wants to. That's what it means to be a programmer."
                      • 34162
                      • 1 Posts
                      Thanks doze!
                      I’ll try my best in the future.
                      and Boom...!
                      laugh