Posted by: infirock | March 28, 2014

Import Configurable Products in Magento

Import Configurable Products in Magento

This article is a part of the tutorial chain below. It’s suggested to go over the previous posts in order to complete this tutorial.

Configurable Product Importing with Magmi

Importing Configurable Products is another great feature that comes with Magmi, but it can be a bit confusing for some, due to configurable and simple product having different columns and column count.

Start by creating a configurable product manually via the admin to assure that the super attribute and simple product relations are set-up correctly and working. After you successfully created a configurable product to go by, you can start with your configurable product spreadsheet, which requires less column headers due to most coming from the simple products. In a duplicated version of the simple products spreadsheet, cut down the values to the following (but do leave the columns you may require, such as page layout or custom designs if you intend to use them):

store,websites,attribute_set,product_type_id,category_ids,type,configurable_attributes,simples_skus,sku,
has_options,name,product_name,description,short_description,meta_title,meta_description,url_key,url_path,
cleaning_instructions,image,small_image,thumbnail,image_label,thumbnail_label,small_image_label,
options_container,msrp_enabled,msrp_display_actual_price_type,gift_message_available,price,special_price,
weight,msrp,status,is_recurring,visibility,enable_googlecheckout,tax_class_id,is_imported

You may notice that there are a few new column headers above, which are configurable_attributes and simples_skus.

The following are just suggestive notes, of how to successfully import simple/configurable products:

  • SP (Simple Product) CSV: Include the super attribute as a column header, used when you manually created your test configurable product.
  • CP (Configurable Product) CSV: Add the super attribute to this spreadsheet, under the configurable_attributes column.
  • SP CSV: You should not include the categories or category_ids column in your simple products spreadsheet, or just leave them empty.
  • CP CSV: Instead, list the categories in your configurable products CSV.
  • SP CSV: Set the value for the visibility column to Not Visible Individually or to Search if preferred (you can change this after importing simple products if missed, within Magmi configuration for configurable products).
  • SP CSV: The type column should be set to simple.
  • CP CSV: The type column should be configurable on the configurable product spreadsheet.
  • SP & CP CSV: Both spreadsheets should have the same value under attribute_set.
  • CP CSV: List the simple product SKU’s under the simples_skus of the corresponding configurable product, comma separated. These will be the products you intend to link the CP with.
  • Lastly, import the simple products first, then follow with the configurable product imports.
Posted by: infirock | March 6, 2014

To shutdown or Restart the system in Ubunto or Linux

Open your terminal with CTRL+ALT+T and do these following commands

To shutdown the system:

sudo shutdown -h now 

To restart:

sudo reboot

& one more command for restart:

sudo shutdown -r now

Another way as one of the user mentioned.

For shutdown:

sudo halt

or:

sudo init 0 

For restart:

sudo init 6

You can get more info on the shutdown command by using one of the following:

  • shutdown --help
  • man shutdown

In general, Create Hosting customers shouldn’t need compilation enabled, since our Magento Hosting Plans come pre-configured and optimised with APC cache. However, if you accidentally enabled compilation, or if you are actively using compilation instead of APC Cache and need to disable compilation to perform an upgrade, install or remove an extension etc, then you will need to disable it again.

There are two ways in which this can be done:

1. Via Magento admin

Navigate to System > Tools > Compilation page and click on Disable button
Navigate to System > Cache Management screen and use Flush Cache button.

2. Via SFTP, by editing the includes/config.php file

To disable compilation in Magento, edit includes/config.php. At around line 28, uncomment the first line and comment out the second:

#define(‘COMPILER_INCLUDE_PATH’, dirname(__FILE__).DIRECTORY_SEPARATOR.’src’);
define(‘COMPILER_COLLECT_PATH’, dirname(__FILE__).DIRECTORY_SEPARATOR.’stat’);

3. Via SSH

php -f shell/compiler.php -- disable
php -f shell/compiler.php -- clear

Check the status:

# php -f shell/compiler.php -- state
Compiler Status:          Disabled
Compilation State:        Not Compiled
Collected Files Count:    0
Compiled Scopes Count:    0

$ php shell/compiler.php

Usage:  php -f compiler.php — [options]

  state          Show Compilation State
  compile       Run Compilation Process
  clear         Disable Compiler include path and Remove compiled files
  enable        Enable Compiler include path
  disable       Disable Compiler include path
  help          This help

