Customising Magento .phtml view files and creating CMS blocks

Ok in yesterdays post, I showed you how you can start bringing in the Bootstrap files into Magento by defining them in the theme’s page.xml. We finished up by tweaking the layout .phtml files.

Now we’ll start editing our header. Open /app/design/frontend/fashion/default/template/page/html/header.phtml and put some placeholder bootstrap HTML into place:

<div id="top-bit">
    <div class="container">
        <div class="row">
            <div class="col-md-8">
                 ...
            </div>
            <div class="col-md-4">
                ...
            </div>
        </div>
    </div>
</div>

<div id="header">
    <div class="container">
        <div class="row">
            ...
        </div>
    </div>
</div>

<nav>
    ...
</nav>

We’ll stick some custom links in, the logo, and shopping basket, and nav bars with menu and search form. To make the top header div, we will create a CMS block with custom links, and a user area. To create a CMS Block, in the Magento Admin Panel, click on CMS > Static Blocks, and Add new block. I gave mine a title of Top Links, an ID of top_links, and in the content I added an inline bootstrap <ul>

<ul class="list-inline">
    <li><span class="glyphicon glyphicon-phone-alt"></span>&nbsp;<strong>Call Us: +39 (0) 55 11 22</strong></li>
    <li><a href="{{store_url=''}}">About Us</a></li>
    <li><a href="{{store_url=''}}">Delivery</a></li>
    <li><a href="{{store_url=''}}">FAQ</a></li><li><a href="{{store_url=''}}">Contacts</a></li>
</ul>

Then in the header.phtml, you add within the div#top-bit container row col-md-8:

<?= $this->getChildHtml('top_links'); ?>

Ok, in any Magento shop, we should have a welcome message, and Login | Register links. In the col-md-4 div, stick the following in:

<span class="welcome pull-left">
    <?= $this->getLayout()->getBlock('header')->getWelcome(); ?>
</span>
<ul class="list-inline pull-left">
    <?php
    if ($this->helper('customer')->isLoggedIn()) { ?>
        <li><a title="<?= $this->__('My Account'); ?>" href="<?= $this->getUrl('customer/account') ?>"><?= $this->__('My Account'); ?></a></li>
        <li><a title="Log Out" href="<?= $this->getUrl('customer/account/logout'); ?>"><?= $this->__('Logout'); ?></a></li>
    <?php } else { ?>
        <li><a href="<?= $this->getUrl('customer/account/login/')?>"><?= $this->__('Login') ?></a></li>
        <li><a href="<?= $this->getUrl('customer/account/create/')?>"><?= $this->__('Create Account') ?></a></li>
    <?php } ?>
</ul>

Now we can customise the CSS for our top bit. Open up /skin/frontend/fashion/default/css/styles.css and add the following styling rules:

div#top-bit
{
    background:none repeat scroll 0 0 #000;
    color:#FFF;
    font-size:12px;
    padding:10px 0 0;
    border-bottom:3px solid #FA9221;
}
div#top-bit ul
{
    margin:5px 0 0;
}
div#top-bit a
{
    color:#9F9F9F;
}
div#top-bit a:hover
{
    color:#f89223
}
div#top-bit .user-links .welcome
{
    padding:10px;
}
div#top-bit .user-links ul
{
    background: none repeat scroll 0 0 #FA9221;
    margin: 0;
    padding: 10px;
}
div#top-bit .user-links a
{
    color:#fff;
}

Ok, the section under the top-bit will contain a logo and a shopping cart. To change what the logo is, in the Magento Admin Panel, navigate to System > Configuration > Design > Header and change the Logo Image src.

Stick the following in div#header container row:

<div class="col-md-4">
   <a href="<?= $this->getUrl('') ?>" title="<?= $this->getLogoAlt() ?>" class="logo">
       <img src="<?= $this->getLogoSrc() ?>" alt="<?= $this->getLogoAlt() ?>" />
   </a>
</div>
<div class="col-md-4 col-md-offset-4">
     <?php echo $this->getChildHtml('top_cart') ?>
</div>

Now we actually need a top_cart section. Create app/design/frontend/fashion/default/template/checkout/cart/topcart.phtml.

