Tag Archive: php


It’s something to do with using PHP FPM / Fast CGI, and auth headers being disable for that.

So we add this to the directory entry of the .htaccess:

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

You now have your missing header back!

In PHPStorm, you can do a regex find and replace. To upgrade a crappy old site using <?, just use the following regex:

#<\?(?!=|php|xml)#

https://regex101.com/r/yD6dK5/5

DOMDocuments are cool, and a really nice way of dealing with HTML in an OO fashion. However, sometimes, we have an HTML string element which we need to add to our Document. Here’s how you do it:

    function createNodesFromHTML(DOMDocument $doc,$str) 
    {
        $nodes = array();
        $d = new DOMDocument();
        $d->loadHTML("<html>{$str}</html>");
        $child = $d->documentElement->firstChild->firstChild;
        while($child) {
            $nodes[] = $doc->importNode($child,true);
            $child = $child->nextSibling;
        }
        return $nodes;
    }


        $dom = new DOMDocument();
        $icon = '<i class="fa fa-remove"></i>'; // This is our string

        $button = $dom->createElement('a');
        $button->setAttribute('href', '/whatever/delete/12345');
        $button->setAttribute('class', 'btn btn-sm btn-danger');
        
        // This is us turning the string(s) into nodes we can add
        $nodes = createNodesFromHTML($dom, $icon);
        $button->appendChild($nodes[0]);
        
        $dom->appendChild($button);
        echo $dom->saveHTML();

As any decent developer knows, register_globals was a terrible idea, a security risk, and turned ON by default in old versions of PHP!

Thankfully it was removed in PHP 5.4. However, if you are stuck developing on a site that used register_globals, you may find yourself in a situation where seemingly you can’t upgrade beyond PHP 5.3.

However, it’s not all bad news, we can put a piece of code in place which emulates register_globals. This will let us turn it off. It still means your code is less than secure, but of course that’ll be fixed in time as you upgrade and refactor the site, right?

To emulate register_globals, just add the following code to one of your initialisation/bootstrap scripts:

// Emulate register_globals on
if (!ini_get('register_globals')) {
    $superglobals = array($_SERVER, $_ENV,
        $_FILES, $_COOKIE, $_POST, $_GET);
    if (isset($_SESSION)) {
        array_unshift($superglobals, $_SESSION);
    }
    foreach ($superglobals as $superglobal) {
        extract($superglobal, EXTR_SKIP);
    }
}

Now you can turn it off in php.ini. Why is it so bad though? Well, have a look at this:

code

Looks like nothing should happen on that page, right? nothing has been defined.

WRONG! try adding ?loggedIn=anything to the end of the URL:

loggedin

As you readers probably know, I can’t stand XAMPP and MAMP, being two steaming piles of crap, and have long advocated that you set up VirtualBox & Vagrant, then head over to http://www.puphpet.com, fill in the forms to configure your VM,  generate the config.yaml, and then unzip it and run ‘vagrant up’ to install it. Brilliant so far.

Yesterday I had a total downer of a day, trying to run an old legacy PHP 5.3 app. PuPHPet doesn’t have the EOL PHP 5.3, so at first I settled as a one off for MAMP, but it was slow and horrible.

Then I thought, wait! If I don’t configure Apache or PHP in puphpet, I could get a box up and install 5.3 myself. That’s when I discovered the awesomeness of the puphpet/files folder.

The only thing I used in there was the ssh keys. But there are empty folders waiting for .sh files (shell scripts) to be dropped in.

So for this box, I created exec-once/install-stuff.sh which contained the following:

#!/bin/bash
yum -y install httpd php
yum -y install php-mysql php-devel php-gd php-pecl-memcache php-pspell php-snmp php-xmlrpc php-xml

Then upon running vagrant provision, it not only looked for changes in config.yaml, but it checks for changes in these files too!

I then made set-vhosts.sh, and import-database.sh, which look like these:

#!/bin/bash
echo "
===========================================
Adding vhosts to /etc/httpd/conf/httpd.conf
===========================================
"
echo "
<VirtualHost *:80>

   DocumentRoot /var/www/fife/web
   ServerName fife
   ErrorLog /var/www/fife/log/error.log

   <Directory "/var/www/fife">
      Options -Indexes +FollowSymLinks
      Order allow,deny
      Allow from all
      AllowOverride All
  </Directory>