Clear the cache:

rm -rf var/cache/* var/session/*

Note for recent versions of Magento – Broken

Seems like this tutorial doesn’t work anymore for recent versions (1.6.2 for me), because of magento prices indexing. Price is not calculated on the fly on frontend anymore, and indexing does not call the event “catalog_product_get_final_price”. To be confirmed.

Attention: Disable Mage_Compiler

System → Tools → Compilation → In the top right corner there are 2 buttons, make sure the first one is labeled ‘Disabled’.

Overview

Apart from the powerful OOP way of customizing Magento, which is overriding methods by subclassing Magento’s core Blocks and Models, there is another way to plug in customizations in key flow areas of your Magento eCommerce shop.

Referred to as the Event-Observer methodology, Magento has been programmed to raise events in crucial areas of the flow Using these events for customizations can keep upgrading a much more simple task that does not require fiddling around with Magento’s core source code. An example would be the event ‘catalog_product_save_after’ which will be raised by Magento immediately after a product is saved.

Terminology

Event An Event is something that occurs in a certain place during a particular sequence flow. Say once a customer completes an order, the flow sequence would be to

1. Save the order details 2. Send e-mail confirmation to customer

Events may be emitted before or after each of these flow points to introduce custom logic.

Observer An Observer is an event handler. It listens to any event it is attached to and accordingly reacts to the event.

Customization – Using Events vs. Overriding classes

Simply put, think about overriding existing core logic if you need to completely change or if you need to extend core logic and your new logic is going to be reused elsewhere. Use events if you are fine with existing logic provided by Magento and need to add to the core logic.

Example Usage

This example tries to use the Event-Observer technique to introduce a percentage discount for each product. Currently Magento supports special price functionality without a % discount. So we would use this opportunity to customize magento to introduce %discount at a product level.

Before starting, the aim is to ensure that the percentage discount is considered for a simple product when a product is displayed. The event is raised in the class Mage_Catalog_Model_Product_Type_Price→getFinalPrice() (Magento 1.3.0 file: app/code/core/Mage/Catalog/Model/Product/Type/Price.php). The event is raised by the line Mage::dispatchEvent(’catalog_product_get_final_price’,array(’product’⇒$product));

The event that we are about to handle is catalog_product_get_final_price which is going to help us add logic to consider the percentage discount.

Step 1

Create a new attribute ‘percent_discount‘.

Attrib Identifier –percent_discount , Scope – Store View , Catalog I/p – Text , Unique Value – No , Values Required – NoInput , Validation –Decimal , Apply to Configurable/All Product Types – Yes

Use in quick search – No , Advanced Search – No , Comparable – No , Visibile on Frontend – Yes , Attribute Label – % Discount

Step 2

Add this new attribute to your attributeset. If your product’s attributeset is ‘default‘, add the new ‘percent_discount’ attribute to this attributeset under “prices” attribute group.

Step 3

Register a new custom local module under name ‘Xyz’. For this create file ‘Xyz.xml’ under directory ‘app/etc/modules/’. File contents are –

  1. <?xml version=”1.0″?>
  2. <config>
  3.   <modules>
  4.     <Xyz_Catalog>
  5.       <codePool>local</codePool>
  6.       <active>true</active>
  7.     </Xyz_Catalog>
  8.   </modules>
  9. </config>

Step 4

Register the event with its Observer. Create file ‘config.xml’ under directory ‘app/code/local/Xyz/Catalog/etc/’ with contents as –

  1. <?xml version=”1.0″?>
  2. <config>
  3.   <global>
  4.     <models>
  5.         <xyzcatalog>
  6.              <class>Xyz_Catalog_Model</class>
  7.         </xyzcatalog>
  8.     </models>
  9.     <events>
  10.       <catalog_product_get_final_price>
  11.         <observers>
  12.           <xyz_catalog_price_observer>
  13.             <type>singleton</type>
  14.             <class>Xyz_Catalog_Model_Price_Observer</class>
  15.             <method>apply_discount_percent</method>
  16.           </xyz_catalog_price_observer>
  17.         </observers>
  18.       </catalog_product_get_final_price>
  19.     </events>
  20.   </global>
  21. </config>

Step 5

Creating the Observer. Create the directory structure – app/code/local/Xyz/Catalog/Model/Price/. Place the php code below in a file by name ‘Observer.php’ in the directory just created.

  1. <?php
  2. class Xyz_Catalog_Model_Price_Observer
  3. {
  4.     public function __construct()
  5.     {
  6.     }
  7.     /**
  8.      * Applies the special price percentage discount
  9.      * @param   Varien_Event_Observer $observer
  10.      * @return  Xyz_Catalog_Model_Price_Observer
  11.      */
  12.     public function apply_discount_percent($observer)
  13.     {
  14.       $event = $observer->getEvent();
  15.       $product = $event->getProduct();
  16.       // process percentage discounts only for simple products
  17.       if ($product->getSuperProduct() && $product->getSuperProduct()->isConfigurable()) {
  18.       } else {
  19.         $percentDiscount = $product->getPercentDiscount();
  20.         if (is_numeric($percentDiscount)) {
  21.           $today = floor(time()/86400)*86400;
  22.           $from = floor(strtotime($product->getSpecialFromDate())/86400)*86400;
  23.           $to = floor(strtotime($product->getSpecialToDate())/86400)*86400;
  24.           if ($product->getSpecialFromDate() && $today < $from) {
  25.           } elseif ($product->getSpecialToDate() && $today > $to) {
  26.           } else {
  27.             $price = $product->getPrice();
  28.             $finalPriceNow = $product->getData(‘final_price’);
  29.             $specialPrice = $price – $price * $percentDiscount / 100;
  30.             // if special price is negative – negate the discount – this may be a mistake in data
  31.             if ($specialPrice < 0)
  32.               $specialPrice = $finalPriceNow;
  33.             if ($specialPrice < $finalPriceNow)
  34.               $product->setFinalPrice($specialPrice); // set the product final price
  35.           }
  36.         }
  37.       }
  38.       return $this;
  39.     }
  40. }