<?php 

if ($this->getIsNeedToDisplaySideBar())
{
?>
    <div class="block block-cart block-topcart">
        <?php $cart_qty = $this->getSummaryCount(); ?>
        <div class="block-title">
            <div class="block-title">
                <span class="glyphicon glyphicon-shopping-cart"></span>
                <strong><span><?= $this->__('My Cart') ?></span></strong>

                <?php
                    if ($cart_qty > 0)
                    { 
                        $s = $cart_qty == 1 ? '' : 's';
                ?>
                <p class="amount">
                    <?= $this->__('There are <a href="%s">%s items</a> in your cart.', $this->getUrl('checkout/cart'), $cart_qty); ?>
                    <?= Mage::helper('checkout')->formatPrice($this->getSubtotal()) ?>
                </p>
                <?php } else { ?>
                        <p class="empty"><?= $this->__('You have no items in your shopping cart.') ?></p>
                <?php } ?>

                <?php if($cart_qty && $this->isPossibleOnepageCheckout()) { ?>
                    <div class="actions">
                        <?= $this->getChildHtml('extra_actions'); ?>
                        <button type="button" title="<?= $this->__('Checkout');?>" class="button" onclick="setLocation('<?= $this->getCheckoutUrl() ?>')">
                            <span><span><?= $this->__('Checkout') ?></span></span>
                        </button>
                    </div>
                <?php } ?>

                <?php $items = $this->getRecentItems(); ?>
                <?php if(count($items)){ ?>
                    <p class="block-subtitle"><?= $this->__('Recently added item(s)'); ?></p>
                    <ol id="cart-sidebar" class="mini-products-list">
                        <?php foreach($_items as $_item) { ?>
                            <?= $this->getItemHtml($_item) ?>
                        <?php } ?>
                    </ol>
                    <script type="text/javascript">decorateList('cart-sidebar', 'none-recursive')</script>
                <?php } ?>
        </div>
    </div>
<?php } ?>

Then we must declare top_cart in our local.xml:

<reference name="header">
    <block type="checkout/cart_sidebar" name="top_cart" template="checkout/cart/topcart.phtml" before="-">
        <action method="addItemRender"><type>simple</type><block>checkout/cart_item_renderer</block><template>checkout/cart/sidebar/default.phtml</template></action>
        <action method="addItemRender"><type>grouped</type><block>checkout/cart_item_renderer_grouped</block><template>checkout/cart/sidebar/default.phtml</template></action>
        <action method="addItemRender"><type>configurable</type><block>checkout/cart_item_renderer_configurable</block><template>checkout/cart/sidebar/default.phtml</template></action>
        <block type="core/text_list" name="cart_sidebar.extra_actions" as="extra_actions" translate="label" module="checkout">
            <label>Shopping Cart Sidebar Extra Actions</label>
        </block>
    </block>
</reference>

The <reference name=”header”> refers to the ID of a div. Again bung in some CSS:

#header {
    padding-top:10px;
}
#header .logo {
    display:block;
    margin-bottom:20px;
}
#header .block-topcart {
    margin-top: 5px;
    padding: 14px 20px 10px;
}
#header .block-topcart .block-title {
    font-size: 15px;
    margin-bottom: 5px
}
#header .block-topcart p.empty {
    font-size: 12px;
    color: #666;
    font-style: italic
}
#header .block-topcart .block-content {
    display: none
}

Now in the <nav> tag in the header.phtml, we can add the navbar code:

<nav class="navbar navbar-default navbar-main" role="navigation">
    <div class="container">
        <div class="row">
            <div class="navbar-header">
                <a class="navbar-brand visible-xs" href="#">
                    <?php echo $this->__('Categories') ?>
                </a>
                <button type="button" class="navbar-toggle" data-toggle="collapse"
                        data-target=".navbar-main-collapse">
                    <span class="sr-only"><?php echo $this->__('Toggle Navigation') ?></
                    span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
            </div>
            <div class="collapse navbar-collapse navbar-main-collapse">
                <?php echo $this->getChildHtml('topMenu') ?>
                <?php echo $this->getChildHtml('topSearch') ?>
            </div>
        </div>
    </div>
