Back to blog home

How to mirror/duplicate Magento websites/stores

It's been a while since I wrote my last blog post about Magento, so let's start a new series.
I will describe the process of creating a new website and store and populating it with existing data from another store.

We have this situation:

  • multiple websites (on different domains)
  • multiple store views (for different languages)
  • we want a new website (on a new domain) with only one store view (one language)

Manually configuring the described situation in Magento through the admin panel can take a while, since there is a lot of clicking, saving and adding data.

We are going to create a new website and assign all relevant data using SQL update scripts.

So the things that we are going to do with our SQL install/upgrade scripts are:

  • create a new website, assign root category and add a store view
  • copy and assign all configuration related data
  • add some specific data, like store name, url, etc. (this can differs by your needs - e.g. different shipping and payment methods)
  • copy and assign all CMS pages and static block-related data
  • copy and assign all category-related configuration data
  • copy and assign all store products' attribute labels and option data
  • assign all products

Creating the new website, store and proper store views

//#addWebsite
/** @var $website Mage_Core_Model_Website */
$website = Mage::getModel('core/website');
$website->setCode('code_of_your_new_website')
    ->setName('name_of_your_new_website')
    ->save();

//#addStoreGroup
/** @var $storeGroup Mage_Core_Model_Store_Group */
$storeGroup = Mage::getModel('core/store_group');
$storeGroup->setWebsiteId($website->getId())
    ->setName('name_of_your_new_group')
    ->setRootCategoryId('root_category_id')
    ->save();

//#addStore
/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->setCode('store_code')
    ->setWebsiteId($storeGroup->getWebsiteId())
    ->setGroupId($storeGroup->getId())
    ->setName('store_view_name')
    ->setIsActive(1)
    ->save();

 

Copy all related configuration data from existing store view of existing website to new website/store

/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->load('store_code','code');
$storeId = $store->getStoreId();
$websiteId = $store->getWebsiteId();