Step 6

NOTE: To get Magento to load the changed local code configuration, one needs to (temporary) disable caching of code configuration. In admin panel, go to System > Cache management and uncheck the Configuration option.

Set the discount on the product. Navigate to the catalog product on the admin login and edit a product. Set the percentage discount for this product (under prices subtab).

Step 7

Navigate to the product details page on the front end and observe that the new discount has taken effect. To be noted here is that, on all other screens where discounted price is required. An example here is the search results screen, where you would need to add this new attribute to the select query search attributes in method Mage_CatalogSearch_Block_Result→_getProductCollection()

  1. $_productCollection= $_productCollection->addAttributeToSelect(‘percent_discount’);

List of Events

The events list is continually expanding in the Magento core and with extensions you can easily add even more events. In v1.4 there are nearly 300 events compared to 223 in v1.3 and 140 in v1.2. On a Unix like system you can easily determine the available events in your particular build by grepping through the Local, Core and Community folders of your install eg change to the Magento root folder and type

  1. grep -rin -B2 -A2 “Mage::dispatchEvent” app/* > events.txt

This will create a file events.txt containing all the events located in the app folder.

If you prefere a shell script check out the blog post on http://www.edmondscommerce.co.uk/blog/magento/magento-events-cheat-sheet-grep-works-for-any-version/

A list of events from earlier releases

Other Notes

(From an unknown Wiki user) I found that step 4 was wrong, here is how I got it to work:

Created: local/Company/Module/Model/Observer.php as class Company_Module_Model_Observer

Then I played around with the XML and watched the file it was trying to include (which with the above instructions was looking for classes called Mage_Company). Then I used this XML exactly, changed EVENT_TO_HOOK and ‘Company’ and ‘company’ and ‘module’. Pay attention to case. (Note from the editor: the case of “company_module_model_observer” seems to be wrong. Won’t problably work on case-sensitive file systems).

<events>
  <EVENT_TO_HOOK>
    <observers>
      <module>
        <type>singleton</type>
        <class>company_module_model_observer</class>
        <method>methodToCall</method>
      </module>
    </observers>
  </EVENT_TO_HOOK>     
</events>
Always backup the database before you run any queries.

UPDATE sales_flat_order_grid SET status = 'processing';  
UPDATE sales_flat_order SET state = 'processing', status = 'processing';
====================================

If you want to create new order statuses (not states) and assign them to a particular state you need to use the sales/order_status model. It’s pretty easy:

1
2
3
$status = Mage::getModel('sales/order_status');
$status->setStatus('status_code');
$status->setLabel('status_label');

Then you can assign the state with the assignState method:

1
2
$status->assignState('processing');
$status->save();
=============================================
Recently my task was to allow client to have different "type" of order in Magento. Requirement was that these 
orders need to have their own grid in Magento admin, and also that they need to be processed somewhat differently 
than regular orders. I have solved this task by adding new order states and statuses to be used only for this type 
of orders. To support this design it was also required to create new payment method so that orders of this type 
can be initiated into new order state automatically after being placed using this payment method. In this article 
I'm bringing you some code snippets and notes on how to implement this kind of solution.

Introduction

Before getting into the code, if feel the need to explain order status – state concept of Magento. General idea is that you have order states and order statuses that belong to specific order states. In my opinion two “entities” were introduced to increase granularity trough out the life cycle of an order.

First a few words about order statuses as something user has under control from Magento admin (System -> Order Statuses). Order statuses are kept inside sales_order_status table whose structure and default contents is displayed on the following listings.

Table sales_order_status structure
mysql> DESCRIBE sales_order_status;
+--------+--------------+------+-----+---------+-------+
| Field  | Type         | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+-------+
| status | varchar(32)  | NO   | PRI | NULL    |       |
| label  | varchar(128) | NO   |     | NULL    |       |
+--------+--------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
Table sales_order_status data
mysql> SELECT * FROM sales_order_status;
+--------------------------+--------------------------+
| status                   | label                    |
+--------------------------+--------------------------+
| canceled                 | Canceled                 |
| closed                   | Closed                   |
| complete                 | Complete                 |
| fraud                    | Suspected Fraud          |
| holded                   | On Hold                  |
| payment_review           | Payment Review           |
| paypal_canceled_reversal | PayPal Canceled Reversal |
| paypal_reversed          | PayPal Reversed          |
| pending                  | Pending                  |
| pending_payment          | Pending Payment          |
| pending_paypal           | Pending PayPal           |
| processing               | Processing               |
+--------------------------+--------------------------+
12 rows in set (0.00 sec)

Next there are order states, something user can not change from Magento admin. Order states as well as mappings of orders statuses to states are kept inside sales_order_status_state table. For structure and data please refer to following listings.

Table sales_order_status_state structure
mysql> DESCRIBE sales_order_status_state;
+------------+----------------------+------+-----+---------+-------+
| Field      | Type                 | Null | Key | Default | Extra |
+------------+----------------------+------+-----+---------+-------+
| status     | varchar(32)          | NO   | PRI | NULL    |       |
| state      | varchar(32)          | NO   | PRI | NULL    |       |
| is_default | smallint(5) unsigned | NO   |     | NULL    |       |
+------------+----------------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
Table sales_order_status_state data
mysql> SELECT * FROM sales_order_status_state;
+-----------------+-----------------+------------+
| status          | state           | is_default |
+-----------------+-----------------+------------+
| canceled        | canceled        |          1 |
| closed          | closed          |          1 |
| complete        | complete        |          1 |
| fraud           | payment_review  |          0 |
| holded          | holded          |          1 |
| payment_review  | payment_review  |          1 |
| pending         | new             |          1 |
| pending_payment | pending_payment |          1 |
| processing      | processing      |          1 |
+-----------------+-----------------+------------+
9 rows in set (0.00 sec)

Important thing to point out is that information that ends up being attached to order (sales_flat_order table) is order status information. Because of that we can freely say that order states are used simply to logically organize order statuses.

The code

First piece of code is one that isn’t actually related to order states and statuses, but it is required to allow us to have another “type” of order as described at the beginning of this article. I’m referring to Magento installer script for adding new order attribute to order EAV entity and new column to it’s close cousin sales_flat_order_grid table. Latter one contains subset of order data and it’s purpose is to increase performance on Orders grid in Magento admin.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
$installer = $this;
$installer->startSetup();

$installer->addAttribute(
    'order',
    'is_specialorder',
    array(
        'type' => 'int',
        'default' => 0,
        'grid' => true,
        'unsigned'  => true,
    )
);

$installer->endSetup();

The grid parameter is what instructs Magento to keep this new attribute and it’s clone from sales_flat_order_grid table in sync.

Second piece of code is the actual code for adding new order state and 4 statuses.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
<?php
$installer = $this;

// Required tables
$statusTable = $installer->getTable('sales/order_status');
$statusStateTable = $installer->getTable('sales/order_status_state');

// Insert statuses
$installer->getConnection()->insertArray(
    $statusTable,
    array(
        'status',
        'label'
    ),
    array(
        array('status' => 'specialorder_pending', 'label' => 'Special Order Pending'),
        array('status' => 'specialorder_processing', 'label' => 'Special Order Processing'),
        array('status' => 'specialorder_complete', 'label' => 'Special Order Complete'),
        array('status' => 'specialorder_canceled', 'label' => 'Special Order Canceled')
    )
);

// Insert states and mapping of statuses to states
$installer->getConnection()->insertArray(
    $statusStateTable,
    array(
        'status',
        'state',
        'is_default'
    ),
    array(
        array(
            'status' => 'specialorder_pending',
            'state' => 'specialorder_state',
            'is_default' => 1
        ),
        array(
            'status' => 'specialorder_processing',
            'state' => 'specialorder_state',
            'is_default' => 0
        ),
        array(
            'status' => 'specialorder_complete',
            'state' => 'specialorder_state',
            'is_default' => 0
        ),
        array(
            'status' => 'specialorder_canceled',
            'state' => 'specialorder_state',
            'is_default' => 0
        )
    )
);

The is_default parameter isn’t enough for Magento to use this new state with it’s default status when your special order is created. This is because Magento’s built-in payment methods like checkmo assign all new orders to built-in “new” state and “pending” status. To resolve this we need to create our own payment method that is aware of our new order state. If you are just adding order statuses to one of default Magento states, you can skip this step. With imaginary namespace Ournamespace and module name Ourmodule, here’s little XML snippet to get our payment method warmed up:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0"?>

<config>
    <!-- -->
    <default>
        <payment>
            <specialorder_payment_method>
                <active>1</active>
                <model>Ournamespace_Ourmodule_Model_Payment_Specialorder</model>
                <order_status>specialorder_pending</order_status>
                <allowspecific>0</allowspecific>
                <payment_action>init</payment_action>
                <group>offline</group>
            </specialorder_payment_method>
        </payment>
    </default>
    <!-- -->
</config>

Here comes the payment method code that goes into app/code//Ournamespace/Ourmodule/Model/Payment/Specialorder.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

class Ournamespace_Ourmodule_Model_Payment_Specialorder extends Mage_Payment_Model_Method_Abstract
{
    protected $_code = 'specialorder_payment_method';
    protected $_canUseCheckout = false;
    protected $_isInitializeNeeded = true;

    /**
     * Update order state to system configuration
     *
     * @return Mage_Payment_Model_Method_Abstract
    */
    public function initialize($action, $stateObject)
    {
        if(($status = $this->getConfigData('order_status'))) {
            $stateObject->setStatus($status);
            $state = $this->_getAssignedState($status);
            $stateObject->setState($state);
            $stateObject->setIsNotified(true);
        }
        return $this;
    }

    /**
     * Get the assigned state of an order status
     *
     * @param string order_status
     */
    protected function _getAssignedState($status)
    {
        $item = Mage::getResourceModel('sales/order_status_collection')
            ->joinStates()
            ->addFieldToFilter('main_table.status', $status)
            ->getFirstItem();

        return $item->getState();
    }

}

