Editing CMS pages and static pages in Magento is getting easier all the time. The inclusion of a WYSIWYG editor in the Enterprise Edition and also version 1.4 of the Community edition, makes the process a lot easier.
However, if you have a lot of changes to make, then using a web interface to do them can be slow and time consuming.
Wouldn’t it be good if you could open a CMS page or static block in an external HTML editor and when you hit ‘Save’ the page is updated in Magento automatically?
Impossible?
No. Here’s how – using Incron.
Incron is your friend
Incron is a system level tool that is a lot like cron, apart from the fact that the events that it triggers are not based upon time, but instead are based upon file system events occurring.
So with cron you can have the system run a command every 5 minutes, or at 06:30AM every morning. That’s useful, but Incron takes a different approach.
Instead, you can have Incron run a command when a file in a folder is updated. This is the key to our system.
Installing Incron
Installation is straightforward. If you are using CentOS, for example, simply run:
yum install incron
Once installed, run:
service incrond start chkconfig incrond on
You now have Incron installed, started and configured to load automatically when your system boots.
Configuring Incron
If you are used to editing crontabs, then Incron will be straightforward. I’m not intending to document that in great detail, but it suffices to say that:
incrontab -e
works the same as
crontab -e
For our purposes with this project, each entry in your incrontab file consists of the following elements:
cms_folder_path IN_CLOSE_WRITE path_to_php_executable -f path_to_trigger_file $#
Our solution needs two entries – one for your CMS pages and another for your CMS static blocks. So a typical incrontab file could look like:
/path_to_web_root/var/cms/pages IN_CLOSE_WRITE /usr/local/sbin php -f /path_to_web_root/var/cms_trigger_pages.php $# /path_to_web_root/var/cms/blocks IN_CLOSE_WRITE /usr/local/sbin php -f /path_to_web_root/var/cms_trigger_blocks.php $#
It’s important to use the file folder paths when creating Incron entries. The $# entry at the end of each line is important. This passes the name of the file that Incron detects has changed through to the cms_trigger_*.php file.
The Magento side – building the local files
Configuring Magento is also fairly straightforward. There are essentially three components: a script to output the CMS pages/blocks as static text files, a script that updates changes in these files back to Magento and a folder to store the files.
Before we go too much further, it’s worth pointing out that we’re not advocating this as the most secure solution and we certainly wouldn’t recommend having this live on your production server.
The script cms_update.php is a standalone script that can be run from either the command line or, if its located in the correct place, from your web browser.
If you are running it from the command line use:
php -f cms_update.php
When it runs it scans through Magento’s CMS pages and static blocks and creates a files locally on your server in one of two folders – one for pages and the other for blocks. Each file is uniquely named and contains the CMS content from Magento. The file name contains the database ID number of the page/block and the content’s title.
Each time cmd_update.php is run it simply overwrites the files in those folders with whatever content is in Magento at the time.
Accessing the files
With your CMS pages and static blocks now existing as real files on your remote server, the trick is updating these remotely so that Incron’s events are triggered.
Whilst you could do this by downloading a file locally, changing it and then re-uploading it – thus overwriting the original and triggering Incron, this is not the most user friendly or transparent method.
Instead, we recommend an SFTP client that enables you to map a remote SFTP login to a Windows, Linux or Mac drive. We particularly link ExpanDrive (www.expandrive.com). This comes in Windows or Mac versions.
So your remote server (including your CMS file directories) now appear on your local system as a new share. You can then use an local HTML or text editor to open the remote files and edit them.
Then, when you save the document this is transparently uploaded and changed on the remote server, thus triggering Incron.
So we have achieved local editing of CMS pages and blocks with automatic updates back into Magento. The results are instantaneous, so you can literally hit Save in your text editor and then reload the page in your web browser to see the results. If you are doing CMS content updates, it’s a massive time saver.
cms_update.php
<?php
require_once('app/Mage.php');
Mage::app('');
// Root directory
$root_folder='var/cms/';
// Check folder exists
if (!is_dir($root_folder.'pages')) {
mkdir($root_folder);
}
if (!is_dir($root_folder.'blocks')) {
mkdir($root_folder);
}
// Do pages
$cmspages=Mage::getModel('cms/page')->getCollection();
foreach ($cmspages as $cms) {
$filepath=$root_folder.'pages/'.$cms->getid().'_'.$cms->identifier.'.txt';
$fh=fopen($filepath,'w');
fwrite($fh,$cms->getcontent());
fclose($fh);
}
// Do blocks
$cmsblocks=Mage::getModel('cms/block')->getCollection();
foreach ($cmsblocks as $block) {
$filepath=$root_folder.'blocks/'.$block->getid().'_'.$block->identifier.'.txt';
$fh=fopen($filepath,'w');
fwrite($fh,$block->getcontent());
fclose($fh);
}
?>Done.
cms_trigger_blocks.php
<?php
require_once('app/Mage.php');
Mage::app('');
// Root directory
$root_folder='/path_to_web_root/var/cms/blocks';
$filename=$argv[1];
// Read new content
$filepath=$root_folder.'/'.$filename;
$fh=fopen($filepath,'r');
$cms_content=fread($fh, filesize($filepath));
fclose($fh);
// Extract CMS ID
$tmp=explode('_',$filename);
$cms_id=$tmp[0];
// Get page stores
$read = Mage::getSingleton('core/resource')->getConnection('core_read');
$select = $read->select()
->from('cms_block_store')
->where('cms_block_store.block_id=?', $cms_id);
$result = $read->fetchAll($select);
$stores=array();
foreach ($result as $store)
{
$stores[]=$store[store_id];
}
$cmspage=Mage::getModel('cms/block')
->load($cms_id);
$cmspage->setstores($stores);
$cmspage->setcontent($cms_content);
$cmspage->save();
?>
cms_trigger_pages.php
<?php
require_once('app/Mage.php');
Mage::app('');
// Root directory
$root_folder='/path_to_web_root/html/store/var/cms/pages';
$filename=$argv[1];
// Read new content
$filepath=$root_folder.'/'.$filename;
$fh=fopen($filepath,'r');
$cms_content=fread($fh, filesize($filepath));
fclose($fh);
// Extract CMS ID
$tmp=explode('_',$filename);
$cms_id=$tmp[0];
// Get page stores
$read = Mage::getSingleton('core/resource')->getConnection('core_read');
$select = $read->select()
->from('ontapcms_page_store')
->where('ontapcms_page_store.page_id=?', $cms_id);
$result = $read->fetchAll($select);
$stores=array();
foreach ($result as $store)
{
$stores[]=$store[store_id];
}
$cmspage=Mage::getModel('cms/page')
->load($cms_id);
$cmspage->setstores($stores);
$cmspage->setcontent($cms_content);
$cmspage->save();
?>
What it doesn’t do yet
Whilst this is an entirely usable system, there are a number of improvements that could be made. These include:
- At the moment, once cms_update.php is run, any changes to the CMS pages/blocks in the admin panel are not reflected to the files being used. You’d have to run the script again to ensure that the files were the most up to date. Therefore, a small extension could be written for use during development that contains an observer to monitor CMS pages/blocks being created and modified in the admin panel. This would then cause an updated file to be created in our /var/cms/ folder structure.
- Remote creation of CMS pages or blocks is not currently possible. So you still need to go into Magento to create a page first before it can be edited externally.
- Security. There are certainly some improvements to be made to security. IP locking and, of course, SFTP access control should be exercised in any case – but the cms_trigger.php script should probably do some of its own checking somewhere along the line.
- More content. In theory, you could extend the same functionality to include product descriptions, giving a rich and easy to manipulate CMS environment more suited to development/store builders.











