2
votes

A site of mine has a strange behavior. From time to time some of the pages are unpublished without any user interaction.

In the page history there is no entry about any activity. The pages are children of a secured page.

The unpublished pages are not always the same. It varies in what page and in the period.

The apache access files give no information about any access from the outside.

For testing I changed the content of these pages. After waiting a few days one of these pages was unpublished again. The content of this page did not change. So I can exclude the possibility of a nightly recovery of the database by the provider.

How can this be possible?

System: SilverStripe 3.1.12 (CMS/Framework)

2
Hi Patrick, I'm sorry but I've never had an issue like this before. As I can't recreate the issue I can't investigate what the problem might be. Is this happening on a live server or on a local development environment? Are you able to recreate this issue in another environment? - 3dgoo
I can't recreate it too. It only happens on live server. On the local dev env everything is all right. I can't imagine what the problem can be. I run nearly 15 Silverstripe Websites without Problems like these. I think i have to call the Provider. Silverstripe can not be the reason for this issue. - PatrickE
Have you checked that there aren't any cron jobs running that might be the reason? - Olli Tyynelä
When you publish it, check the *_Live table for the record to confirm it is there with the content etc you were intending. When it is randomly unpublished again, do the same check trying to find the same row. At the same time, update a random page that this is not happening to with an extra word or phrase. For me, the only thought that is coming to mind is the DB is going back in time (not even joking). Unless you have some crazy complex or different code, I don't think it is a Silverstripe issue. - Turnerj
Are you sure that you don't' have a workflow module that is publishing and unpublishing? check for fields embargo and expiry with date times - Barry

2 Answers

1
votes

We can use onBeforeUnpublish to notify us of when a page is unpublished to help debug the problem. We do this through a SiteTree extension.

We declare a SiteTree extension in our config.yml file (or an alternative yml file):

SiteTree:
  extensions:
    - SiteTreeExtension

In the extension class we add an onBeforeUnpublish function to email us when ever a page is unpublished:

class SiteTreeExtension extends DataExtension {

    public function onBeforeUnpublish() {

        $member = Member::currentUser();
        $config = SiteConfig::current_site_config();

        $pageEditLink = Director::absoluteBaseURL() . 'admin/pages/edit/show/' . $this->owner->ID;

        $content = '<p>Page has been unpublished</p>';
        $content .= '<p><strong>Page name</strong><br />';
        $content .= '<a href="' . $pageEditLink . '">' . $this->owner->Title . '</a></p>';
        $content .= '<p><strong>Page ID</strong><br />';
        $content .= '<a href="' . $pageEditLink . '">' . $this->owner->ID . '</a></p>';

        if ($member) {
            $memberEditLink = Director::absoluteBaseURL() . 'admin/security/EditForm/field/Members/item/' . $member->ID . '/edit';

            $content .= '<p><strong>Member email</strong><br />';
            $content .= '<a href="' . $memberEditLink . '">' . $member->Email . '</a></p>';
            $content .= '<p><strong>Member ID</strong><br />';
            $content .= '<a href="' . $memberEditLink . '">' . $member->ID . '</a></p>';
        }

        $email = Email::create(
            '[email protected]',
            '[email protected]',
            $config->Title . ' - Page Unpublished',
            $content
        );

        $email->send();
    }

}

In the above code the email content has a log of the page that was unpublished and member that unpublished the page.

This doesn't fix the problem but it should help track and debug the issue.

1
votes

Check that you aren't calling remove() on a DataList, as this will remove a page from the live database (but it stays in draft). If you have this code somewhere, this is where your problem lies. Simply convert the DataList to an ArrayList so that remove() doesn't directly manipulate the database (only your instance of the list).

$pages = DataList::create('YourClassNameHere');
$pages = $pages->toArray();
$pagesArray = new ArrayList($pages);

foreach ($pagesArray as $page) {
    if (your logic here) {
        $pagesArray->remove($page);
    }
}

Or you could use filterByCallback() to manipulate the retrieved DataList without actually editing the data:

$pages = DataList::create('YourClassNameHere');
$pages = $pages->filterByCallback(function($page) { return $page->canView(); });

Hope that helps.