Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a featured image for CMS page in Prestashop

I want to add an image from back-end for each CMS page I'm adding in Prestashop, just like we add featured images for posts/page in Wordpress.

I couldn't find any codes/modules which support this feature in prestashop.

like image 629
Leo T Abraham Avatar asked Jun 05 '15 04:06

Leo T Abraham


People also ask

How do I upload images to PrestaShop?

Store Manager for PrestaShop is empowered with the useful ability to add images using drag&drop. Basically, all you need to do is to press “Add image” button, browse through the folders of your local computer, click on the necessary image(s) and move them to the place where product images can be previewed.

How do I change my image in PrestaShop?

To change the image, click the Browse button under the Image field. Select your new image from your local computer. Once you have selected the new image, click on the Save button to activate it.

Where does PrestaShop store product images?

there are all product images, especially in subdirectories /img/p/1/ img/p/2/ img/p/3/ etc.

What is CMS PrestaShop?

The CMS (Content Management System) in PrestaShop allows you to create, delete and manage the pages of your Store and also their contents like static blocks, images, banners and many more features.


3 Answers

It is possible, but it isn't straightforward. Here are the steps you need to do to implement image upload to the CMS page module. This approach is not the most elegant way to implement this in PrestaShop, but I hope it helps you to move forward.

Step 1, Update the model so it can contain the image:

First override 'classes/CMS.php' to 'override/classes/CMS.php'.

class CMS extends CMSCore
{    
    // add a public field to store the CMS image
    public $CMS_IMG; 

    /**
    * @see ObjectModel::$definition
    */
    public static $definition = array(
        'table' => 'cms',
        'primary' => 'id_cms',
        'multilang' => true,
        'fields' => array(
        'id_cms_category' =>  array('type' => self::TYPE_INT, 'validate' => 'isUnsignedInt'),
        'position' =>    array('type' => self::TYPE_INT),
        'active' =>    array('type' => self::TYPE_BOOL),
        // Lang fields
        'meta_description' =>  array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255),
        'meta_keywords' =>   array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'size' => 255),
        'meta_title' =>   array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isGenericName', 'required' => true, 'size' => 128),
        'content' =>    array('type' => self::TYPE_HTML, 'lang' => true, 'validate' => 'isString', 'size' => 3999999999999),

        // add one image per page        
        'CMS_IMG' =>   array('type' => self::TYPE_STRING, 'lang' => true, 'validate' => 'isString', 'size' => 3999999999999),  ),
    );
}

Step 2, Implement the code needed to upload the image in the backoffice:

Override 'controllers/admin/AdminCmsController.php' in 'override/controllers/admin/AdminCmsController.php'

