Posted by

Add custom field to CMS page

To add a custom field to CMS page we will use Magento event mechanism. You can see all events here.

We need to make a module to extend the functionality of CMS page model. We will name it Flexishore_Cms. Add file named Flexishore_Cms.xml to the app/etc/modules directory. Add the folowing content:

<?xml version="1.0"?>
<config>
    <modules>
        <Flexishore_Cms>
            <active>true</active>
            <codePool>local</codePool>
        </Flexishore_Cms>
    </modules>
</config>

Magento is now aware of new module. Now we can create the module itself, which must be located in the app/code/local/Flexishore/Cms directory. Inside this directory, create an etc directory and to file config.xml add this content:

<?xml version="1.0"?>
<config>
    <modules>
        <Flexishore_Cms>
            <version>0.1.0</version>
        </Flexishore_Cms>
    </modules>
 
    <global>
 
        <models>
            <cms>
                <class>Flexishore_Cms_Model</class>
            </cms>
        </models>
 
        <resources>
            <cms_setup>
                <setup>
                    <module>Flexishore_Cms</module>
                    <class>Mage_Catalog_Model_Resource_Eav_Mysql4_Setup</class>
                </setup>
                <connection>
                    <use>core_setup</use>
                </connection>
            </cms_setup>
            <cms_write>
                <connection>
                    <use>core_write</use>
                </connection>
            </cms_write>
            <cms_read>
                <connection>
                    <use>core_read</use>
                </connection>
            </cms_read>
        </resources>
 
    </global>
 
    <adminhtml>
        <events>
 
            <cms_page_prepare_save>
                <observers>
                    <flexishore_cms_save_page>
                        <type>singleton</type>
                        <class>cms/observer_cms</class>
                        <method>savePage</method>
                    </flexishore_cms_save_page>
                </observers>
            </cms_page_prepare_save>
 
            <adminhtml_cms_page_edit_tab_main_prepare_form>
                <observers>
                    <flexishore_cms_prepare_form>
                        <type>singleton</type>
                        <class>cms/observer_cms</class>
                        <method>prepareForm</method>
                    </flexishore_cms_prepare_form>
                </observers>
            </adminhtml_cms_page_edit_tab_main_prepare_form>
 
        </events>       
 
    </adminhtml>
 
</config>

We have added 2 custom observers which will be used to handle our new attribute. To make it work create new file called Cms.php in app/code/local/Flexishore/Cms/Model/Observer directory. It must contain 2 methods : prepareForm and savePage

Method prepareForm is responsible for adding our new attribute to existing form.

/**
 * Add image field to form
 *
 * @param Varien_Event_Observer $observer
 *
 * @return void
 */
public function prepareForm(Varien_Event_Observer $observer)
{
    $form = $observer->getEvent()->getForm();
 
    $fieldset = $form->addFieldset(
        'image_fieldset',
        array(
             'legend' => 'Image',
             'class' => 'fieldset-wide'
        )
    );
 
    $fieldset->addField('background', 'image', array(
        'name' => 'background',
        'label' => 'Background image',
        'title' => 'Background image'
    ));
}

Method savePage is responsible for saving custom background image on server in media/background directory

/**
 * Save background image
 *
 * @param Varien_Event_Observer $observer
 *
 * @return void
 */
public function savePage(Varien_Event_Observer $observer)
{
    $model = $observer->getEvent()->getPage();
    $request = $observer->getEvent()->getRequest();
 
    if (isset($_FILES['background']['name']) && $_FILES['background']['name'] != '') {
        $uploader = new Varien_File_Uploader('background');
 
        $uploader->setAllowedExtensions(array('jpg','jpeg','gif','png'));
        $uploader->setAllowRenameFiles(false);
        $uploader->setFilesDispersion(false);
 
        // Set media as the upload dir
        $media_path  = Mage::getBaseDir('media') . DS . 'background' . DS;
 
        // Set thumbnail name
        $file_name = 'cms_';
 
        // Upload the image
        $uploader->save($media_path, $file_name . $_FILES['background']['name']);
 
        $data['background'] = 'background' . DS . $file_name . $_FILES['background']['name'];
 
        // Set thumbnail name
        $data['background'] = $data['background'];
        $model->setBackground($data['background']);
    } else {
        $data = $request->getPost();
        if($data['background']['delete'] == 1) {
            $data['background'] = '';
            $model->setBackground($data['background']);
        } else {
            unset($data['background']);
            $model->setBackground(implode($request->getPost('background')));
        }
    }
}

We are almost done now, but we need to add missing attribute to database. To do this, create sql directory in app/code/local/Flexishore/Cms. After that we have to add new file called mysql-install-0.1.0.php with this content:

<?php
/**
 * Flexishore Sunvalley module
 *
 * @category    Flexishore
 * @package     Flexishore_Cms
 * @author      Kos Rafał <rafal.k@flexishore.com>
 * @copyright  Copyright (c) 2011 Flexishore http://flexishore.com
 */
 
$installer = $this;
$setup = new Mage_Eav_Model_Entity_Setup('core_setup');
$installer->startSetup();
 