As you can see in the preceding code listing, any order placed using this payment method (referenced using specialorder_payment_method) will go trough initialize() function and will have it’s state and status set to default order status and first order’s state this status is assigned to. If your status is assigned to multiple order states, you can hardcode desired order state code instead of using _getAssignedState() function to obtain this code.

That’s all for today, until next time I wish you all happy coding!

 
Posted by: infirock | January 24, 2014

Magento – Add breadcrumbs on customer account area pages

Posted by: infirock | January 24, 2014

Magento – check if coupon code used

Magento – check if coupon code used

Once on the Onepage Checkout page, I need to track if the customer has used any specific coupon code. This can be checked by the checkout session.

Use this code to hunt up the coupon code. This code will return the coupon code if used or empty result.

<?php
$coupon_code = Mage::getSingleton('checkout/session')->getQuote()->getCouponCode();
if($coupon_code){
    echo "coupon used";
}else{
    echo "coupon not used";
}
?>

Magento – get the block class name

Magento Blocks are the view classes of modules that handle the front-end interface of the website.

To get the block class name of any block, use the following code.

<?php
//assuming the block code is "catalog/product"
$block = “catalog/product”; 
//retrieve the class name
$block_class_name = Mage::getConfig()->getBlockClassName($block);
echo $block_class_name; 
//now this will be the output - Mage_Catalog_Block_Product
?>
Posted by: infirock | January 24, 2014