class AdminCmsController extends AdminCmsControllerCore
{
    public function renderForm()
    {        
        $this->display = 'edit';
        $this->toolbar_btn['save-and-preview'] = array(
            'href' => '#',
            'desc' => $this->l('Save and preview')
        );
        $this->initToolbar();
        if (!$this->loadObject(true))
            return;
        $categories = CMSCategory::getCategories($this->context->language->id, false);
        $html_categories = CMSCategory::recurseCMSCategory($categories, $categories[0][1], 1, $this->getFieldValue($this->object, 'id_cms_category'), 1);

        // Add code to get image url
        $image_url = '';
        $imgName = $this->getImageValue($this->object);
        if($imgName) {
            $image = _PS_IMG_DIR_ . 'cms/' . $imgName;
            $image_url = ImageManager::thumbnail($image, $this->table.'_'.(int)$this->object->id.'.'.$this->imageType, 350,
                $this->imageType, true, true);
        }

        $this->fields_form = array(
            'tinymce' => true,
            'legend' => array(
                'title' => $this->l('CMS Page'),
                'image' => '../img/admin/tab-categories.gif'
            ),
            'input' => array(
                // custom template
                array(
                    'type' => 'select_category',
                    'label' => $this->l('CMS Category'),
                    'name' => 'id_cms_category',
                    'options' => array(
                        'html' => $html_categories,
                    ),
                ),
                array(
                    'type' => 'text',
                    'label' => $this->l('Meta title:'),
                    'name' => 'meta_title',
                    'id' => 'name', // for copy2friendlyUrl compatibility
                    'lang' => true,
                    'required' => true,
                    'class' => 'copy2friendlyUrl',
                    'hint' => $this->l('Invalid characters:').' <>;=#{}',
                    'size' => 50
                ),
                array(
                    'type' => 'text',
                    'label' => $this->l('Meta description'),
                    'name' => 'meta_description',
                    'lang' => true,
                    'hint' => $this->l('Invalid characters:').' <>;=#{}',
                    'size' => 70
                ),
                array(
                    'type' => 'tags',
                    'label' => $this->l('Meta keywords'),
                    'name' => 'meta_keywords',
                    'lang' => true,
                    'hint' => $this->l('Invalid characters:').' <>;=#{}',
                    'size' => 70,
                    'desc' => $this->l('To add "tags" click in the field, write something, then press "Enter"')
                ),
                array(
                    'type' => 'text',
                    'label' => $this->l('Friendly URL'),
                    'name' => 'link_rewrite',
                    'required' => true,
                    'lang' => true,
                    'hint' => $this->l('Only letters and the minus (-) character are allowed')
                ),
                array(
                    'type' => 'textarea',
                    'label' => $this->l('Page content'),
                    'name' => 'content',
                    'autoload_rte' => true,
                    'lang' => true,
                    'rows' => 5,
                    'cols' => 40,
                    'hint' => $this->l('Invalid characters:').' <>;=#{}'
                ),                
                /* Add an fileupload component to the form */
                array(
                    'type' => 'file',
                    'label' => $this->l('Page image'),
                    'name' => 'CMS_IMG',
                    'desc' => $this->l('Upload an image for this page'),
                    'lang' => true,
                    'display_image' => true,
                    'image' => $image_url ? $image_url : false,
                ),                
                array(
                    'type' => 'radio',
                    'label' => $this->l('Displayed:'),
                    'name' => 'active',
                    'required' => false,
                    'class' => 't',
                    'is_bool' => true,
                    'values' => array(
                        array(
                            'id' => 'active_on',
                            'value' => 1,
                            'label' => $this->l('Enabled')
                        ),
                        array(
                            'id' => 'active_off',
                            'value' => 0,
                            'label' => $this->l('Disabled')
                        )
                    ),
                ),
            ),
            'submit' => array(
                'title' => $this->l('   Save   '),
                'class' => 'button'
            )
        );
        if (Shop::isFeatureActive())
        {
            $this->fields_form['input'][] = array(
                'type' => 'shop',
                'label' => $this->l('Shop association:'),
                'name' => 'checkBoxShopAsso',
            );
        }
        $this->tpl_form_vars = array(
            'active' => $this->object->active
        );
        return AdminControllerCore::renderForm();
    }

    public function postProcess()
    {
        $languages = Language::getLanguages(false);
        $update_images_values = false;

        foreach ($languages as $lang)
        {
            if (isset($_FILES['CMS_IMG'])
                && isset($_FILES['CMS_IMG']['tmp_name'])
                && !empty($_FILES['CMS_IMG']['tmp_name']))
            {
                if ($error = ImageManager::validateUpload($_FILES['CMS_IMG'], 4000000))
                    return $error;
                else
                {
                    $ext = substr($_FILES['CMS_IMG']['name'], strrpos($_FILES['CMS_IMG']['name'], '.') + 1);
                    $file_name = md5($_FILES['CMS_IMG']['name']).'.'.$ext;

                    if (!move_uploaded_file($_FILES['CMS_IMG']['tmp_name'],
                        _PS_IMG_DIR_ .'cms'.DIRECTORY_SEPARATOR.$file_name))
                        return Tools::displayError($this->l('An error occurred while attempting to upload the file.'));
                    else
                    {
                        $values['CMS_IMG'][$lang['id_lang']] = $file_name;
                    }
                }

                $update_images_values = true;
                $cms = new CMS((int)Tools::getValue('id_cms'));
                $cms->CMS_IMG = $file_name;
                $cms->update();
            }
        }

        parent::postProcess();
    }