</nav>

We now have a very bootstrappy looking search box! As you can see from the code above, we are also wanting the ChildHtml of topMenu. So lets add that. Edit /app/design/ frontend/fashion/default/template/page/html/topmenu.phtml :

 

<?php
    $_menu = $this->getHtml('level-top');
    if ($_menu) { ?>
        <ul class="nav navbar-nav">
            <li><a href="<?php echo $this->getUrl('') ?>" title="<?php echo $this->getLogoAlt() ?>">Home</a></li>
            <?= $_menu; ?>
        </ul>
<?php }

We need to add a little jQuery to dynamically add a couple of our bootstrap classes, so in /skin/frontend/fashion/default/js/jquery/jquery.scripts.js

 

$j = jQuery.noConflict();

$j(document).ready(function(){
    jQuery('.navbar .parent').addClass('dropdown');
    jQuery('.navbar a.level-top').addClass('dropdown-toggle');
    jQuery('.navbar li.parent ul').addClass('dropdown-menu');
    jQuery('.navbar li.level1 ul').wrap('<li class="dropdown-submenu" />');
    jQuery('.navbar ul.nav li.level0.dropdown').hover(function() {
        jQuery(this).find('.level0.dropdown-menu').stop(true, true).fadeIn();
    }, function() {
            jQuery(this).find('.level0.dropdown-menu').stop(true, true).fadeOut();
        });
});

Lastly (at least in this post) we’ll sort out a footer. Edit /app/design/frontend/ bookstore/default/template/page/html/footer.phtml

<div class="row">
    <div class="col-md-4">
        <?= $this->getChildHtml('footer-company') ?>
    </div>
    <div class="col-md-8">
        <div class="row">
            <?= $this->getChildHtml('footer-cmslinks') ?>
            <hr>
        </div>
        <div class="row">
            <div class="col-md-6">
                <?= $this->getChildHtml('footer-newsletter') ?>
            </div>
            <div class="col-md-6">
                <?= $this->getChildHtml('footer-social') ?>
            </div>
        </div>
    </div>
</div>
<div class="row">
    <div class="col-md-12">
        <hr>
    </div>
    <div class="col-md-8">
        <?= $this->getCopyright() ?>
    </div>
    <div class="col-md-4">
        <?= $this->getChildHtml('footer-cards') ?>
    </div>
</div>

There are six things being called here. Four items will be CMS blocks, and the other two normal blocks (newsletter and copyright). We define our blocks in the local.xml in the footer reference:

<reference name="header">
    <block type="checkout/cart_sidebar" name="top_cart" template="checkout/cart/topcart.phtml" before="-">
        <action method="addItemRender"><type>simple</type><block>checkout/cart_item_renderer</block><template>checkout/cart/sidebar/default.phtml</template></action>
        <action method="addItemRender"><type>grouped</type><block>checkout/cart_item_renderer_grouped</block><template>checkout/cart/sidebar/default.phtml</template></action>
        <action method="addItemRender"><type>configurable</type><block>checkout/cart_item_renderer_configurable</block><template>checkout/cart/sidebar/default.phtml</template></action>
        <block type="core/text_list" name="cart_sidebar.extra_actions" as="extra_actions" translate="label" module="checkout">
            <label>Shopping Cart Sidebar Extra Actions</label>
        </block>
    </block>
</reference>

<reference name="footer">
    <block type="cms/block" name="footer-company" as="footer-company">
        <action method="setBlockId"><block_id>footer-company</block_id></action>
    </block>
    <block type="cms/block" name="footer-cmslinks" as="footer-cmslinks">
        <action method="setBlockId"><block_id>footer-cmslinks</block_id></action>
    </block>
    <block type="cms/block" name="footer-social" as="footer-social">
        <action method="setBlockId"><block_id>footer-social</block_id></action>
    </block>
    <block type="cms/block" name="footer-cards" as="footer-cards">
        <action method="setBlockId"><block_id>footer-cards</block_id></action>
    </block>
</reference>