Magento – programmatically update product details

Magento – programmatically update product details

E-commerce programming in Magento represents, probably the most creative outlet for a developer. Magento offers a ready to use and powerful catalog to manage products and categories easily and effectively. Creating new attributes, products and categories are easy tasks for both developers or store owners.

Beside the Magento Admin interface, its custom modular structure offers freedom for developers to build and modify the products programmatically. Updating products details programmatically can be accomplished by creating custom module or using any existing module. The given example is working on a custom module.

Scenario:

We have product id and we need to update the product details eg. updating name, product description, short description, product status etc., but it is not just limited to this, we can update other details of the product using the given example code.

<?php
class Mymodule_ModuleName_IndexController extends Mage_Core_Controller_Front_Action
{
    public function updateproductAction(){
        //this code is running under a controllers action method.

        //important
        Mage::setIsDeveloperMode(true);
        Mage::app()->setCurrentStore(Mage::getModel('core/store')->load(Mage_Core_Model_App::ADMIN_STORE_ID));

        //load product
        $product = Mage::getModel("catalog/product")->load(135);

        //Update product details
        $product->setStatus(1); 
        $product->setName('New product name');
        $product->setDescription(addslashes("Product's full description here."));
        $product->setShortDescription(addslashes("Product's short description here."));
        //using the setAttributeName we can update any other detail of the product.

        try { 
            $product->save(); 
            echo "Product updated";
        }catch(Exception $ex) { 
            //Handle the error 
        } 
    }
}
Posted by: infirock | January 24, 2014

