Thursday, August 29, 2013

Magento shortcuts

Various magento shortcuts

Get a url with the correct protocol (http/https)

To get a url from a template with the correct protocol use:
$url = $this->getUrl('some url path', array('_secure' => Mage::app()->getFrontController()->getRequest()->isSecure()));

Alternatively you can use:
$this->getUrl('some url path', array('_secure' => Mage::app()->getStore()->isCurrentlySecure()));

If you are outside a template you can replace $this-> with Mage::

Saturday, March 16, 2013

Polishing up the magento mini search

 Magento comes with a mini search form complete with search suggestions. To fetch and show the search suggestions magento uses the prototype Ajax.Autocompleter. This works well but it's not fully configured in the default magento setup. The aim of this post is to complement the magento search suggestions with the following:
  • limit the number of returned results - magento returns all results by default and this can generate a long list as well as adding some overhead
  • add a search indicator so the user knows that a search is in progress
  • highlight the search term in the returned results
  • remove the number of results that magento adds to each returned result

Preparing files for editing

To achieve the points above we'll need to edit some of the magento files. As it's not good to change the magento core files we'll copy these files to the local code pool. We'll need to copy the following files:
  • app/code/core/Mage/CatalogSearch/Model/Query.php to app/code/local/Mage/CatalogSearch/Model/
  • app/code/core/Mage/CatalogSearch/Block/Autocomplete.php to app/code/local/Mage/CatalogSearch/Block/
  • app/design/frontend/base/default/template/catalogsearch/form.mini.phtml to app/design/frontend/default/default/template/catalogsearch/
 In addition to the above files we will need to edit js/varien/js.js and add some css styling. You can add the css either to your theme's css files or directly in the updated form.mini.phtml file


Limit the number of results returned by magento

Limiting the number of results is quite simple. All we need to do is edit app/code/local/Mage/CatalogSearch/Model/Query.php and add a line to the getSuggestCollection function so it looks like the following:
    /**
     * Retrieve collection of suggest queries
     *
     * @return Mage_CatalogSearch_Model_Resource_Query_Collection
     */
    public function getSuggestCollection()
    {
        $collection = $this->getData('suggest_collection');
        if (is_null($collection)) {
            $collection = Mage::getResourceModel('catalogsearch/query_collection')
                ->setStoreId($this->getStoreId())
                ->setQueryFilter($this->getQueryText());
            //limit the number of returned results
            $collection->getSelect()->limit(10);
            $this->setData('suggest_collection', $collection);
        }
        return $collection;
    }
The code that limits the result numbers is on line 14.

Removing results numbers and adding highlights to results