$installer->run('
  ALTER TABLE  `cms_page` ADD  `background` VARCHAR( 255 ) NULL;
');
 
$installer->endSetup();

After all you should see this on CMS edit page:

Source code of module : https://github.com/Flexishore/flexishore-examples

22 thoughts on “Add custom field to CMS page

  1. Exactly what I was looking for. Worked perfectly. It really sucks that you have to alter the cms_page table in order to expand the power of pages though. Really makes it seem like pages was a complete afterthought.

  2. Thank you @Rafal,

    I used your approach and for sure it saved the day,
    but got problem with uploading the image.

    I resolved it and would like to share about it here.

    Your approach works really well expect when we have
    field which type is “file”. The problem comes from, that
    the generated cms page add / edit form doesn’t have


    'enctype' = 'multipart/form-data'

    It is obvious, that we can’t submit files to the server.

    I resolved that problem quickly by rewriting:
    Mage_Adminhtml_Block_Cms_Page_Edit_Form

    My suggestion is the next:


    class MyCompany_MyModule_Block_Cms_Page_Edit_Form extends Mage_Adminhtml_Block_Widget_Form
    {

    protected function _prepareForm()
    {
    $form = new Varien_Data_Form(
    array(
    'id' => 'edit_form',
    'action' => $this->getData('action'),
    'method' => 'post',
    'enctype' => 'multipart/form-data'
    )
    );
    $form->setUseContainer(true);
    $this->setForm($form);
    return parent::_prepareForm();
    }
    }

    The only difference with the core class is:

    ......
    'enctype' => 'multipart/form-data'
    ......

    Cheers!

    • Any solutions for this? At the moment I have a copy of the Form.php in a local folder structure and added ‘enctype’ => ‘multipart/form-data’.

      Surely, must be able to inject this via the observers.

      Any thoughts?

      • Thanks for your responce…

        After making all steps, on front page I have:

        Fatal error: Call to a member function getId() on a non-object in Z:\home\wellmag\www\app\code\core\Mage\Cms\Helper\Page.php on line 67

        protected function _renderPage(Mage_Core_Controller_Varien_Action $action, $pageId = null, $renderLayout = true)
        {

        $page = Mage::getSingleton(‘cms/page’);
        if (!is_null($pageId) && $pageId!==$page->getId()) {
        $delimeterPosition = strrpos($pageId, ‘|’);

        ——

        $page = Mage::getSingleton(‘cms/page’);

        couldn’t get the singleton ‘cms/page’…

        • Hmm, I have checked this code

          $page = Mage::getSingleton('cms/page');
          var_dump(get_class($page));

          on 1.6.1 and everything was ok.

          Did you overwrite Cms model?

          • No, I didn’t…
            and I removed maked changes and got the source code of this solution from git …
            and still not worked for me… with the same error…
            very strange…

          • Okay…
            I’ve installed clear Magento 1.6.1.
            and copy sources from git archive…
            caches are flished and disabled…

            it’s not work…
            with the same error…
            Magento couldn’t find ‘cms/page’ in registry
            and couldn’t register it with self::register method

            Ohhh…

          • there are 2 lines from system.log, which repeating for each page reload… nothing else for this issue…

          • By the way…
            Rafal, many thanks for your help…

            I’m new to Magento of cource…
            but I’ve solve my issue…

            I’ve added some classes which Magento requires (investigated system.log) as descendants from core cms page classes…

            and now it works…

            Thanks for help!

          • I got the same problem as you Vitaliy, Fatal error: Call to a member function getId() on a non-object in /var/sites/xxxxxxx/trunk/app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php on line 99

            Can you tell me which method you added ??

  3. I got the same problem as you Vitaliy, Fatal error: Call to a member function getId() on a non-object in /var/sites/xxxxxxx/trunk/app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php on line 99

    Can you tell me which method you added ?

  4. I got error
    Fatal error: Call to a member function load() on a non-object in /home/www/html/app/code/core/Mage/Adminhtml/controllers/Cms/PageController.php on line 91

    I can’t understand why it don’t work.

  5. For all of those who are getting the “Fatal error: Call to a member function….” The reason is the config.xml in this post is overwriting the core Mage_Cms module. You need to change your XML to the code to the below. (Sorry for the multiple posts… the code formatting in these comments is very poorly handled. Hopefully this works. If not, go here… http://pastie.org/3672081 )

    <?xml version=”1.0″?>
    <config>
    <modules>
    <Flexishore_Cms>
    <version>0.1.0</version>
    </Flexishore_Cms>
    </modules>
    <global>
    <models>
    <!– <cms>
    <class>Flexishore_Cms_Model</class>
    </cms> –>
    <flexishorecms>
    <class>Flexishore_Cms_Model</class>
    </flexishorecms>
    </models>
    <resources>
    <!– <cms_setup> –> <flexishorecms_setup>
    <setup>
    <module>Flexishore_Cms</module><class>Mage_Catalog_Model_Resource_Eav_Mysql4_Setup</class>
    </setup>
    <connection>
    <use>core_setup</use>
    </connection>
    <!– </cms_setup> –> </flexishorecms_setup>
    <!– <cms_write> –> <flexishorecms_write>
    <connection>
    <use>core_write</use>
    </connection>
    <!– </cms_write> –> </flexishorecms_write>
    <!– <cms_read> –> <flexishorecms_read>
    <connection>
    <use>core_read</use>
    </connection>
    <!– </cms_read> –> </flexishorecms_read>
    </resources>
    </global>
    <adminhtml>
    <events>
    <cms_page_prepare_save>
    <observers>
    <flexishore_cms_save_page>
    <type>singleton</type>
    <!–<class>cms/observer_cms</class>–>
    <class>flexishorecms/observer_cms</class>
    <method>savePage</method>
    </flexishore_cms_save_page>
    </observers>
    </cms_page_prepare_save>
    <adminhtml_cms_page_edit_tab_main_prepare_form>
    <observers>
    <flexishore_cms_prepare_form>
    <type>singleton</type>
    <!–<class>cms/observer_cms</class>–>
    <class>flexishorecms/observer_cms</class>
    <method>prepareForm</method>
    </flexishore_cms_prepare_form>
    </observers>
    </adminhtml_cms_page_edit_tab_main_prepare_form>
    </events>
    </adminhtml>
    </config>

  6. Pingback: Magento: WYSIWYG In Widget Options | Code and Programming

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">