Ok, the CMS blocks then. Log in to the admin panel, and go to CMS > Static Blocks. Click add new block, call it footer_company

<h4>About Our company</h4> <p>Our company are awesome, we use Bootstrap 3.0 and Magento version
       1.19. We are developing solutions and blah blah blah<a href="https://github.com/delboy1978uk">Visit Our Github!</a>

Add footer-cmslinks :

 

<div class="col-md-3">
    <h4>Column Name</h4>
    <ul>
        <li><a href="{{store_url=''}}about-magento-demo-store">About Us</a></li>
        <li><a href="{{store_url=''}}customer-service">Customer Service</a></li>
        <li class="last privacy"><a href="{{store_url=''}}privacy-policy-cookie-restriction-mode">Privacy Policy</a></li>
    </ul>
</div>
<div class="col-md-3">
    <h4>Column Name</h4>
    <ul>
        <li><a href="{{store_url=''}}about-magento-demo-store">About Us</a></li>
        <li><a href="{{store_url=''}}customer-service">Customer Service</a></li>
        <li class="last privacy"><a href="{{store_url=''}}privacy-policy-cookie-restriction-mode">Privacy Policy</a></li>
    </ul>
</div>
<div class="col-md-3">
    <h4>Column Name</h4>
    <ul>
        <li><a href="{{store_url=''}}about-magento-demo-store">About Us</a></li>
        <li><a href="{{store_url=''}}customer-service">Customer Service</a></li>
        <li class="last privacy"><a href="{{store_url=''}}privacy-policy-cookie-restriction-mode">Privacy Policy</a></li>
    </ul>
</div>
<div class="col-md-3">
    <h4>Column Name</h4>
    <ul>
        <li><a href="{{store_url=''}}about-magento-demo-store">About Us</a></li>
        <li><a href="{{store_url=''}}customer-service">Customer Service</a></li>
        <li class="last privacy"><a href="{{store_url=''}}privacy-policy-cookie-restriction-mode">Privacy Policy</a></li>
    </ul>
</div>

Now the footer-social block:

<ul class=”list-inline footer-social”>
<li><a class=”ico-facebook” href=”#”><span></span>Facebook</a></li>
<li><a class=”ico-twitter” href=”#”><span></span>Twitter</a></li>
<li><a class=”ico-google” href=”#”><span></span>Google+</a></li>
</ul>

Finally footer-cards:

<a href="#">
       <span style="font-size:12px; padding-right:10px;">Secure
       Payments</span>
       <img src="{{skin_url='images/cards.png'}}">
       </a>

Now we have our CMS blocks, we still need the other two. The newsletter block wont appear, because the default goes in the left hand side for whatever reason. Back in the xml, we add this:

<reference name="left">
    <remove name="left.newsletter"/>
</reference>

And in the footer reference, we add this:

<block type="newsletter/subscribe" name="footer.newsletter" as="footer-newsletter" template="newsletter/subscribe.phtml"/>

Now we create app/design/ frontend/base/default/template/newsletter/subscribe.phtml :

<div class="block block-subscribe">
    <form action="<?= $this->getFormActionUrl() ?>" method="post"
          id="newsletter-validate-detail">
        <div class="input-group">
           <span class="input-group-addon"><?= $this->__('Newsletter'); ?></span>
            <input type="text"
                   class="form-control input-sm required-entry validate-email"
                   title="<?= $this->__('Sign up for our newsletter') ?>"
                   id="newsletter"
                   name="email">
           <span class="input-group-btn">
               <button class="btn btn-default btn-sm" title="<?= $this->__('Subscribe') ?>" type="submit"><?= $this->__('Subscribe') ?></button>
           </span>
        </div>
    </form>
    <script type="text/javascript">
        //<![CDATA[
        var newsletterSubscriberFormDetail = new VarienForm('newsletter-validate-detail');
        //]]>
    </script>
</div>

Finally, add a splodge of CSS:

