Skip to Content search facebook instagram pinterest twitter youtube

Preview system

SproutCMS's built-in preview system, useful for admin forms which will store data to be displayed on the front end, has been described as being simultaneously a brilliant and a horrible idea.

The way it works is this:

  1. Data is submitted via a POST form (usually the add or edit form for a ManagedAdminController of some sort, e.g. PageAdminController)
  2. Temporary database tables are created and populated with content needed to render the preview, by a nifty hack which changes the database table name prefix from sprout_ to something random.
  3. The POSTed data are saved into the temporary tables using the controller's _editSave method
  4. The normal front-end display method is called to render the preview (e.g. PageController::view)

The good thing about this method is that there's no need to write specific code to handle previews for each bit of data which can be previewed - which would usually be done by mangling the $_POST data into formats expected by the preview. The bad thing is that if the view includes data from a wide variety of sources, much data will need to be temporarily duplicated in step 2, making it a computationally intensive procedure. Generally this isn't a problem, but it could be if there are many admins making frequent edits which need previewing. It wouldn't be suitable for implementing a popular wiki, for instance.

Making it work

Add a preview button

The first thing you need to do is add a preview button to the add/edit form. If you're using a ManagedAdminController, all you need to do is update that controller's _getEditSubActions method to include an action called _preview with a URL to a preview method (to be written next), as per the following example:

modules/Example/Controllers/Admin/ExampleAdminController.php

public function _getEditSubActions($item_id)
{
    $actions = parent::_getEditSubActions($item_id);
    $actions['_preview'] = "admin/call/{$this->controller_name}/preview/{$item_id}";
    return $actions;
}

Handle the preview submission

This preview method handles the above submission. The Preview helper sets up of the temporary tables which provide the preview functionality. Here's an example:

modules/Example/Controllers/Admin/ExampleAdminController.php

public function preview($item_id)
{
    $tables = [
        'example_table1' => 0,
        'example_table2' => 1,
        'example_table3' => ['active' => 1],
    ];
    Preview::load($this, $tables, $item_id);
 
    $front_end = new ExampleController();
    Preview::run($front_end, 'view', [$item_id]);
}

The Preview::load call must specify ALL the tables into which data will be saved. Any tables not specified will have data overwritten. The amount of data duplicated depends on the conditions supplied for each table as described in the API docs.

Once the POST data for the preview has been saved, the preview can be run via Preview::run with the appropriate front-end view method. Typically the names of the admin and front-end controllers align, e.g. ExampleAdminController and ExampleController.

Special considerations

If the _editSave method of the relevant ManagedAdminController performs additional actions, such as sending emails, setting session messages or redirecting to another URL, these will have to be disabled somehow when the preview method calls _editSave. One way is to simply set a class attribute in_preview to false, and checking that attribute in the _editSave method:

modules/Example/Controllers/Admin/ExampleAdminController.php

public function preview($item_id)
{
	$this->is_preview = true;
 
	// ... as per the earlier example
}
 
 
public function _editSave($item_id)
{
	// validation etc. goes here
 
	if (empty($this->is_preview)) {
		Notification::confirm('Record saved');
		$this->sendEmails($item_id);
		Url::redirect('some/url');
	}
}