home | contact us
» Posts tagged "helpful tips"

Items Tagged: helpful tips


There is a problem in Magento that when you try to move a category by dragging it in the admin, it can cause the above error, whilst causing the rest of the site to slow down.

This is caused by the system trying to re-index every product within the space of a transaction.

An easy way to get round this is to switch the indexing mode from auto to manual and then move the categories.

You will still need to re-index the site, but this can be run on a cron when the site is quite.


 

I have been working with a server that had been configured differently from the way that I prefer.

The two biggest complaints that I had about it were that the timeout was set very low, meaning that the connection would break off every five minutes, and that vim had been set up so if you selected text using the mouse you could not copy it.

The solutions to these two problems are as follows.

You can tell the terminal not to timeout with the following command

export TMOUT=0

Be aware that this will only work for the terminal that you are working with.

The issue with vim is that the mouse was triggering visual mode.

To get round this hold down shift when selecting text and everything will work as expected


 

Sometime a backup script can go wrong, and rather the overwrite the old files you place a copy of the new ones into the same folder.

This can then escalate and before you know it you have multiple levels of the same files.

If you just want to flatten these files then this script can do that you

// The duplicated directory
DUPLICATED_DIR_NAME='uploads'
// A new directory for the files to go into
NEW_DIR_NAME='realuploads'
for f in <code>find ./ | grep $DUPLICATED_DIR_NAME/$DUPLICATED_DIR_NAME </code>; 
do 
NEWFILE=<code>echo $f | sed 's/$DUPLICATED_DIR_NAME\//\//g'</code>; 
NEWDIR=../$NEW_DIR_NAME/<code>dirname $NEWFILE</code>; 
if [[ ! -d $NEWDIR ]]
then
mkdir $NEWDIR; 
fi
cp -f &quot;$f&quot; ../$NEW_DIR_NAME/$NEWFILE; 
done

 

I have recently been putting together a system that needed to interact with Magento.

A big issue that I came across was a warning similar to this


Warning: include(): Failed opening 'Model/Base.php' for inclusion (include_path='...') in /path/to/magento/lib/Varien/Autoload.php on line 93

As I was running with an error handler that turned all errors into exceptions this prevented the code from running.

The issue was due to my code using a custom autoloader, and when the Varien auto-loader was called first it could not find the files which triggered a warning.

There are multiple ways of getting round this – see here for an example – if you are using PHP 5.3+ there is a much simpler solution.

Since PHP 5.3 the spl_autoload_register has had a prepend option which places the autoloader at the top of the stack. This means that it will try your autoloader first, rather than the Varien one, avoiding the warning if the file can only be found using your autoloader. To do this just use the following command

spl_autoload_register('my_autoloader',null,true);

 

I recently had a Magento store that was not running cron jobs despite everything appearing to be set up correctly.

After tearing out my hair, I discovered that there was a cron job running that had not closed properly, which prevented any new cron jobs from starting.

This is because the cron.sh file that is used by magento checks the currently running processes, and if one exists quietly exits.

To check if this is the case you can run a modified line from the cron.sh file as set out below


ps auxwww | grep "/path/to/magento/cron.php" | grep -v grep | grep -v cron.sh

If this returns a line similar to the one below


root 2125 0.0 0.9 329896 40484 ? S Nov13 0:00 /usr/bin/php /path/to/magento/cron.php

You can kill the running job, which will allow cron to run normally. At this stage you should debug the cron tasks to see why the process stalled


 

I recently had a client that wanted to remove the category structure from their product urls.

There is a option to do this in the admin, but they wanted to redirect all of the existing urls to the shorter one.

The way that I wanted to do this was to truncate the current core_url_rewrite table and regenerate the urls with the “Use Categories Path for Product URLs” set to no, and then override the 404 controller to redirect to the correct url.

However, after the urls were generated, I found that all of the urls including the category path were still included, which meant that the override would not work.

After spending quite a bit of time looking for a way to get round this, I put together a simple override to prevent the category path urls from getting generated.