#footer {
    background-color:#FA9221;
    color:rgba(0,0,0,0.3);
    padding:20px 0;
    border-bottom:5px solid #333;
    font-size:12px,;
}
#footer h4 {
    color:rgba(0,0,0,0.6);
    font-size:14px;
}
#footer ul {
    list-style-position:inside;
    padding:0;
    margin:0;
}
#footer a {
    color:rgba(0,0,0,0.5);
    font-size:12px;
}
#footer a:hover {
    color:rgba(0,0,0,0.8);
}
#footer hr {
    border-color:rgba(0,0,0,0.2);
    border-style:dotted;
}
/* Social Icons */
#footer .footer-social a {
    display:inline-block;
    font-size:12px;
    line-height:24px;
}
#footer .footer-social a span {
    background: url(../images/sprite-social.png) no-repeat scroll 0 0 rgba(0, 0, 0, 0);
    display: inline-block;
    float: left;
    height: 24px;
    margin-right: 6px;
    padding-left: 20px;
    width:24px;
}
#footer .footer-social a.ico-facebook span {
    background-position:0 0;
}
#footer .footer-social a.ico-twitter span {
    background-position:-40px 0;
}
#footer .footer-social a.ico-google span {
    background-position:-80px 0;
}
#footer .footer-social a.ico-facebook:hover span {
    background-position:0 -28px;
}
#footer .footer-social a.ico-twitter:hover span {
    background-position:-40px -28px;
}
#footer .footer-social a.ico-google:hover span {
    background-position:-80px -28px;
}
#footer hr{
    margin-top: 20px;
    margin-bottom: 20px;
}

And that’s the end of the second chapter of my book! Next post I do, I’ll be blogging my experience customising our home page

Advertisements

Adding a custom search form to Magento

Ok, so you have a custom Magento theme (or at least a partially customised theme so far!), but now we need a custom search box.

In /app/design/frontend/your-theme/template, create catalogsearch/form.mini.phtml

<?php $helper =  $this->helper('catalogsearch'); ?>
<form id="search_mini_form" class="navbar-form navbar-right" role="search" action="<?= $helper->getResultUrl()?>" method="get">
    <div class="form-group">
        <div class="input-group">
            <span class="input-group-addon">
                <div class="glyphicon glyphicon-search pull-left"></div>
            </span>
            <input id="search"
                   type="text"
                   name="<?= $helper->getQueryParamName() ?>"
                   value="<?= $helper->getEscapedQueryText() ?>"
                   class="form-control"
                   maxlength="<?= $helper->getMaxQueryLength();?>"
                   placeholder="<?= $this->__('Search...') ?>" />
                <span class="input-group-btn">
                    <button type="submit" class="btn btn-default">Submit</button>
                </span>
            </div>
        </div>
    <div id="search_autocomplete" class="search-autocomplete"></div>
</form>
<script type="text/javascript">
    //<![CDATA[
    var searchForm = new Varien.searchForm('search_mini_form', 'search', '<?= $this->__('Search...') ?>');
    searchForm.initAutocomplete('<?= $helper->getSuggestUrl() ?>', 'search_autocomplete');
    //]]>
</script>

Of course, if you know how, you can generate a Zend_Form and save you having to code the form by hand! 😉

Overriding Magento’s Mage_Core

This was a bit fidgety, but its possible to override core Magento files! Actually there are two ways, but one involves copy pasting the class and tweaking. That will break if the class ever changes on a Magento update, so I won’t even tell you how to do that.

Instead, we’ll create our own module. My module’s called Madskull, and I already have a folder in /app/code/local/madskull

In this example, I overrode Mage_Core_Model_Url. I had to have a custom getUrl() method.

I created (in the aforementioned folder) Url/Url.php, which extends Mage_Core_Model_Url :

<?php

/**
 * Class Madskull_Core_Model_Url
 *
 *  @author delboy1978uk
 */
class Madskull_Url_Url extends Mage_Core_Model_Url
{
    /**
     * Do a quick string replace to ditch apostrophes
     * @return string
     */
    public function getUrl($routePath = null, $params = null)
    {
        return str_replace("'",'',parent::getUrl($routePath,$params));
    }
}

Okay, next in the Url directory, create an etc folder, and create config.xml :