Delete product programmatically

Magento – Delete product programmatically

To delete a product In magento use the following code.
http://www.techdilate.com/code/magento-delete-product-programmatically/

This code will help to delete the product

<?php
Mage::register("isSecureArea", 1);
$product_id = 2; //use your own product id
try{
    Mage::getModel("catalog/product")->load( $product_id  )->delete();
}catch(Exception $e){
    echo "Delete failed";
}
?>

Programmatically removing product images in Magento

From time to time you might want to remove images from a large amound of products in Magento. I had this exact situation recently trying to help someone in the Magento IRC channel (#magento).

In our case, we needed to go through all configurable products and remove the images for the simple products associated with them. Obviously this would be very time consuming to do by hand, so I put together a PHP script to do it for me.

Here is the code to remove the images (media gallery) for an individual product:

$_product = Mage::getModel('catalog/product')->load('1234');
$mediaApi = Mage::getModel("catalog/product_attribute_media_api");
try {
    $items = $mediaApi->items($_product->getId());
    foreach($items as $item) {
        echo ($mediaApi->remove($_product->getId(), $item['file']));
    }
} catch (Exception $exception){
    var_dump($exception);
    die('Exception Thrown');
}

Note: There is actually no need for the first line. If you know the ID, that’s all the Media API needs to work. You don’t need to load the product object – it’s just assumed you probably already did. In theory, this could work from a CSV of product IDs.

http://www.magentocommerce.com/boards/viewthread/36558/

Here’s how I deleted all the images from the file system (media/catalog/product) which were not referenced in catalog_product_entity_media_gallery. It skips the cache folder.
Notes:
1) Make sure you backup your media/catalog/product and clear your image cache after you do this in case things go terribly wrong.
2) You have to uncomment two lines for this to work.
3) Tested in 1.4.0.1 only.

<?php
/**
* Delete Unused Product Images.
*
*/

if ( ! isset($_SERVER['DOCUMENT_ROOT'] ) ) {
$_SERVER['DOCUMENT_ROOT'] = str_replace( '\\',DS, substr($_SERVER['SCRIPT_FILENAME'], 0, 0-strlen($_SERVER['PHP_SELF']) ) );
}

define('PATH_TO_MAGENTO', rtrim($_SERVER['DOCUMENT_ROOT'],'/')); // update accordingly
require_once PATH_TO_MAGENTO.'/app/Mage.php';
Mage::app()->setCurrentStore(Mage_Core_Model_App::ADMIN_STORE_ID);

