If like me, you take an unsophisticated approach to batch product updates in Magento, you may have noticed it can be a little slow.
As one of my clients' sites has grown, some batch updates were taking up to 30 minutes to run. This is too long.
If the changes you are making are just to update simple attributes, for example we have a sales ranking attribute, you can use the following code to update the value without incurring the massive overhead of a full product save.
$product->setNumSales(1234);
$product->getResource()->saveAttribute($product, 'num_sales');
The saveAttribute method takes two parameters, the first is the model containing the attribute value, the second the attribute code. To find out the attribute code, look it up in either the db (eav_attribute) or in the admin backend under catalog->attribute.
Using the getResource()-->saveAttribute() call, takes 1/5s, doing a full save(), takes 2-3 seconds. When iterating over a large product base, that is HUGE.
Update 4 Mar 2014 - Please take a look at DannyD's comment below for a more robust approach to mass attribute updates.
Mysql has many great date handling functions, but one that I don't see used very often is DATE_SUB, which is fantastic at handling time intervals.
For example, say you want to select all records from a table that has a date set more than 1 month old (compared to the current time).
SELECT * FROM table WHERE DATE_SUB(CURDATE(),INTERVAL 30 DAY) > date_column
This assumes your date column is of type date, or datetime, although using FROM_UNIXTIME will allow you to work with timestamps as well.
The date_sub call, if ran on 2010-05-20, will return 2010-04-20. So if your date_column field has a date greater than this value, it is therefore more than 30 days old.
This is particularly handy when generating reports.
In a word, don't!
I just saw an insane suggestion on a Magento forum, advising users to change their admin url by hacking app/code/core/Mage/Adminhtml/etc/config.xml.
This is dangerous and pointless. Dangerous, because when you attempt to upgrade magento, you will at best lose your custom configuration, and at worst, cause an upgrade to fail. Pointless, because you can achieve the same effect by making changes to app/etc/local.xml.
This file overrides any configuration set elsewhere and by default, actually already has a definition for a custom admin url. When you install Magento, the installer sets up this file up by subbing in the details you provide the installer into local.xml.template.
So to change your admin url, after running the installer, simply fire up an editor and open app/etc/local.xml and look for this:
<admin>
<routers>
<adminhtml>
<args>
<frontName><![CDATA[admin]]></frontName>
</args>
</adminhtml>
</routers>
</admin>
Change the admin (inside the CDATA declaration) to foobar, or gobbles, or topsecret, whatever. Much easier, much safer than hacking away at core magento configuration files.
I originally wrote this for a client and I thought it might help others out there trying to do the same thing. Adding template content to Magento views ought to be really simple, but sadly due to a lack of good documentation, it is anything but.
To add a text template to a view in magento, you need to consider three aspects
- The template block itself
- The block, or layout, the template will sit in
- The layout .xml configuration
The first element is simplest, create some html, stuff it into a .phtml file and copy it to a directory within your theme, which resides (relative to the store root dir) in 'app/design/frontend/<package>/<theme>/templates'. I'm going to assume the package/theme is default/default from here forward.
You will now need to configure one or more layout xml templates (app/design/frontend/default/default/layout') to refer to your new template block. For most general purpose, globally available blocks, this will be 'page.xml'.
For example, to add a productfinder template to the three column layout, you need to edit page.xml and within the
<block type="page/html" name="root" output="toHtml" template="page/3columns.phtml">
...
</block>
block add the following code near the closing </block>:
<block type="core/template" name="my_product_finder" as="my_product_finder" template="templatedir/productfinder.phtml"/>
Type="core/template' refers to a Magento class Mage_Core_Block_Template. This type can be different if you want a specific type of block. But core/template is the simplest way to include some text on a page. The 'name' and 'as' attributes allow you to reference the block in your enclosing templates, e.g. 3column.phtml, or other layout .xml files. The template attribute is the relative path to the text template you want to include and is relative to the theme template root i.e. app/design/frontend/<package>/<theme>/templates.
Once you have created a layout definition for your block, including the template on a page is easy. In 3column.phtml, for example, simply put <?php $this->getChildHtml('my_product_finder') ?> and the text will be included. Remember to refresh, or clear Magento's cache first though.
One more element to consider is exclusions. If you put the above code in 3column.phtml, that text will appear on every page that uses that layout template. You may not, for example, want to include it on customer dashboard pages. In this case you will need to define a remove statement within the layout.xml for the group of pages you want to change. In this example, we need to edit customer.xml
In customer.xml (and indeed page.xml) you will see a number of elements similar to <default></default> (which applies to ALL pages), <customer_account></customer_account> (which refers to all pages with the url customer/account/), and <customer_account_edit></customer_account_edit> (which refers to all pages with the url customer/account/edit/). Including your remove declaration in the right element here allows fine grained control over which pages your blocks appear.
In the example here, we want to remove the product finder from ALL customer account pages. Therefore within the <customer_account> element we add the code
<customer_account>
...
<reference name="root">
<remove name="my_product_finder"></remove>
</reference>
</customer_account>
The reference name=root element ensures we are altering the root block, which is the one in which we defined our template block in page.xml. The enclosed remove call, uses the name of the block we created "mns_product_finder" to identify the block we want to remove for these pages.
That's it! All pages that exist under <customer_account> (so all of them) have this block removed.