<config>
    <modules>
        <Madskull_Url>
            <version>1.0.1</version>
        </Madskull_Url>
    </modules>
    <global>
        <models>
            <core>
                <rewrite>
                    <url>Madskull_Url_Url</url>
                </rewrite>
            </core>
        </models>
    </global>
</config>

Finally, we activate the module by adding it to a new file /app/etc/modules/Madskull_Url_Url.xml :

<?xml version="1.0"?>
<config>
    <modules>
        <Madskull_Url>
            <active>true</active>
            <codePool>local</codePool>
            <depends>
                <Mage_Core />
            </depends>
        </Madskull_Url>
    </modules>
</config>

Job done! Now, without creating second copies of the core classes, you can extend away, and updates will not affect your code!

Getting link rel=”prev/next” links in Magento category pages

Google likes this stuff, so we should utilise tags in the.I could probably put this code in a better place, but for now, I went into my head view file located at app/design/frontend/themename/default/template/page/html/head.phtml

if ($this->getAction()->getFullActionName() == 'catalog_category_view') // Category Page
{
    $category = Mage::registry('current_category');
    
    $collection = $category->getProductCollection()
                        ->addAttributeToFilter('status', 1)
                        ->addAttributeToFilter('visibility', array(
                            'in' => array(
                                Mage_Catalog_Model_Product_Visibility::VISIBILITY_IN_CATALOG, 
                                Mage_Catalog_Model_Product_Visibility::VISIBILITY_BOTH)
                            )
                        );
    /** @var @var Mage_Page_Block_Html_Pager $tool */
    $tool = $this->getLayout()
                 ->createBlock('page/html_pager')
                 ->setLimit($this->getLayout()
                 ->createBlock('catalog/product_list_toolbar')
                 ->getLimit())
                 ->setCollection($collection);

    $prev = false;
    $next = false;
    if ($tool->getCollection()->getSelectCountSql())
    {
        if ($tool->getLastPageNum() > 1)
        {
            if (!$tool->isFirstPage())
            {
                $prev = true;
                if ($tool->getCurrentPage() == 2)
                {
                    $url = explode('?', $tool->getPreviousPageUrl());
                    $prev_url = @$url[0];
                }
                else
                {
                    $prev_url = $tool->getPreviousPageUrl();
                }
            }
            if (!$tool->isLastPage()) {
                $next = true;
                $next_url = $tool->getNextPageUrl();
            }
        }
    }
    echo ($prev) ?'<link rel="prev" href="' . $prev_url . '" />' : null;
    echo ($next) ? '<link rel="next" href="' . $next_url . '" />' : null;
}

If you DON’T have category pages with duplicate content that can be accessed from multiple urls, you can now turn off the canonical tag in the SEO settings. Log into the admin panel, and select System > Configuration > Catalogue  > Search Engine Optimisations. Then you can set Use Canonical Link Meta Tag For Categories to No.

Again, leave it yes if you have duplicate content, ie /crystal-wine-glasses has the same (but less) content than /wine-glasses.

Job done! Google will like that! 😀

Adding Bootstrap theme template files to your custom Magento theme

Last post, I created my own cusomised Magento theme. It looks crap, but it works! Instructions here https://delboy1978uk.wordpress.com/2015/06/04/creating-custom-magento-themes/ In this post, I am going to take my fancy bootstrap 3 store template, and integrate it in to our newly created theme. The first stage is learning how the templates all work, so we’ll bring in the js and css, and make our own header until we get the hang of it. Then we can take the HTML from our template and add it in. But first things first.

fashion

The theme I downloaded has Bootstrap 3, but not the latest version, so I’m grabbing the latest from http://getbootstrap.com/getting-started/#download.

Once downloaded, copy the following files into your theme in /skin/frontend/fashion/default :

/css
    /bootstrap.min.css
/js
    /bootstrap.min.js
/fonts
    /glyphicons-halflings-regular.eot
    /glyphicons-halflings-regular.svg
    /glyphicons-halflings-regular.ttf
    /glyphicons-halflings-regular.woff