/* initiate installer */
$installer = $this;
/* start setup */
$installer->startSetup();
/* do setup */
$installer->run("

# DEFINE
SET @to_website := $websiteId; # the websites_id of the recipient store
SET @to_store := $storeId; # the store_id of the recipient store
SET @from_website := 3; # the websites_id of the donor store
SET @from_store := 5; # the store_id of the donor store

/** core_config_data */
DELETE FROM core_config_data
WHERE scope = 'websites'
AND scope_id = @to_website;
DELETE FROM core_config_data
WHERE scope = 'stores'
AND scope_id = @to_store;

INSERT INTO core_config_data (
scope,
scope_id,
path,
value
) SELECT
scope,
@to_website,
path,
value
FROM core_config_data
WHERE scope = 'websites'
AND scope_id = @from_website;

INSERT INTO core_config_data (
scope,
scope_id,
path,
value
) SELECT
scope,
@to_store,
path,
value
FROM core_config_data
WHERE scope = 'stores'
AND scope_id = @from_store;
");
/* end setup */
$installer->endSetup();

Change specific config data for new store

/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->load('store_code','code');
$storeId = $store->getStoreId();
$websiteId = $store->getWebsiteId();

$_config = new Mage_Core_Model_Config();
$_options = array(
    'web/url/use_store' => '0',
    'design/theme/template' => 'your_template_folder',
    'design/theme/skin' => 'your_skin_folder',
    'design/theme/layout' => 'your_layout_folder',
    'web/secure/base_url' => 'https://www.your.new.domain.xxx/',
    'web/unsecure/base_url' => 'http://www.your.new.domain.xxx/',
    'general/store_information/name' => 'your_store_name',
    'general/country/default' => 'COUNTRY_CODE',
    'general/country/allow' => 'COUNTRY_CODE',
);

foreach( $_options as $_path => $_value ) {
    $_config->saveConfig( $_path, $_value, 'websites', $websiteId );
}

Copy all category-related configuration data from existing store view of existing website to new website/store

/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->load('store_code','code');
$storeId = $store->getStoreId();
$websiteId = $store->getWebsiteId();

/* initiate installer */
$installer = $this;
/* start setup */
$installer->startSetup();
/* do setup */
$installer->run("

# DEFINE
SET @to_website := $websiteId; # the websites_id of the recipient store
SET @to_store := $storeId; # the store_id of the recipient store
SET @from_website := 3; # the websites_id of the donor store
SET @from_store := 5; # the store_id of the donor store

/** catalog_category_entity_int */
DELETE FROM catalog_category_entity_int
WHERE store_id = @to_store;

INSERT INTO catalog_category_entity_int (
    entity_type_id,
    attribute_id,
    store_id,
    entity_id,
    value
) SELECT
    entity_type_id,
    attribute_id,
    @to_store,
    entity_id,
    value
FROM catalog_category_entity_int
WHERE store_id = @from_store;

/** catalog_category_entity_text */
DELETE FROM catalog_category_entity_text
WHERE store_id = @to_store;

INSERT INTO catalog_category_entity_text (
    entity_type_id,
    attribute_id,
    store_id,
    entity_id,
    value
) SELECT
    entity_type_id,
    attribute_id,
    @to_store,
    entity_id,
    value
FROM catalog_category_entity_text
WHERE store_id = @from_store;

/** catalog_category_entity_varchar */
DELETE FROM catalog_category_entity_varchar
WHERE store_id = @to_store;

INSERT INTO catalog_category_entity_varchar (
    entity_type_id,
    attribute_id,
    store_id,
    entity_id,
    value
) SELECT
    entity_type_id,
    attribute_id,
    @to_store,
    entity_id,
    value
FROM catalog_category_entity_varchar
WHERE store_id = @from_store;
");

/* end setup */
$installer->endSetup();

 

Copy all CMS pages and static block-related data from existing store view of existing website to new website/store

/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->load('store_code','code');
$storeId = $store->getStoreId();
$websiteId = $store->getWebsiteId();

/* initiate installer */
$installer = $this;
/* start setup */
$installer->startSetup();
/* do setup */
$installer->run("

# DEFINE
SET @to_website := $websiteId;
SET @to_store := $storeId;
SET @from_website := 3;
SET @from_store := 5;

/** cms_block_store */
DELETE FROM cms_block_store
WHERE store_id = @to_store;

INSERT INTO cms_block_store (
    block_id,
    store_id
) SELECT
    block_id,
    @to_store
FROM cms_block_store
WHERE store_id = @from_store;

/** cms_page_store */
DELETE FROM cms_page_store
WHERE store_id = @to_store;

INSERT INTO cms_page_store (
    page_id,
    store_id
) SELECT
    page_id,
    @to_store
FROM cms_page_store
WHERE store_id = @from_store;
");

/* end setup */
$installer->endSetup();

 

Alter category tables for proper re-indexing of new flat table

/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->load('store_code','code');
$storeId = $store->getStoreId();
$websiteId = $store->getWebsiteId();

/* initiate installer */
$installer = $this;
/* start setup */
$installer->startSetup();
/* do setup */
$installer->run("
    ALTER TABLE catalog_category_entity ENGINE=INNODB;
    ALTER TABLE catalog_product_entity ENGINE=INNODB;
    ALTER TABLE core_store ENGINE=INNODB;
");

/** reindex Category Flat Data */
/** @var  $process Mage_Index_Model_Process*/
$process = Mage::getModel('index/process')->load(5);
$process->reindexAll();

/* end setup */
$installer->endSetup();

 

Copy all Store Product’s Attribute Labels and Options from existing store view of existing website to new website/store

/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->load('store_code','code');
$storeId = $store->getStoreId();
$websiteId = $store->getWebsiteId();

/* initiate installer */
$installer = $this;
/* start setup */
$installer->startSetup();
/* do setup */
$installer->run("

# DEFINE
SET @to_website := $websiteId;
SET @to_store := $storeId;
SET @from_website := 3;
SET @from_store := 5;

/** eav_attribute_label */
DELETE FROM eav_attribute_label
WHERE store_id = @to_store;

INSERT INTO eav_attribute_label (
    attribute_id,
    store_id,
    value
) SELECT
    attribute_id,
    @to_store,
    value
FROM eav_attribute_label
WHERE store_id = @from_store;

/** eav_attribute_option_value */
DELETE FROM eav_attribute_option_value
WHERE store_id = @to_store;

INSERT INTO eav_attribute_option_value (
    option_id,
    store_id,
    value
) SELECT
    option_id,
    @to_store,
    value
FROM eav_attribute_option_value
WHERE store_id = @from_store;
");

/* end setup */
$installer->endSetup();

 

And finally assign all products. Especially useful if you have a larger number of products (tens of thousands) because Magento's admin grid is not good enough for assigning them all to new store.

 

Copy all product-related data from existing store view of existing website to new website/store

/** @var $store Mage_Core_Model_Store */
$store = Mage::getModel('core/store');
$store->load('store_code','code');
$storeId = $store->getStoreId();
$websiteId = $store->getWebsiteId();

/* initiate installer */
$installer = $this;
/* start setup */
$installer->startSetup();
/* do setup */
$installer->run("
# DEFINE
SET @to_store := $storeId;
SET @from_store := 5;

/** catalog_product_entity */
# PROCESS datetime VALUES
DELETE FROM catalog_product_entity_datetime
WHERE store_id = @to_store;
INSERT INTO catalog_product_entity_datetime (
    store_id,
    entity_type_id,
    attribute_id,
    entity_id,
    value
) SELECT
    @to_store,
    entity_type_id,
    attribute_id,
    entity_id,
    value
FROM catalog_product_entity_datetime
WHERE store_id = @from_store;

# PROCESS decimal VALUES
DELETE FROM catalog_product_entity_decimal
WHERE store_id = @to_store;
INSERT INTO catalog_product_entity_decimal (
    store_id,
    entity_type_id,
    attribute_id,
    entity_id,
    value
) SELECT
    @to_store,
    entity_type_id,
    attribute_id,
    entity_id,
    value
FROM catalog_product_entity_decimal
WHERE store_id = @from_store;

# PROCESS gallery VALUES
DELETE FROM catalog_product_entity_gallery
WHERE store_id = @to_store;
INSERT INTO catalog_product_entity_gallery (
    store_id,
    entity_type_id,
    attribute_id,
    entity_id,
    position,
    value
) SELECT
    @to_store,
    entity_type_id,
    attribute_id,
    entity_id,
    position,
    value
FROM catalog_product_entity_gallery
WHERE store_id = @from_store;

# PROCESS int VALUES
DELETE FROM catalog_product_entity_int
WHERE store_id = @to_store;
INSERT INTO catalog_product_entity_int (
    store_id,
    entity_type_id,
    attribute_id,
    entity_id,
    value
) SELECT
    @to_store,
    entity_type_id,
    attribute_id,
    entity_id,
    value
FROM catalog_product_entity_int
WHERE store_id = @from_store;

# PROCESS text VALUES
DELETE FROM catalog_product_entity_text
WHERE store_id = @to_store;
INSERT INTO catalog_product_entity_text (
    store_id,
    entity_type_id,
    attribute_id,
    entity_id,
    value
) SELECT
    @to_store,
    entity_type_id,
    attribute_id,
    entity_id,
    value
FROM catalog_product_entity_text
WHERE store_id = @from_store;

# PROCESS varchar VALUES
DELETE FROM catalog_product_entity_varchar
WHERE store_id = @to_store;
INSERT INTO catalog_product_entity_varchar (
    store_id,
    entity_type_id,
    attribute_id,
    entity_id,
    value
) SELECT
    @to_store,
    entity_type_id,
    attribute_id,
    entity_id,
    value
FROM catalog_product_entity_varchar
WHERE store_id = @from_store;

/** catalog_product_entity_media_gallery */
# PROCESS value VALUES
DELETE FROM catalog_product_entity_media_gallery_value
WHERE store_id = @to_store;
INSERT INTO catalog_product_entity_media_gallery_value (
    store_id,
    value_id,
    label,
    position,
    disabled
) SELECT
    @to_store,
    value_id,
    label,
    position,
    disabled
FROM catalog_product_entity_media_gallery_value
WHERE store_id = @from_store;

/** catalog_product_option */
# PROCESS price VALUES
DELETE FROM catalog_product_option_price
WHERE store_id = @to_store;
INSERT INTO catalog_product_option_price (
    store_id,
    option_id,
    price,
    price_type
) SELECT
    @to_store,
    option_id,
    price,
    price_type
FROM catalog_product_option_price
WHERE store_id = @from_store;

# PROCESS title VALUES
DELETE FROM catalog_product_option_title
WHERE store_id = @to_store;
INSERT INTO catalog_product_option_title (
    store_id,
    option_id,
    title
) SELECT
    @to_store,
    option_id,
    title
FROM catalog_product_option_title
WHERE store_id = @from_store;

# PROCESS type_price VALUES
DELETE FROM catalog_product_option_type_price
WHERE store_id = @to_store;
INSERT INTO catalog_product_option_type_price (
    store_id,
    option_type_id,
    price,
    price_type
) SELECT
    @to_store,
    option_type_id,
    price,
    price_type
FROM catalog_product_option_type_price
WHERE store_id = @from_store;

# PROCESS type_title VALUES
DELETE FROM catalog_product_option_type_title
WHERE store_id = @to_store;
INSERT INTO catalog_product_option_type_title (
    store_id,
    option_type_id,
    title
) SELECT
    @to_store,
    option_type_id,
    title
FROM catalog_product_option_type_title
WHERE store_id = @from_store;

/** catalog_product_super_attribute */
# PROCESS label VALUES
DELETE FROM catalog_product_super_attribute_label
WHERE store_id = @to_store;
INSERT INTO catalog_product_super_attribute_label (
    store_id,
    product_super_attribute_id,
    use_default,
    value
) SELECT
    @to_store,
    product_super_attribute_id,
    use_default,
    value
FROM catalog_product_super_attribute_label
WHERE store_id = @from_store;

/** catalog_product_bundle_option **/
# PROCESS value VALUES
DELETE FROM catalog_product_bundle_option_value
WHERE store_id = @to_store;
INSERT INTO catalog_product_bundle_option_value (
    store_id,
    option_id,
    title
) SELECT
    @to_store,
    option_id,
    title
FROM catalog_product_bundle_option_value
WHERE store_id = @from_store;

/** catalog_product_website	*/
# PROCESS website VALUES
DELETE FROM catalog_product_website
WHERE website_id = @to_website;

INSERT INTO catalog_product_website (
    product_id,
    website_id
) SELECT
    product_id,
    @to_website
FROM catalog_product_website
WHERE website_id = @from_website;
");

/* end setup */
$installer->endSetup();

 

Note that you should disable cache before running these upgrade scripts. Alternatively, you can run the MySQL queries directly if you enter correct website and store IDs.

Enjoy coding!