This had the added benefit of reducing the number of entries in the core_url_rewite table from ~2k entries to under 500, which cut the amount of time that was needed to generate it.

The code is below for anyone else that needs to use this in the future. There are three files in total, set up like this

EdmondsCommerce/
<code>-- Redirects
    |-- controllers
    |   </code>-- Cms
    |       <code>-- IndexController.php
    |-- etc
    |   </code>-- config.xml
    <code>-- Model
        </code>-- Catalog
            `-- Url.php

This is the code for the Model

class EdmondsCommerce_Redirects_Model_Catalog_Url 
  extends Mage_Catalog_Model_Url {

    /**
     * This method is called each time that a url 
     * is generated for a product. It is called for the 
     * root category and each category that the product is in.
     * 
     * This code checks to see if the category passed to it is
     * the root category. If it is it will 
     * add the url rewrite as normal. If not it does nothing
     * 
     * @param Varien_Object $product
     * @param Varien_Object $category
     */
    protected function _refreshProductRewrite(Varien_Object $product, Varien_Object $category) {
        $rootCategory = $this->getStoreRootCategory($category->getStoreId());
        if($category->getId() == $rootCategory->getId()) {
            parent::_refreshProductRewrite($product, $category);
        }
    }
}

If you want to redirect from the existing urls to the new ones, you will need to use the following controller

include_once('Mage/Cms/controllers/IndexController.php');

class EdmondsCommerce_Redirects_Cms_IndexController 
extends Mage_Cms_IndexController {

    /**
     * This checks to see if the site can redirect
     * before displaying a 404
     * @param type $coreRoute
     */
    public function noRouteAction($coreRoute = null) {
        // Get the request
        $request = $_SERVER['REQUEST_URI'];
        // Strip off get params if there are any
        if (strpos($request, '?') !== FALSE) {
            $request = substr($request, 0, strpos($request, '?'));
        }
        /**
         *  This makes sure that no part of the request is included
         *  in the base url. This should help
         *  the system work if it is running from a sub folder
         */
        $parts = explode('/', Mage::getBaseUrl());
        foreach ($parts AS $part) {
            $request = str_replace(array($part, '//'), '', $request);
        }
        /*
         * Combine the request with the base path to get the full url
         * and remove any trailing slashes
         */
        $path = trim(str_replace('http:/', 'http://', str_replace('//', '/', Mage::getBaseUrl() . $request)), '/');
        //Get the last section which should be the product title
        $cleanedPath = explode('/', $path);
        $key = array_pop($cleanedPath);
        //Here we find url keys like the title
        $collection = Mage::getModel('catalog/product')->getCollection();
        $collection->addAttributeToSelect('url_key');
        $collection->addFieldToFilter(array(
            array('attribute' => 'url_key', 'like' => "$key")));
        $products = $collection->load();
        /*
         * Proceed if there is only 1 result, if there are more we
         * don't know which one is correct
         */
        if (count($products) == 1) {
            foreach ($products AS $product) {
                $url = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB) . $product->getUrlKey();
                //Check to make sure the url is not the same as the path, should prevent infinite redirects
                if ($path != $url) {
                    header('HTTP/1.1 301 Moved Permanently');
                    header('Location: ' . $url);
                    die();
                }
            }
        }
        // Could not find a suitable url carry out the 404
        parent::noRouteAction($coreRoute);
    }

}

Then use the following xml file

<?xml version="1.0"?>
<config>
    <modules>
        <EdmondsCommerce_Redirects>
            <version>0.1.0</version>
            <depends></depends>
        </EdmondsCommerce_Redirects>
    </modules>
    <global>
        <models>
            <redirects>
                <class>EdmondsCommerce_Redirects_Model</class>
            </redirects>
            <catalog>
                <rewrite>
                    <url>EdmondsCommerce_Redirects_Model_Catalog_Url</url>
                </rewrite>
            </catalog>
        </models>
    </global>
    <frontend>
        <routers>
            <cms>
                <args>
                    <modules>
                        <EdmondsCommerce_Redirects before="Mage_Cms">EdmondsCommerce_Redirects_Cms</EdmondsCommerce_Redirects>
                    </modules>
                </args>
            </cms>
        </routers>
    </frontend>
</config>

 

Sometimes you may want to quickly compare all of the attributes that object (category / product) has in magento. The EAV structure of the database makes this difficult to do this simply, so this is a query that will do it for you

SELECT * FROM (
    SELECT 
        ce.sku,
        ea.attribute_id,
        ea.attribute_code,
        CASE ea.backend_type
           WHEN 'varchar' THEN ce_varchar.value
           WHEN 'int' THEN ce_int.value
           WHEN 'text' THEN ce_text.value
           WHEN 'decimal' THEN ce_decimal.value
           WHEN 'datetime' THEN ce_datetime.value
           ELSE ea.backend_type
        END AS value,
        ea.is_required AS required
    FROM catalog_product_entity AS ce
    LEFT JOIN eav_attribute AS ea 
        ON ce.entity_type_id = ea.entity_type_id
    LEFT JOIN catalog_product_entity_varchar AS ce_varchar 
        ON ce.entity_id = ce_varchar.entity_id 
        AND ea.attribute_id = ce_varchar.attribute_id 
        AND ea.backend_type = 'varchar'
    LEFT JOIN catalog_product_entity_int AS ce_int 
        ON ce.entity_id = ce_int.entity_id 
        AND ea.attribute_id = ce_int.attribute_id 
        AND ea.backend_type = 'int'
    LEFT JOIN catalog_product_entity_text AS ce_text 
        ON ce.entity_id = ce_text.entity_id 
        AND ea.attribute_id = ce_text.attribute_id 
        AND ea.backend_type = 'text'
    LEFT JOIN catalog_product_entity_decimal AS ce_decimal 
        ON ce.entity_id = ce_decimal.entity_id 
        AND ea.attribute_id = ce_decimal.attribute_id 
        AND ea.backend_type = 'decimal'
    LEFT JOIN catalog_product_entity_datetime AS ce_datetime 
        ON ce.entity_id = ce_datetime.entity_id 
        AND ea.attribute_id = ce_datetime.attribute_id 
        AND ea.backend_type = 'datetime'
    WHERE ce.sku = YOUR_SKU
  ) AS tab
  WHERE tab.value != "";

This version of the query will only return values that are not blank, but if you only run the sub query it will give you every value.
Replace catalog_product* for catalog_category to get the values for a category. You will also have to use a different selector than SKU.


 

One of the features that I was previously unaware of in Netbeans is its ability to automatically generate common class methods. This post is a quick guide of how this works for future reference.

To get the system to work, first load up a php class. For this example I’m going to be extending the Magento Product Model. This basic class can be seen here, with a couple of extra properties added.

To start generating the methods you need to press [Alt] & [Insert] and you will be presented with a menu similar to the one below

This lists all of the common methods that do not currently exist within the class. The first thing that we’ll do is to generate a constructor, which gives us the following options

Here you can select which of the class properties you want to be set using the constructor. Pick the ones you want and click OK, and the following code is generated

The Getters and Setters work in the same way, and the Override & Implement provides you with a list of all of the methods that the class can override from its parents. Using these together can help you to quickly all of the methods you need in minutes, as shown below.


 

If you have ever had to browse for a coding solution, you will have come across the problem of “smart” quotes replacing normal punctuation. Thankfully there is a simple fix to to this, a userscript called DumbQuotes which can be downloaded here.

This will convert all of the single & double quotes into something more code friendly.


 

I do a lot front end development with Magento, and one of the biggest time sinks for this is waiting for a page to load when you want to change a line of CSS.

Whilst you can use Firebug / Chrome to edit CSS rules on the page, you still need check that the file is saved correctly. As this is Magento, this can take some time due to caching being disabled.

Thankfully there is an extension for Chrome which will just reload you CSS files and not the entire page. You can install it here and save a lot of time during development!


 
rss icon