Stick your jquery.min.js in /js/lib/jquery.  There’s already a jQuery in there, but yours might be newer. You’ll notice a noconflict.js too. That stops jQuery and Prototype from conflicting with one another.
Ok, now we’ve done that, we need to configure our /app/design/frontend/fashion/default/layout/local.xml file. Javascript & Css go in our head block. So lets add it:

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * local.xml
 * Local layout modifications for our local theme
 * @category    design
 * @package     fashion
 * @copyright   Copyright (c) 2015 delboy1978uk.
 */
-->
<layout version="0.1.0">
    <default>
        <reference name="head">
            <action method="addJs"><script>js/lib/jquery.min.js</script></action>
            <action method="addJs"><script>js/lib/jquery/noconflict.js</script></action>
            <action method="addItem"><type>skin_js</type><name>js/bootstrap.min.js</name></action>
            <action method="addItem"><type>skin_css</type><name>css/bootstrap.min.css</name></action>
            <action method="addItem"><type>skin_css</type><name>css/styles.css</name></action>
            <action method="addItem"><type>skin_css</type><name>css/styles-ie.css</name></action>
        </reference>
    </default>
</layout

As you know, the C of CSS stands for cascading. The styles.css in the base theme will be called first, which obviously is unwanted behaviour which could cause class conflicts, so we really want to stop the base theme from loading it. So add this line before the bootstrap.min.css line :

<!-- Remove base theme styles.css --> 
<action method="removeItem"><type>skin_css</type><name>css/styles.css</name></action>

Now let’s deal with the world’s shittiest, least standards compliant browser out there (if you can call it a browser) : Internet Explorer.  The usual suspects apply here, namely https://oss.maxcdn.com/libs/respond.js/1.3.0/ respond.min.js & https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js . Download them into the theme js folder, and add them under that bootstrap js line (notice the params bit):

<action method="addItem"><type>skin_js</type><name>js/html5shiv.js</name><params/><if>lt IE 9</if></action>
<action method="addItem"><type>skin_js</type><name>js/respond.min.js</name><params/><if>lt IE 9</if></action>

You can also add a config section specifically for print, so here’s what to add after the reference=”head” section:

<print translate="label" module="page">
    <label>All Pages (Print Version)</label>
    <!-- Mage_Page -->
    <block type="page/html" name="root" output="toHtml" template="page/print.phtml">

        <!-- This block allows the print.phtml template to get the logo -->
        <block type="page/html_header" name="header" as="header"/>

        <block type="page/html_head" name="head" as="head">

            <action method="addCss"><stylesheet>css/styles.css</stylesheet></action>
            <action method="addItem"><type>skin_css</type><name>css/styles-ie.css</name><params/><if>lt IE 8</if></action>
            <action method="addCss"><stylesheet>css/widgets.css</stylesheet></action>
            <action method="addItem"><type>skin_css</type><name>css/print.css</name></action>
        </block>

        <block type="core/text_list" name="content" as="content" translate="label">
            <label>Main Content Area</label>
        </block>

    </block>
</print>

Now we add our ‘root’ template file. At the top, in the default node but above the <reference name=”head”> node, add the following (for the example I’m using the 2 col layout):

<reference name="root">
      <action method="setTemplate">
          <template>page/2columns-left.phtml</template>
      </action>
</reference>

Great! Now it’s time to rip apart the .phtml files we copied over from the base theme! Open /app/design/frontend/fashion/default/template/page/2columns-left.phtml

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php echo $this->getLang() ?>" lang="<?= $this->getLang() ?>">

    <head>
        <?= $this->getChildHtml('head') ?>
    </head>

    <body<?= $this->getBodyClass() ? ' class="'.$this->getBodyClass().'"' : null; ?>>
        <?= $this->getChildHtml('after_body_start') ?>
        <?= $this->getChildHtml('global_notices'); ?>
        <header>
            <?= $this->getChildHtml('header'); ?>
        </header>
        <section id="after-header">
            <div class="container">
                <?= $this->getChildHtml('slider'); ?>
            </div>
        </section>
        <section id="maincontent">
            <div class="container">
                <div class="row">
                    <?= $this->getChildHtml('breadcrumbs'); ?>
                    <aside class="col-left sidebar col-md-3">
                        <?= $this->getChildHtml('left'); ?>
                    </aside>
                    <div class="col-main col-md-9">
                        <?= $this->getChildHtml('global_messages'); ?>
                        <?= $this->getChildHtml('content'); ?>
                    </div>
                </div>
            </div>
        </section>
        <footer id="footer">
            <div class="container">
                <?= $this->getChildHtml('footer'); ?>
            </div>
        </footer>
        <?= $this->getChildHtml('before_body_end'); ?>
        <?= $this->getChildHtml('global_cookie_notice'); ?>
        <?= $this->getAbsoluteFooter(); ?>
    </body>

