Easy 'Under Construction' pages for SilverStripe sites

For if you've ever been in the situation where you've developed a SilverStripe site for a client and now they want to review it before making it live - but you don't have a staging server set up. What you usually want to do is give the client full access to their website, but prevent the public from viewing the unfinished product. [ad#Half Banner] This simple technique is perfect for those situations. It lets you deliver a static HTML 'Under Construction' page to the general public, but if an admin user is logged in, the 'Under Construction' page disappears and the admin user can browse the site as normal. Additionally the 'Under Construction' page is served up with a 503 - Service Unavailable HTTP response status code.

IMPORTANT! Don't waste your time doing this yourself

When you can just use this small module (only 4 files including the README!) I've already created. To enable the 'Under Construction' page you just have to install the module by dropping the module folder ('underconstruction') into the root of your SilverStripe install and then running a /dev/build. The 'Under Construction' page is generated for you and is immediately enabled but to enable the 'Under Construction' page you need to tick the checkbox in the SiteConfig Access tab. To remove the maintenance page and put the site live properly, just remove the module folder or preferably just untick the checkbox in the SiteConfig Access tab. How to do it yourself anyway...

Creating the 'Under Construction' page

To create a quick maintenance page we can take advantage of Page::requireDefaultRecords() and the ErrorPage class. The requireDefaultRecords() function is going to be called when we run /dev/build, it is going to use the ErrorPage class to create a static HTML error page called 'error-503.html' in the assets folder. If the 'error-503.html' page is ever deleted, all you have to do is run /dev/build again to regenerate it. Alternatively, you could create your own 'error-503.html' page with perhaps your agency branding and a nice 'Under Construction' message and dump that into the /assets folder to use instead. Here is the basic code that you can drop in to your Page class. As you can see a lot has been borrowed from the ErrorPage::requireDefaultRecords() function:

function requireDefaultRecords() {
  
  parent::requireDefaultRecords();
  
  // Ensure that an assets path exists before we do any error page creation
	if(!file_exists(ASSETS_PATH)) {
		mkdir(ASSETS_PATH);
	}

	$pageUnderConstructionErrorPage = DataObject::get_one('ErrorPage', "\"ErrorCode\" = '503'");
	$pageUnderConstructionErrorPageExists = ($pageUnderConstructionErrorPage && $pageUnderConstructionErrorPage->exists()) ? true : false;
	$pageUnderConstructionErrorPagePath = ErrorPage::get_filepath_for_errorcode(503);
	if(!($pageUnderConstructionErrorPageExists && file_exists($pageUnderConstructionErrorPagePath))) {
		if(!$pageUnderConstructionErrorPageExists) {
			$pageUnderConstructionErrorPage = new ErrorPage();
			$pageUnderConstructionErrorPage->ErrorCode = 503;
			$pageUnderConstructionErrorPage->Title = _t('UnderConstruction.TITLE', 'Under Construction');
			$pageUnderConstructionErrorPage->Content = _t('UnderConstruction.CONTENT', '<p>Sorry, this site is currently under construction.</p>');
			$pageUnderConstructionErrorPage->Status = 'New page';
			$pageUnderConstructionErrorPage->write();
			$pageUnderConstructionErrorPage->publish('Stage', 'Live');
		}

		// Ensure a static error page is created from latest error page content
		$response = Director::test(Director::makeRelative($pageUnderConstructionErrorPage->Link()));
		if($fh = fopen($pageUnderConstructionErrorPagePath, 'w')) {
			$written = fwrite($fh, $response->getBody());
			fclose($fh);
		}

		if($written) {
			DB::alteration_message('503 error page created', 'created');
		} else {
			DB::alteration_message(sprintf('503 error page could not be created at %s. Please check permissions', $pageUnderConstructionErrorPagePath), 'error');
		}
	}
}

Serving up the 'Under Construction' page to non admin users

Displaying the maintenance page is fairly straight forward, you just need a snippet like the one below in your Page_Controller::init() method to essentially check if an admin user is logged in (or is trying to log in).

if (!Permission::check('ADMIN') 
    && strpos($_SERVER['REQUEST_URI'], '/admin') === false 
    && strpos($_SERVER['REQUEST_URI'], '/Security') === false) {
  Debug::friendlyError(503);
  exit;
}

But isn't there already a module that solves the same problem?

Yes there is, but its shit compared to this new one. So use this one instead.

Updates

I have updated this module so that there is a convenient way to turn 'Under Construction' pages on or off via the CMS, there is now a checkbox in the SiteConfig->Access tab that CMS users can tick depending on whether the under construction page should be shown or not.