    public function getImageValue()
    {
        $db = Db::getInstance();
        $sql = 'SELECT CMS_IMG FROM '._DB_PREFIX_.'cms_lang WHERE id_cms = ' . $this->object->id;
        return $db->getValue($sql);
    }
}

Step 3, Implement the code for the frontend

Overide 'controllers/front/CmsController.php' in 'override/controllers/front/CmsController.php'

class CmsController extends CmsControllerCore
{

    /**
     * Assign template vars related to page content
     * @see CmsControllerCore::initContent()
     */
    public function initContent()
    {
        if(!empty($this->cms->CMS_IMG)) {
            $this->context->smarty->assign('cms_image', _PS_IMG_ . 'cms/' . $this->cms->CMS_IMG);
        }

        parent::initContent();
    }
}

Step 4, use your image in the template

Now you can, e.g. in cms.tpl use the following code:

{if $cms_image != ''}
    <img src="{$cms_image}">
{/if}

Based on: https://www.prestashop.com/forums/topic/141903-add-custom-field-to-cms-module/

like image 72
11mb Avatar answered Sep 18 '22 19:09

11mb


Adding all these as separate answer, since some moderators seem to reject even most simplest fix/change to original answer as "This edit deviates from the original intent of the post" or "This edit was intended to address the author of the post" ..right.


Improving answer by 11mb

Step 0, Note that new field needs to be manually added in SQL table (use SQL or PhpMyAdmin structure edit):

ALTER TABLE `ps_cms_lang` ADD `CMS_IMG` TEXT NULL DEFAULT NULL;

Step 1.2, Class cache file needs to be deleted for changes to be active:

/cache/class_index.php