$connection = Mage::getSingleton('core/resource')->getConnection('core_write');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Delete Unused Product Images</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<h1>Delete Unused Product Images</h1>
<p><a href="?delete=1" onclick="return confirm('Do you want to delete all unused Product Images?')">Delete Images</a></p>
<div style="white-space: pre">
<?php
if(isset($_GET['delete']) && $_GET['delete'] === '1') {
$root = getcwd() . '/media/catalog/product';
$delFileCount = 1;
deleteUnusedImages($root, $root, $connection);
if($delFileCount == 1) {
echo 'No images to delete';
}
}

function deleteUnusedImages($d, $root, $connection, $l = 0) {
global $delFileCount;

$x = 'jpg|gif';
$files = array();
foreach(array_diff(scandir($d), array('.','..')) as $f) {
if($f != 'cache') {
if(is_file($d .DS . $f) && ( ($x) ? ereg($x . '$', $f) : 1) ) {
$files[] = $f;
} else if(is_dir($d .DS . $f)) {
deleteUnusedImages($d .DS . $f, $root, $connection, $l + 1);
// If the dir is empty delete it
if(!count(array_diff(scandir($d .DS . $f), array('.','..')))) {
echo 'Delete empty dir ' . $d .DS . $f;
//rmdir($d .DS . $f);
echo '. OK.' . "\n";
}
}
}
}

if(count($files)) {
$sql = 'select * from (';

foreach($files as $i => $f) {
$sql .= "select '" . mysql_real_escape_string(str_replace($root, '', $d)) .DS . $f . "' as value ";
if($i < count($files) - 1) {
$sql .= ' union all ';
}
}
$sql .= ' ) as b ' .
'where value not in ( ' .
'    select value '.
'    from catalog_product_entity_media_gallery ' .
')';

$rows = $connection->fetchAll($sql);

if(count($rows)) {
foreach($rows as $f) {
// replace the wrong separator
$del = str_replace((DS == '/') ? '\\' : '/', DS, $root . $f['value']);
echo $delFileCount++ . ' ' . $del;
//unlink($del);
echo '. OK' . "\n";
}
}
}
flush();
}
?>
</div>
</body>
</html>

References:
Posted by: infirock | January 24, 2014

How to use jQuery’s .noConflict() functionality

How to use jQuery’s .noConflict() functionality

About jQuery.noConflict();

jQuery is a great javascript library that makes your javascript development more interestin, exciting and effective. Most of us use jQuery without even knowing how it works or how to write jQuery code. We just take jQuery plugin and plug it in into our web pages. We go so crazy that we don’t just plug in jQuery plugins, but also end up with MooTools, prototype.js plugins in our pages and that’s probably when the problems start. All those plugins work perfect on their own but when you add another javascript framework plugin they start to conflict.

The good news is that jQuery made sure it does not conflict with other plugins. All you need to use is jQuery’s .noConflict() method like this jQuery.noConflict(); before you write any jQuery code.

Example use

Here is an exaple of its use taken from jQuery.noConflict() post on jQuery blog:

<html>
  <head>
  <script src="prototype.js"></script>
  <script src="jquery.js"></script>
  <script>
    jQuery.noConflict();
    // Use jQuery via jQuery(...)
    jQuery(document).ready(function(){
        jQuery("div").hide();
    });
    // Use Prototype with $(...), etc.
    $('someid').hide();
  </script>
  </head>
  <body></body>
</html>

When you call .noConflict() jQuery will return $() to it’s previous owner and you will need to use jQuery() instead of shorthand $() function.

You can also use the following code snippets to still use $() in your code, but with one drawback, you will not have access to your other library’s $() method.

// Method 1
jQuery(document).ready(function($){
    $("div").hide();
});

// Method 2
(function($) {
    /* some code that uses $ */ 
})(jQuery);

var jq = $.noConflict();
jq(document).ready(function(){
jq(“button”).click(function(){
jq(“p”).text(“jQuery is still working!”);
});
});

TIP: Don’t forget that you can always assign jQuery to any other variable name to use it as your shorthand: var $_ = jQuery;

References:

jQuery.noConflict()

http://www.w3schools.com/jquery/jquery_noconflict.asp

http://www.google.co.in/url?sa=t&rct=j&q=&esrc=s&source=web&cd=10&cad=rja&ved=0CIEBELcCMAk&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DDRHnWD_2DYM&ei=KVTiUoPSFKSziAfHhoHQAw&usg=AFQjCNGT30fZAGYNatLInxM7Adqxeao_WA&bvm=bv.59930103,d.aGc

Older Posts »

Categories