We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 14638
    • 14 Posts
    Hello,
    We have a plugin that listens for the OnDocPublished (and OnDocUnpublished) event and updates a custom table with the published doc info. It works fine when a document is published adhoc, but when a Publish Date is set, the event doesn’t fire when the document publishes itself at the specified time.

    Is there another event that fires when a document goes from unpublished to published through the Publish Date functionality, or is this something that could be updated in ModX to fire the OnDocPublished event?
      • 3749
      • 24,544 Posts
      I’m afraid not. What’s needed is to move OnDocPublished into the resource->save() code so it will always fire (since there’s no way to change the published status without saving the resource).
        Did I help you? Buy me a beer
        Get my Book: MODX:The Official Guide
        MODX info for everyone: http://bobsguides.com/modx.html
        My MODX Extras
        Bob's Guides is now hosted at A2 MODX Hosting
        • 14638
        • 14 Posts
        Thank you Bob for looking into this. I’ll file a bug report.
          • 14638
          • 14 Posts
            • 14915
            • 43 Posts
            Hello Bob,

            do you know where the resource->save() code is located? Thanks.
              • 3749
              • 24,544 Posts
              core/model/modx/modresource.class.php

              Unless you add your own code there, you’ll want to add something like this:

              $modx->invokeEvent('OnDocPublished',array(
                  'docid' => $resource->get('id'),
                  'id' => $resource->get('id'),
                  'resource' => &$resource,
              ));


              But it will have to fire only when the pub status is changing from unpublished to published. I’m not sure how well that will work in that location. See the ActivationEmail plugin which does something similar with user activation because OnActivateUser never actually fires.

              One potential problem is that the code above is already in the core/model/modx/processors/resource/publish.php file so there’s a chance that the event will fire twice in some circumstances. I’m not sure if the processor code is ever called, however. It may just be there for future use. Not to mention the usual warnings against altering the core code.
                Did I help you? Buy me a beer
                Get my Book: MODX:The Official Guide
                MODX info for everyone: http://bobsguides.com/modx.html
                My MODX Extras
                Bob's Guides is now hosted at A2 MODX Hosting
                • 14915
                • 43 Posts
                Hi Bob,

                the main post scheduling function seems to happen in the checkPublishStatus() function in core/model/modx/modrequest.class.php:

                /**
                     * Checks the current status of timed publishing events.
                     * @todo refactor checkPublishStatus...offload to cachemanager?
                     */
                    public function checkPublishStatus() {
                        $cacheRefreshTime= 0;
                        if (file_exists($this->modx->getOption(xPDO::OPT_CACHE_PATH) . "sitePublishing.idx.php"))
                            include ($this->modx->getOption(xPDO::OPT_CACHE_PATH) . "sitePublishing.idx.php");
                        $timeNow= time() + $this->modx->getOption('server_offset_time',null,0);
                        if ($cacheRefreshTime != 0 && $cacheRefreshTime <= $timeNow) {
                            /* FIXME: want to find a better way to handle this publishing check without mass updates to the database! */
                            $tblResource= $this->modx->getTableName('modResource');
                            if (!$result= $this->modx->exec("UPDATE {$tblResource} SET published=1,publishedon={$timeNow} WHERE pub_date < {$timeNow} AND pub_date > 0")) {
                                $this->modx->log(modX::LOG_LEVEL_ERROR, 'Error while refreshing resource publishing data: ' . print_r($this->modx->errorInfo(), true));
                            }
                            if (!$result= $this->modx->exec("UPDATE $tblResource SET published=0,publishedon={$timeNow} WHERE unpub_date < {$timeNow} AND unpub_date IS NOT NULL AND unpub_date > 0")) {
                                $this->modx->log(modX::LOG_LEVEL_ERROR, 'Error while refreshing resource unpublishing data: ' . print_r($this->modx->errorInfo(), true));
                            }
                            if ($this->modx->getCacheManager()) {
                                $this->modx->cacheManager->clearCache();
                            }
                            $timesArr= array ();
                            $sql= "SELECT MIN(pub_date) AS minpub FROM $tblResource WHERE pub_date>$timeNow AND pub_date IS NOT NULL";
                            if (!$result= $this->modx->query($sql)) {
                                $this->modx->log(modX::LOG_LEVEL_ERROR, "Failed to find publishing timestamps\n" . $sql);
                            } else {
                                $result= $result->fetchAll(PDO::FETCH_ASSOC);
                                $minpub= $result[0]['minpub'];
                                if ($minpub != null) {
                                    $timesArr[]= $minpub;
                                }
                            }
                            $sql= "SELECT MIN(unpub_date) AS minunpub FROM $tblResource WHERE unpub_date>$timeNow AND unpub_date IS NOT NULL";
                            if (!$result= $this->modx->query($sql)) {
                                $this->modx->log(modX::LOG_LEVEL_ERROR, "Failed to find publishing timestamps\n" . $sql);
                            } else {
                                $result= $result->fetchAll(PDO::FETCH_ASSOC);
                                $minunpub= $result[0]['minunpub'];
                                if ($minunpub != null) {
                                    $timesArr[]= $minunpub;
                                }
                            }
                            if (count($timesArr) > 0) {
                                $nextevent= min($timesArr);
                            } else {
                                $nextevent= 0;
                            }
                            $fp= @ fopen($this->modx->getOption(xPDO::OPT_CACHE_PATH) . "sitePublishing.idx.php", "wb");
                            if ($fp) {
                                @ flock($fp, LOCK_EX);
                                @ fwrite($fp, "<?php \$cacheRefreshTime=$nextevent; ?>");
                                @ flock($fp, LOCK_UN);
                                @ fclose($fp);
                            }
                        }
                    }
                


                It would be nice for this code to fire the appropriate event for each document that is published or un-published here. Since documents are published or unpublished en-masse, we’d first have to retrieve a list of post that would be modified, and fire the appropriate event for each, and then run an update for each.

                This function seems to be called on every page request, which is not very efficient. It would be better to separate post scheduling into a cron-job.
                  • 3749
                  • 24,544 Posts
                  As you can see from the "todo" and "fix me" comments, this is slated for refactoring at some point.

                  The cron job idea is a good one, but I don’t think there’s any way for MODx to set up a cron job on install and many users wouldn’t know how to do it in their own.

                  The problem is that users can set a future publish date on resources and the code to implement that has to run fairly often.

                  I also think that putting the OnDocPublished event here would miss documents that are published manually in the Manager (using various methods) and new documents created as already published either in the Manager or in code. That’s why I suggested putting it in the resource->save() function. Any document that is having its status changed from unpublished to published has to be saved.
                    Did I help you? Buy me a beer
                    Get my Book: MODX:The Official Guide
                    MODX info for everyone: http://bobsguides.com/modx.html
                    My MODX Extras
                    Bob's Guides is now hosted at A2 MODX Hosting