Step 4, use your image in the template
..
Or more universal form (also usable in category subpages - use CMS_IMG attribute (-> or . depends on code):

{if isset($cms->CMS_IMG) && $cms->CMS_IMG}
    <img src="{$img_ps_dir}/cms/{$cms->CMS_IMG}">
{/if}

1. For a non-multiligual field - make these adjustments:

ALTER TABLE `ps_cms` ADD `CMS_IMG` TEXT NULL DEFAULT NULL;

'CMS_IMG' =>   array('type' => self::TYPE_STRING, 'lang' => false, ..

'lang' => false,

$sql = 'SELECT CMS_IMG FROM '._DB_PREFIX_.'cms WHERE id_cms = ' . $this->object->id;

+And remove all that lang stuff in postProcess()


2. Multiple fixes to postProcess()

  • code does not correctly save data - should not use $cms->update(); in postProcess() as triggers exception on adding new page, due partial data = just set $_POST['CMS_IMG'] value..
  • should generate unique filename (start with id) for each page.
  • should check for isSubmit to avoid processing in wrong chain (if same field name used in CMS categories).

Updated code:

public function postProcess()
{
    if ( (Tools::isSubmit('submitAddcms') || Tools::isSubmit('viewcms'))
        && isset($_FILES['CMS_IMG'])
        && isset($_FILES['CMS_IMG']['tmp_name'])
        && !empty($_FILES['CMS_IMG']['tmp_name']))
    {
        $id = (int)Tools::getValue('id_cms');

        if ($error = ImageManager::validateUpload($_FILES['CMS_IMG'], 4000000))
            return $error;
        else
        {
            $ext = substr($_FILES['CMS_IMG']['name'], strrpos($_FILES['CMS_IMG']['name'], '.') + 1);
            $file_name = $id .'_cms_'. md5($_FILES['CMS_IMG']['name']).'.'.$ext;

            if (!move_uploaded_file($_FILES['CMS_IMG']['tmp_name'],
                _PS_IMG_DIR_.'cms'.DIRECTORY_SEPARATOR.$file_name))
                return Tools::displayError($this->l('An error occurred while attempting to upload the file.'));
            else {
                $_POST['CMS_IMG'] = $file_name;
                @chmod(_PS_IMG_DIR_.'cms'.DIRECTORY_SEPARATOR.$file_name, 0666);
            }
        }
    }

    parent::postProcess();
}
like image 32
megamurmulis Avatar answered Sep 18 '22 19:09

megamurmulis


The above solutions just do not fit with PrestaShop's philosophy.

Adding a featured image for a CMS page should mimic existing mecanisms (see creation/edition of categories or suppliers logo).

Following is my solution, working for PrestaShop 1.6.1.7. It will add an image field, upload image to img/cms folder and create all thumbnails.

I did not figure out how to delete the image yet, you are more than welcome to comment my answer. Be careful when updating PrestaShop, files out of the override folder may be updated.

1/ Add the following to defines.inc.php (after line 137):

define('_PS_CMS_IMG_DIR_', _PS_IMG_DIR_.'cms/');

2/ Add the following to defines_uri.inc.php (after line 61):

define('_THEME_CMS_DIR_', _PS_IMG_.'cms/');

3/ Add rules to .htaccess file:

RewriteRule ^cms/([0-9]+)(\-[\.*_a-zA-Z0-9-]*)(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/cms/$1$2$3.jpg [L]
RewriteRule ^cms/([a-zA-Z_-]+)(-[0-9]+)?/.+\.jpg$ %{ENV:REWRITEBASE}img/cms/$1$2.jpg [L]

4/ Override classes/CMS.php to override/classes/CMS.php:

<?php
class CMS extends CMSCore
{    
    // Add an id_image attribute to allow further tests in cms.tpl
    public $id_image = 'default';

    public function __construct($id = null, $id_lang = null, $id_shop = null)
    {
        parent::__construct($id, $id_lang, $id_shop);
        $this->id_image = ($this->id && file_exists(_PS_CMS_IMG_DIR_.(int)$this->id.'.jpg')) ? (int)$this->id : false;
        $this->image_dir = _PS_CMS_IMG_DIR_;
    }
}
?>

5/ Override classes/ImageType.php to override/classes/ImageType.php

  • Add a public attribute to the class: public $cms

  • Append to $definition=>fields: 'cms' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool')

  • In getByNameNType, append to $types var: 'cms'

6/ Override classes/Link.php to override/classes/Link.php:

class Link extends LinkCore
{
    public function getCmsImageLink($name, $id_cms, $type = null)
    {
        if ($this->allow == 1 && $type) {
            $uri_path = __PS_BASE_URI__.'cms/'.$id_cms.'-'.$type.'/'.$name.'.jpg';
        } else {
            $uri_path = _THEME_CAT_DIR_.$id_cms.($type ? '-'.$type : '').'.jpg';
        }
        return $this->protocol_content.Tools::getMediaServer($uri_path).$uri_path;
    }
}

7/ Override controllers/AdminCmsController.php to override/controllers/AdminCmsController.php:

  • Append the following to the __contruct method, right before parent::__construct():

    $this->fieldImageSettings = array(
        'name' => 'banner_img',
        'dir' => 'cms',
    );
    
  • Append the following to the postProcess method, right after line 351 (in one of the elseif blocks, look for a condition on submitAddcms and submitAddcmsAndPreview):

    $object = $this->loadObject();
    $image_is_posted = $this->postImage($object->id);
    if (! $image_is_posted) {
        throw new PrestaShopException("image not posted...");
    }
    
  • In the renderForm method, start with:

    if (!($obj = $this->loadObject(true))) {
        return;
    }
    
    $image = _PS_CMS_IMG_DIR_.$obj->id.'.jpg';
    $image_url = ImageManager::thumbnail($image, $this->table.'_'.$obj->id.'.'.$this->imageType, 350,
        $this->imageType, true, true);
    
    $image_size = file_exists($image) ? filesize($image) / 1000 : false;
    
    if (Validate::isLoadedObject($this->object)) {
        $this->display = 'edit';
    } else {
        $this->display = 'add';
    }
    

and append the following to the attribute $this->fields_form, for example after the content field:

array(
    'type' => 'file',
    'label' => $this->l('Banner image'),
    'name' => 'banner_img',
    'display_image' => true,
    'image' => $image_url ? $image_url : false,
    'size' => $image_size,
    'hint' => $this->l('Upload a banner image from your computer.')
)
  • Add and afterImageUpload method:

    protected function afterImageUpload() { $return = true; $generate_hight_dpi_images = (bool)Configuration::get('PS_HIGHT_DPI');

    $object = $this->loadObject(true);
    
    /* Generate image with differents size */
    if (($object->id = (int)Tools::getValue('id_cms')) &&
         isset($_FILES) && count($_FILES) && file_exists(_PS_CMS_IMG_DIR_.$object->id.'.jpg')) {
        $images_types = ImageType::getImagesTypes('cms');
        foreach ($images_types as $k => $image_type) {
            $file = _PS_CMS_IMG_DIR_.$object->id.'.jpg';
            if (!ImageManager::resize($file, _PS_CMS_IMG_DIR_.$object->id.'-'.stripslashes($image_type['name']).'.jpg', (int)$image_type['width'], (int)$image_type['height'])) {
                $return = false;
            }
    
            if ($generate_hight_dpi_images) {
                if (!ImageManager::resize($file, _PS_CMS_IMG_DIR_.$object->id.'-'.stripslashes($image_type['name']).'2x.jpg', (int)$image_type['width']*2, (int)$image_type['height']*2)) {
                    $return = false;
                }
            }
        }
    
        $current_logo_file = _PS_CMS_IMG_DIR_.'cms_mini_'.$object->id.'_'.$this->context->shop->id.'.jpg';
    
        if (file_exists($current_logo_file)) {
            unlink($current_logo_file);
        }
    }
    return $return;
    }
    

8/ Override controllers/admin/AdminImagesController.php to override/controllers/admin/AdminImagesController.php

  • In the __construct method, append to $this->fields_list: 'cms' => array('title' => $this->l('CMS'), 'align' => 'center', 'type' => 'bool', 'callback' => 'printEntityActiveIcon', 'orderby' => false)

  • In the __contruct method, append to $this->fields_form=>input:

    array(
        'type' => 'switch',
        'label' => $this->l('Pages CMS'),
        'name' => 'cms',
        'required' => false,
        'is_bool' => true,
        'hint' => $this->l('This type will be used for CMS banner images.'),
        'values' => array(
            array(
                'id' => 'cms_on',
                'value' => 1,
                'label' => $this->l('Enabled')
            ),
            array(
                'id' => 'cms_off',
                'value' => 0,
                'label' => $this->l('Disabled')
            ),
        )
    ),
    
  • In initRegenerate method, append to $types var: 'cms' => $this->l('CMS pages')

  • In the _regenerateThumbnails method, append to $process array: array('type' => 'cms', 'dir' => _PS_CMS_IMG_DIR_)

9/ Update your CMS page template cms.tpl with something like this:

<!-- Check out the default theme's category_header.tpl for original PrestaShop code -->
<div class="cms_banner"{if $cms->id_image} style="background:url({$link->getCmsImageLink($cms->link_rewrite, $cms->id_image, 'large')|escape:'html':'UTF-8'}) right center no-repeat; background-size:cover; "{/if}>
    <div class="container">
        <!-- Your content here -->
    </div>
</div>
like image 22
Q Caron Avatar answered Sep 17 '22 19:09

Q Caron