</html>

Okay, do the same for the other template files too! You know the score! Ditch the Magento markup and replace with BS3 awesomeness!
Check out my next post where we’ll start editing the view files and creating blocks etc!

 

Creating custom Magento themes

First up, get your mock up files, photoshop layout, bootstrap template, or whatever. Then decide on a name for your  package which we’ll use for the whole project. I’m making a fashion store magento site for the purposes of learning, so i got a theme from http://w3layouts.com/, and I’ll be calling my theme ‘fashion‘. Once you have your html template ready, we start creating our folders.

Create the following directory stucture:

/app
    /design
        /frontend
            /fashion
                /default
                    /template
                    /layout
                    /locale

And in the skin directory, create the following structure:

/skin
    /frontend
        /fashion
            /default
                /images
                /css
                /js

Now we have the directory structure in place, we need to create the required files. The easiest way to do this is to copy the files from the base theme, and edit them to suit.

Copy the following files from app/design/frontend/base/default/template/ to app/design/frontend/fashion/default/template/ :

/page/1column.phtml
/page/2columns-left.phtml
/page/2columns-right.phtml
/page/3columns.phtml
/page/html/head.phtml
/page/html/header.phtml
/page/html/footer.phtml

Ok, getting somewhere. Next we create local.xml in /app/design/frontend/fashion/default/layout :

<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
 * local.xml
 * Customised Magento Theme
 * @category    design
 * @package     fashion
 * @copyright   Copyright (c) 2015 delboy1978uk.
 */
-->
<layout version="0.1.0">
    <default>

    </default>
</layout>

Lastly, copy the 3 css files in /skin/frontend/default/css/ into /skin/frontend/fashion/default/css. styles.css is the main stylesheet, print.css is the style for printed materials, styles-ie.css is the style for that popular ‘browser selection tool’ 😉 .

Disable the cache. To do this, navigate to /admin in the browser and log in to your Magento control panel. Once there, go to System > Cache Management . Click select all, choose Disable in the Actions select element, and click submit.

Disabling the Magento Cache
Disabling the Magento Cache

Now we can activate our theme! Click on System > Configuration > General >Design and click on the package option. Type in your package name (in my case fashion), and click Save Config.

Our empty Magento theme
Our empty Magento theme

It’s not much to look at, but we are now using our own custom Magento theme! 😀

It’s a good idea to disable the WYSIWYG editor for the CMS section, as your HTML will be tinkered with. It’s meant for non-techie-types, so lets turn that off. Go to System > Configuration > Content Management, select Disable Completely, and again save your config.

Lastly, pages can be made out of bits from other pages. Sometimes, it can be awkward finding the file you need if there are several blocks in a page. There is a helper for this which displays the template path. Go to System > Configuration > Advanced > Developer. Above the left hand column, you will see Current Configuration Scope. Select Main Website. In the Debug section to the right, select Yes to Template path hints. Save.

Template Path Hints turned ON
Template Path Hints

Have fun setting up your own themes! I’ll be blogging more as I learn more, so stay tuned!

Magento Admin user variables

The magento admin user can add custom variables which can be used in static blocks, the CMS section of the admin panel, and also in the transactional emails. To use these, we go into System > Custom Variables, and click add New Variable. You give it a code like store_city, and in the ‘name’ field put a description (yes, i know). Then you can set an html representation and a plain text representation of what you want the value to be.

Now when editing a CMS page or transactional email, we can do stuff like this:

<p>We are based in: {{CustomVar code="store_city"}}</p>

Nice and easy.