</VirtualHost>
" >> /etc/httpd/conf/httpd.conf

And …

#!/bin/bash
mysql -u root --password=123 --database=fortdev < /var/www/fife/data/sql_scripts/symf_fortdev.sql

I take it by now you get the idea! So now you can totally destroy your VM, and put any customisations in these shell scripts, so your full setup can be back up in 5 minutes flat with a vagrant up and vagrant provision!!!

You can then also start thinking about using puPHPet for deploying your setup to your production server 🙂 There’s a vagrant plugin called Vagrant Managed Servers, which will take care of that for you. https://github.com/tknerr/vagrant-managed-servers . I haven’t looked at it yet, but of course you can expect a blog post on it here when I figure it all out!!

This is real easy, but i keep forgetting which option to use!

If you have separated some of your code into a composer vendor package, and are currently using it in a project, it can be annoying if you need to update it. First you need to open that project up, make your changes, commit, push, wait for tests to pass on travis etc, tag a new version (depending), update packagist if it hasn’t automatically already, and then you can go back into composer and update.

So to save that hassle, composer has the –prefer-source option (–prefer-dist is the one that confused me). This puts the .git folder in your vendor package folder, allowing you to edit, commit, and push from there. Much better.

If you already have the package installed, just delete it. If you haven’t installed it yet, just require it. Both with the –prefer-source option.

composer require delboy1978uk/user --prefer-source
// or
composer update delboy1978uk/user --prefer-source

Replacing my own package above with the one you need, of course. Have fun!Screen Shot 2016-01-14 at 20.26.55

Because this is the way you ensure your code is awesome, and provably works!

If you you have some code you think could be reused in lots of projects, create a repository in Github and share it with the world!

I set up a project on github called delboy1978uk/blank. It’s literally a blank PHP project waiting to be written.

However it already has configuration for Travis for automated testing, and it also hooks up with Scrutinizer, which will analyse the code coverage report Travis sends it,  giving you reports on how many of your class methods have been tested, and the quality of your code (less complex methods = good!).

You can clone the repository, rename a folder and a couple of files, and search and replace my blank class name refs, then you are good to go! Just composer install and you can run tests by running:

vendor/bin/codecept run unit --coverage-html

The coverage option generates an html report you can browse in the tests/output folder.

If you try it straight away you’ll see there is one test in tests/unit/del/BlankTest.php. Tests usually follow this pattern. If it says you pass a string as an argument, and return some object, then test it! The simplest example is a getter/setter. If you run setsomething(‘hello’); then getSomething() should be ‘hello’. Most tests say something like $this->assertTrue() or $this->assertInstanceOf() or $this->assertEquals(). You get the idea. Check the code coverage reports to ensure the tests cover all eventualities. But it’s great seeing your code working, with tested PROOF that it works.

So to summarise:

  • Create your new repository on Github, activate your new repository in Travis CI , and activate your new  repository in Scrutinizer
  • Clone https://github.com/delboy1978uk/blank somewhere and delete the .git from it
  • Clone https://github.com/you/your-project somewhere-else
  • Copy everything from somewhere to somewhere-else (including hidden files)
  • Tweak the composrr.json, rename the class file and test file, search and replace refs
  • Commit & Push 😀
  • Register your project on Packagist!

All that should be doable in 5 minutes, so you can instantly get set up ready to code the real stuff! Try writing your assumptions first in the test file!

 

Phpunit is being removed from Pear, so the best way to install it now is by creating a phpunit.sh which you drop into your puphpet/files/exec-once-unprivileged directory:

#!/bin/bash
composer global require "phpunit/phpunit=4.4.*"
export PATH=$PATH:~/.composer/vendor/bin/

Then just vagrant provision, and that should be it!

This is insanely easy to set up. Run this, or stick it in your .bashrc. If you are running your server on a VM or remote server, change localhost to the IP of your dev box.

export XDEBUG_CONFIG=”idekey=PHPSTORM remote_host=localhost profiler_enable=1″

Now you can start listening for conections in your IDE.

 

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