Ajax.Autocompleter needs a ul returned containing the search suggestions. Magento creates the list in Mage/CatalogSearch/Block/Autocomplete.php in the _toHtml() function. Edit app/code/local/Mage/CatalogSearch/Block/Autocomplete.php and change the _toHtml function as below. You can also add other changes you want applied to the results list.
    protected function _toHtml()
    {
     //change html to return a list on error otherwise the loader image doesn't go away
        $html = '
    '; if (!$this->_beforeToHtml()) { return $html; } $suggestData = $this->getSuggestData(); if (!($count = count($suggestData))) { return $html; } $count--; //get the query text $query = $this->helper('catalogsearch')->getQueryText(); $html = '
    • '; foreach ($suggestData as $index => $item) { if ($index == 0) { $item['row_class'] .= ' first'; } if ($index == $count) { $item['row_class'] .= ' last'; } $text = $this->htmlEscape($item['title']); //get the first case insensitive query occurence in the text $pos = stripos($text,$query); $length = strlen($query); if ($pos !== false) { //get the actual case sensitive piece of text that matches the query and highlight it $replacement="".substr($text, $pos, $length).""; //replace the query in the text with the highlighted version $text = substr_replace($text,$replacement,$pos, $length); } $html .= '
    • '. $text.'
    • '; } $html.= '
    '; return $html; }

    Adding the search indicator element

    The autocompleter plugin can display a visual indicator while the ajax request is running. You can generate a loading indicator at preloaders.net. We'll need to add a div that will contain our progress indicator. To do this edit app/design/frontend/default/default/template/catalogsearch/form.mini.phtml and add the following somewhere inside the search form div (or in another place where you want it displayed):
    
    
    I've uploaded my indicator to the skin/frontend/default/default/images/ folder so I can reference it using the magento getSkinUrl function.
    I want my loading image to show over the search input so I added the css styles to the element to make sure it's positioned correctly and in front of the input.

    Updating the autocomplete javascript

    The last thing we need to do is update the javascript used to initialize the Ajax.Autocompleter. Open js/varien/js.js and search for the following lines of code:
            new Ajax.Autocompleter(
                this.field,
                destinationElement,
                url,
                {
                    paramName: this.field.name,
                    method: 'get',
                    minChars: 2,
    

    Add the following lines after the miChars line:
                    frequency: 0.5,
                    indicator: 'search-running',
    
    The frequency tells autocompleter how often it should poll the input for changes and the indicator is the id of the element that should be shown while the ajax request is running.

    That's it. Comments are always welcome.

    Friday, March 8, 2013

    Random vi shortcuts

    Toggling syntax highlighting

    :syntax [on/off]
    

    Changing the colorscheme

    :colorscheme [colorscheme]
    

    Short form (actually can be anything from colo to colorscheme):
    :colo [colorscheme]
    

    Some default colorschemes:torte, morning, evening, desert, pablo etc. To cycle through the available colorchemes press tab after the command
    To set a colorscheme by default for a profile edit ~/.vimrc and add the following lines:

    syntax on
    colorscheme [colorscheme]
    

    Saturday, March 2, 2013

    Getting magento product custom options

    In one case custom options for products were supposed to be required but they were not set to required in the admin.As there were a lot of products it was impractical to set those manually so the only solution was a script. The easy way is to go into the database and set the is_require field to 1 in the catalog_product_option table. The following query can be used:
    UPDATE `catalog_product_option` SET `is_require`=1
    

    Getting the values for those options is difficult using sql queries so here's a bit of code to achieve that.
    <?php
    require_once (str_replace('//','/',dirname(__FILE__).'/') .'../app/Mage.php');
    umask(0); 
    Mage::app('admin');
    $collection = Mage::getModel('catalog/product')->getCollection()->load();
    
    echo $collection->count(),"<b r/>";
    foreach ($collection as $product) {
     echo "<b>",$product->getId(), " - ",$product->getSku(),"</b><b r/>"; 
     $product->load();
     $i = 1;
     echo "<pre>";
     foreach ($product->getOptions() as $o) {
         echo "<strong>Custom Option:" . $i . "</strong><b r/>";
         echo "Custom Option TYPE: " . $o->getType() . "<b r/>";
         echo "Custom Option TITLE: " . $o->getTitle() . "<b r/>";
         echo "Custom Option Required: " . $o->getIsRequire() . "<b r/>";
         echo "Custom Option Values: <b r/>";
         $values = $o->getValues();
         foreach ($values as $v) {
             print_r($v->getData());
         }
         $i++;
         echo "----------------------------------<b r/>";
     }
     } 
    
    

    Thanks to Subesh Pokhrel
    Due to some unknown black magic the br tags in the code snippets get interpreted and having no time to deal with it now I've just  put a space between the b and the r

    Friday, March 1, 2013

    Linux admin shortcuts

    List of sometimes useful commands

    System information

    Getting hardware information

    Hardware information can be obtained using the dmidecode tool that tries to decode the dmi table. It can also filter the information provided using the -t flag.
    Getting information the physical memory:

    dmidecode -t memory
    

     

    Getting information about a domain

    Domain information cat be obtained using the DNS lookup utility dig. The simplest usage would be:

    dig domainname
    

    and it returns information on the A record of the host.
    The utility can be used to get other types of information by using the -t switch and specifying the record type. For nameservers the query is:
    dig domainname -t NS
    

    For mail records:
    dig domainname -t MX
    

    Reverse lookups can be prformed using the -x flag:
    dig -x ip_address
    

    Thursday, February 28, 2013

    Random postgresql tasks

    Getting the foreign key references to a table


    SELECT
        tc.constraint_name, tc.table_name, kcu.column_name, 
        ccu.table_name AS foreign_table_name,
        ccu.column_name AS foreign_column_name 
    FROM 
        information_schema.table_constraints AS tc 
        JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
        JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
    WHERE constraint_type = 'FOREIGN KEY' AND ccu.table_name='table_name';
    

    Getting the numbers of connections to the server


    select datname, client_addr, usename, Count(1) As connections
    from pg_stat_activity
    group by datname, client_addr, usename
    order by datname, client_addr
    

    Saturday, February 23, 2013

    Magento debugging thoughts

    Random thoughts on debugging in magento

    Logging magento queries

    Sometimes you need to take a look at the queries generated by magento while loading different objects or collections. To log queries edit lib/Varien/Db/Adapter/Pdo/Mysql.php and change the following line:
    protected $_debug               = false;
    
    to
    protected $_debug               = true;
    
    The log file is specified in:
    protected $_debugFile           = 'var/debug/pdo_mysql.log';
    

    Logging ALL magento queries

    Even with logging enabled not all queries are  logged. To enable logging all queries change:

    protected $_logAllQueries       = false;
    
    to
    protected $_logAllQueries       = true;
    

    Logging all magento events

    To log all the events magento throws edit app/Mage.php and add the following line to the dispatchEvent function:
    Mage::log($name, null, 'events.log');
    

    After the change the function should look something like:
    public static function dispatchEvent($name, array $data = array())
        {
            Mage::log($name, null, 'events.log');
            Varien_Profiler::start('DISPATCH EVENT:'.$name);
            $result = self::app()->dispatchEvent($name, $data);
            #$result = self::registry('events')->dispatch($name, $data);
            Varien_Profiler::stop('DISPATCH EVENT:'.$name);
            return $result;
        }
    
    Events will be logged to var/log/events.log

    Magento queries list

    Quick reference list of Magento queries


    Getting store information

    Load store object ($identifier can be store id or code):
    $store = Mage::getModel('core/store')->load($identifier);
    
    Get (admin) Store Id using store code:
    $adminStoreId = Mage::getModel('core/store')->load('admin')->getId();
    

    Filtering by null fields

    Get items with a NULL field:
    $collection = Mage::getModel('your/model')->getCollection();
    $collection->addFieldToFilter('field_code',array('null' => true));
    $collection->load();
    
    Get items with non NULL field:
    $collection = Mage::getModel('your/model')->getCollection();
    $collection->addFieldToFilter('field_code',array('neq' => 'NULL'));
    $collection->load();
    

    Tuesday, January 15, 2013

    XSLT sorting by child attributes

    I'm new to xslt but I had to tackle a problem involving sorting an xml structure based on attributes of generic children. Something like the xml below.
    <data>
     <node name="Node1">
      <attribute name="sortValue" value="value1"/>
      <attribute name="color" value="red"/>
      <attribute name="size" value="XL"/>
     </node> 
     <node name="Node2">
      <attribute name="sortValue" value="value3"/>
      <attribute name="color" value="pink"/>
      <attribute name="size" value="L"/>
     </node> 
     <node name="Node3">
      <attribute name="sortValue" value="value2"/>
      <attribute name="color" value="blue"/>
      <attribute name="size" value="M"/>
     </node> 
     <node name="Node4">
      <attribute name="sortValue" value="value3"/>
      <attribute name="color" value="black"/>
      <attribute name="size" value="S"/>
     </node> 
    </data>
    
    After searching a little I found some solutions and documented them here for future reference.

    Simple Sorting 

    The simple case would involve using the sortValue attributes. To perform a simple sort for the xml on the sort field you can use the following xslt:
    <xsl:template match="/">
      <html>
      <body>
         <table border="1">
          <tr bgcolor="pink">
            <th>Node Name</th>
            <th>Sort Value</th>
            <th>Color</th>
            <th>Size</th>
          </tr>
          <xsl:for-each select="data/node">
          <xsl:sort select="attribute/@value[../@name = 'sortValue']"/>
          <tr>
            <td><xsl:value-of select="@name"/></td>
      <xsl:for-each select="attribute">
       <td><xsl:value-of select="@value"/></td>
      </xsl:for-each>
          </tr>
          </xsl:for-each>
        </table>
      </body>
      </html>
    </xsl:template>
     
    This should give you the following result:

    Node NameSort ValueColorSize
    Node1value1redXL
    Node3value2blueM
    Node2value3pinkL
    Node4value3blackS

    Sorting by multiple attributes

    XSLT also supports multiple sorting so if you want to sort by multiple attributes (for example the last two lines have the same sort value but the color are not sorted) you can add a second sort. For this exmpla just change

    <xsl:sort select="attribute/@value[../@name = 'sortValue']"/>
    
    with
    <xsl:sort select="attribute/@value[../@name = 'sortValue']"/>
    <xsl:sort select="attribute/@value[../@name = 'color']"/>
    
    and you should get:
    Node NameSort ValueColorSize
    Node1value1redXL
    Node3value2blueM
    Node4value3blackS
    Node2value3pinkL

     

    Sorting finite options by priority

    If you have a list of possibilities with a finite number of priorities (like the clothes sizes in the example) you can use a trick to prioritize the list. This involves converting the options to numbers and giving each a weight for the purpose of sorting and performing the sort on numeric values.
    To sort by size in this example you could use the following:
    <xsl:sort data-type='number' order='ascending' 
     select="(number(attribute/@value[../@name = 'size'] = 'S') * 1)
      + (number(attribute/@value[../@name = 'size'] = 'M') * 2)
      + (number(attribute/@value[../@name = 'size'] = 'L') * 3)
      + (number(attribute/@value[../@name = 'size'] = 'XL') * 4)"/>
    
    This should give the following result:
    Node NameSort ValueColorSize
    Node4value3blackS
    Node3value2blueM
    Node2value3pinkL
    Node1value1redXL

    Happy sorting