Magento - Remove Multiple Product URL Rewrites - magento

In my CE-1.9.0 store my products currently create the following url rewrites:
http://example.com/product-name
http://example.com/category/product-name
http://example.com/another-category/subcategory/product-name
However in my store I want to be able to stop creating the rewrites for the category versions. I have System > Configuration > Catalog > Catalog > Use Categories Path for Product URLs set to No so these extra rewrites are unnecessary. Plus my store has around 500,000 products and counting so these extra url's are taking up a lot of space in the core_url_rewrite` table.
So my aim is to only be left with these versions:
http://example.com/product-name
If I truncate the core_url_rewrite table and reindex then only these versions get created so it is only when new products are created. My catalog is so large so I cannot keep truncated and rebuilding the table from scratch as the rebuilding takes several hours.
With help from this question I have found the file that is responsible for creating the rewrites when a product is created. It is:
app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php
However the answer is no longer valid as the code has changed in the core file.
In this file on line #538 there is the _afterLoad function it is the line
$this->_addUrlRewrite($this->_urlRewriteCategory);
And this function _addUrlRewrite however i've tried changing a lot inside this function but have had no luck. The function in full is:
protected function _addUrlRewrite()
{
$urlRewrites = null;
if ($this->_cacheConf) {
if (!($urlRewrites = Mage::app()->loadCache($this->_cacheConf['prefix'] . 'urlrewrite'))) {
$urlRewrites = null;
} else {
$urlRewrites = unserialize($urlRewrites);
}
}
if (!$urlRewrites) {
$productIds = array();
foreach($this->getItems() as $item) {
$productIds[] = $item->getEntityId();
}
if (!count($productIds)) {
return;
}
$select = $this->_factory->getProductUrlRewriteHelper()
->getTableSelect($productIds, $this->_urlRewriteCategory, Mage::app()->getStore()->getId());
$urlRewrites = array();
foreach ($this->getConnection()->fetchAll($select) as $row) {
if (!isset($urlRewrites[$row['product_id']])) {
$urlRewrites[$row['product_id']] = $row['request_path'];
}
}
if ($this->_cacheConf) {
Mage::app()->saveCache(
serialize($urlRewrites),
$this->_cacheConf['prefix'] . 'urlrewrite',
array_merge($this->_cacheConf['tags'], array(Mage_Catalog_Model_Product_Url::CACHE_TAG)),
$this->_cacheLifetime
);
}
}
foreach($this->getItems() as $item) {
if (empty($this->_urlRewriteCategory)) {
$item->setDoNotUseCategoryId(true);
}
if (isset($urlRewrites[$item->getEntityId()])) {
$item->setData('request_path', $urlRewrites[$item->getEntityId()]);
} else {
$item->setData('request_path', false);
}
}
}

Related

TYPO3 Extbase: How to render the pagetree from my model?

I want to create some kind of sitemap in extbase/fluid (based on the pagetree). I have loaded the pages table into a model:
config.tx_extbase.persistence.classes.Tx_MyExt_Domain_Model_Page.mapping.tableName = pages
I have created a controller and repository, but get stuck on the part wich can load the subpages as relation into my model.
For example:
$page = $this->pageRepository->findByPid($rootPid);
Returns my rootpage. But how can I extend my model that I can use $page->getSubpages() or $page->getNestedPages()?
Do I have to create some kind of query inside my model? Or do I have to resolve this with existing functions (like the object storage) and how?
I tried a lot of things but can simply figure out how this should work.
you have to overwrite your findByPid repository-method and add
public function findByPid($pid) {
$querySettings = $this->objectManager->create('Tx_Extbase_Persistence_Typo3QuerySettings');
$querySettings->setRespectStoragePage(FALSE);
$this->setDefaultQuerySettings($querySettings);
$query = $this->createQuery();
$query->matching($query->equals('pid', $pid));
$pages = $query->execute();
return $pages;
}
to get all pages. Than you can write your own getSubpages-method like
function getSubpages($currentPid) {
$subpages = $this->pagesRepository->findByPid($currentPid);
if (count($subpages) > 0) {
$i = 0;
foreach($subpages as $subpage) {
$subpageUid = $subpage->getUid();
$subpageArray[$i]['page'] = $subpage;
$subpageArray[$i]['subpages'] = $this->getSubpages($subpageUid);
$i++;
}
} else {
$subpageArray = Array();
}
return $subpageArray;
}
i didn't test this method, but it looks like this to get alle subpages.
i wonder that i couldĀ“t find a typo3 method that return the complete Page-Tree :( So i write a little function (you can use in an extbase extension), for sure not the best or fastes way, but easy to extend or customize ;)
first you need an instance of the PageRepository
$this->t3pageRepository = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Frontend\\Page\\PageRepository');
this->t3pageRepository->init();
make the init, to set some basic confs, like "WHERE deletet = 0 AND hidden = 0..."
then with this function you get an array with the page data and subpages in. I implement yust up to three levels:
function getPageTree($pid,$deep=2){
$fields = '*';
$sortField = 'sorting';
$pages = $this->t3pageRepository->getMenu($pid,$fields,$sortField);
if($deep>=1){
foreach($pages as &$page) {
$subPages1 = $this->t3pageRepository->getMenu($page['uid'],$fields,$sortField);
if(count($subPages1)>0){
if($deep>=2){
foreach($subPages1 as &$subPage1){
$subPages2 = $this->t3pageRepository->getMenu($subPage1['uid'],$fields,$sortField);
if(count($subPages2>0)){
$subPage1['subpages'] = $subPages2;
}
}
}
$page['subpages'] = $subPages1;
}
}
}
return $pages;
}

Magento new basic shipping method not showing in frontend

I am trying to create a new shipping method. This method allows users to COLLECT items from a paticular warehouse. So not much involved really.
I have followed a couple of tuts online, and have my module built and installed. It is working on the backend, i can enAble it, and set various values.
When i use the frontend checkout....or even use the following code:
Mage::getSingleton('shipping/config')->getAllCarriers();
I do not get the new shipping method name output.
The message i get on the frontend checkout is:
Sorry, no quotes are available for this order at this time.
Even though i have other shipping methods enabled.
I have another extension in use (regarding stock located in several warehouses). As part of this extension, it lists available shipping options...so that i can assign specific options to a specific warehouse. My new shipping method is not listed that shipping options list.
I seem to have everything required. My other extension is not picking up the method...so must be missing something.
Also, given i am getting no shipping options on frontend...confusing.
I was creating a complex shipping method...rather than a copy of the free shipping method. Turns out i actually needed a copy of the free shipping method, so made my life easier...
This was easier than i thought it would be.
Dont want to post all my code (you will also need a config.xml and system.xml file) but heres my carrier model logic file:
class Myco_Clickcollectshipping_Model_Carrier_Mymethod extends Mage_Shipping_Model_Carrier_Abstract {
protected $_code = 'mymethod ';
public function collectRates(Mage_Shipping_Model_Rate_Request $request)
{
if (!$this->getConfigFlag('active')) {
return false;
}
$freeBoxes = 0;
if ($request->getAllItems()) {
foreach ($request->getAllItems() as $item) {
if ($item->getFreeShipping() && !$item->getProduct()->isVirtual()) {
$freeBoxes+=$item->getQty();
}
}
}
$this->setFreeBoxes($freeBoxes);
$result = Mage::getModel('shipping/rate_result');
if ($this->getConfigData('type') == 'O') { // per order
$shippingPrice = $this->getConfigData('price');
} elseif ($this->getConfigData('type') == 'I') { // per item
$shippingPrice = ($request->getPackageQty() * $this->getConfigData('price')) - ($this->getFreeBoxes() * $this->getConfigData('price'));
} else {
$shippingPrice = false;
}
$shippingPrice = $this->getFinalPriceWithHandlingFee($shippingPrice);
if ($shippingPrice !== false) {
$method = Mage::getModel('shipping/rate_result_method');
$method->setCarrier('mymethod ');
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod('mymethod ');
$method->setMethodTitle($this->getConfigData('name'));
if ($request->getFreeShipping() === true || $request->getPackageQty() == $this->getFreeBoxes()) {
$shippingPrice = '0.00';
}
$method->setPrice($shippingPrice);
$method->setCost($shippingPrice);
$result->append($method);
}
return $result;
}
public function getAllowedMethods()
{
return array('mymethod ' => $this->getConfigData('name'));
}
}

Magento- configurable products options order to match the order they are in the attribute set

I have a magento site I'm building (1.6) my site has a bunch of configurable options with 6 or so attributes set as dropdowns for the customer to pick from. After saving a configurable product the order of the attributes changes. I've been able to find what I think is happening, it is reordering them according to the attribute id not the order I have them set up in the attribute set. I need to find a way to get magento to keep the order of the attributes the same as they are in the attribute set. Any help is greatly appreciated.
Trick is pretty simple.
Just drag'n'drop them in product->edit->associatedProduct tab ;)
The order of attributes from this page is saved to catalog_product_super_attribute table.
I was also looking for the same and finally i found this and it works for me hope it will work for others too.
From Admin Panel > Catalog > Attributes > Manage Attributes select the one like if you want to make it like for the capacity 4GB > 8GB > 16GB and so on then do this small changes.
Select Manage Label / Options > Manage Options (values of your attribute) and if you already created the variables just add the position manually, like:
4GB - 1
8GB - 2
16GB - 3
Save and flush the cache.
That's it, now it should show the attributes as per the position that you assign.
It is an old question but I have found a solution right now having the same problem.
If you are still interesting in changing the order of the configurable attribute you may want to look into this method:
Mage_Catalog_Model_Product_Type_Configurable::getConfigurableAttributes()
getConfigurableAttributes() load the collection of attributes.
The first time the collection is loaded, before saving the configurable, there is no position value, so I think the attribute ID rules on the display order.
If you want to alter this order you can only add a sort for attribute_id after the ->orderByPosition() and revert the order ( this will preserve the position functionality )
For example, here I have added ->setOrder('attribute_id','DESC')
public function getConfigurableAttributes($product = null)
{
Varien_Profiler::start('CONFIGURABLE:'.__METHOD__);
if (!$this->getProduct($product)->hasData($this->_configurableAttributes)) {
$configurableAttributes = $this->getConfigurableAttributeCollection($product)
->orderByPosition()
->setOrder('attribute_id','DESC')
->load();
$this->getProduct($product)->setData($this->_configurableAttributes, $configurableAttributes);
}
Varien_Profiler::stop('CONFIGURABLE:'.__METHOD__);
return $this->getProduct($product)->getData($this->_configurableAttributes);
}
OR
In case you want to modify the order in more radical way, you can also act on this method:
Mage_Adminhtml_Block_Catalog_Product_Edit_Tab_Super_Config::getAttributesJson()
This is basically calling the getConfigurableAttributes().
To understand if this is the first configurable load, you can check all the attributes in the array $attributes to see if they all have a position ==0 and then proceed with a manual reorder )
Example
I'm omitting all the module creation and the rewrite part.
Here an example modifying getAttributesJson() in order to have the color attribute always on the top.
public function getAttributesJson()
{
$attributes = $this->_getProduct()->getTypeInstance(true)
->getConfigurableAttributesAsArray($this->_getProduct());
if (!$attributes) {
return '[]';
} else {
// == START ==
// checking if I can re-order
if ($this->isNoSavedPosition($attributes)) {
$attributes = $this->attributeReorder($attributes);
}
// == END ==
// Hide price if needed
foreach ($attributes as &$attribute) {
if (isset($attribute['values']) && is_array($attribute['values'])) {
foreach ($attribute['values'] as &$attributeValue) {
if (!$this->getCanReadPrice()) {
$attributeValue['pricing_value'] = '';
$attributeValue['is_percent'] = 0;
}
$attributeValue['can_edit_price'] = $this->getCanEditPrice();
$attributeValue['can_read_price'] = $this->getCanReadPrice();
}
}
}
}
return Mage::helper('core')->jsonEncode($attributes);
}
public function isNoSavedPosition($attributes)
{
foreach ($attributes as $attribute) {
if (isset($attribute['position']) && $attribute['position'] != 0) {
return false;
}
}
// there is no position saved
// - this is the first time the configurable is loaded
// - (the position is saved on second save action)
return true;
}
public function attributeReorder($attributes)
{
// we want the Color attribute to be always on the top
$newAttributesOrderArray = array();
foreach ($attributes as $key => $attribute) {
if (isset($attribute['label']) && $attribute['label'] == 'Color') {
$newAttributesOrderArray[] = $attribute;
unset($attributes[$key]);
}
}
$newAttributesOrderArray = array_merge($newAttributesOrderArray,$attributes);
return $newAttributesOrderArray;
}

Magento - get bundled products where a simple product belongs to

I want to show all bundles on a simple product's page and so need to retrieve the information. I searched and tried a lot. This post sounds promising, but is either not working or maybe not for my problem:
Magento - get a list of bundled product ids from a product id
I found a solution for grouped products but this can't be applied here.
$grouped_product_model = Mage::getModel('bundle/product_selection');
$groupedParentId = $grouped_product_model->getParentIdsByChild($product->getId());
I found the table catalog_product_bundle_selection to be the right place to search, but I wonder if there is a clean way and existing function to search this table by product_id than just to hack this.
I didn't find a solution in Mage_Bundle.
What did I miss?
After getting first aid from vrnet I wrote a new block class, so I can update the layout
class Thomaier_Catalog_Block_Product_View_BundledSelect extends Mage_Catalog_Block_Product_View
{
protected $_simpleProducts = array( '3' ); // just an example
public function getBundles() {
$bundleIds = array();
$bundlesCollectionModel = Mage::getResourceModel('bundle/selection_collection');
$bundlesCollection = $bundlesCollectionModel->getSelect()
->where('`selection`.`product_id` in (' . join(',', (array)$this->_simpleProducts) . ')');
foreach ($bundlesCollection as $bundleItem) {
$bundleIds[] = $bundleItem->getParentProductId();
}
...
}
}
I skipped some parts. As I mentioned in the comment, the SQL query works fine when I try it in phpmyadmin, but $bundleItem is not created and ->load() throws an exception.
Thanks for advice.
Below is a method I wrote for a client having the same request with an extra : the ability to shuffle the result.
Hope it helps.
protected $_simpleProducts = array(); // Array with IDs of simple products you want bundles from.
protected $_shuffle = false;
public function getBundles() {
$bundleIds = array();
/*Rather than using a collection model
and make operations with getSelect,
a more elegant way is to extend
Mage_Bundle_Model_Mysql4_Selection_Collection
with a method that would be something like
setProductIdsFilter($productIds)*/
$bundlesCollectionModel = Mage::getResourceModel('bundle/selection_collection');
$bundlesCollection = $bundleCollectionModel->getSelect()
->where('`selection`.`product_id` in (' . join(',', (array)$this->_simpleProducts) . ')');
foreach ($bundlesCollection as $bundleItem) {
$bundleIds[] = $bundleItem->getParentProductId();
}
if (count($bundleIds)) {
$allowBundles = Mage::getResourceModel('catalog/product_collection')
->addIdFilter($bundleIds)
->addFieldToFilter('status', Mage_Catalog_Model_Product_Status::STATUS_ENABLED);
if ($this->_shuffle) {
$allowBundles->getSelect()->order('rand()');
}
if ($allowBundles->count()) {
return $allowBundles;
}
}
return;
The following is the best way to work with these. This way you do not rely on a custom query but instead you can use the core methods:
$bundlesCollection = Mage::getResourceModel('bundle/selection')
->getParentIdsByChild($simple_product_ids_array_or_int);
foreach ($bundlesCollection as $bundleProdId) {
//do anything you want with the bundleProdId array elements
}

using group() breaks getSelectCountSql in magento

When I'm using
$collection->getSelect()->group('entity_id')
or
$collection->groupByAttribute('entity_id')
It breaks getSelectCountSql and I'm getting 1 record and 1 page.
Magento does
$countSelect->columns('COUNT(DISTINCT e.entity_id)');
Is there a way to fix it?
I run into it,While overriding _prepareCollection of Mage_Adminhtml_Block_Catalog_Product_Grid
Thanks
I updated the lib/Varien/Data/Collection/Db.php file to allow this as I had to have it work. You'll have to keep track of this for upgrades but it works.
public function getSelectCountSql()
{
$this->_renderFilters();
$countSelect = clone $this->getSelect();
$countSelect->reset(Zend_Db_Select::ORDER);
$countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
$countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
$countSelect->reset(Zend_Db_Select::COLUMNS);
// Count doesn't work with group by columns keep the group by
if(count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) {
$countSelect->reset(Zend_Db_Select::GROUP);
$countSelect->distinct(true);
$group = $this->getSelect()->getPart(Zend_Db_Select::GROUP);
$countSelect->columns("COUNT(DISTINCT ".implode(", ", $group).")");
} else {
$countSelect->columns('COUNT(*)');
}
return $countSelect;
}
in some cases, the method from Eric doesn't work.
It's better to rewrite the getSize() method to
public function getSize()
{
if (is_null($this->_totalRecords)) {
$sql = $this->getSelectCountSql();
$result = $this->getConnection()->fetchAll($sql, $this->_bindParams);;
foreach ($result as $row) {
$this->_totalRecords += reset($row);
}
}
return intval($this->_totalRecords);
}
I have solved this using the function below:
public function getSize()
{
return sizeof( $this->getAllIds());
}
This helped me in issue of getSize() returning 1 count of product collection in Magento CE 1.5.
I have overwritten the Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection file and place above function.
Very nice article
Here are few changes I made in order to make it work for me
Changes suggested in Db.php are not required for resolving group by in catalog collection.
I made the similar change in
Catalog->model->Ressource->EAV->Mysql4->product->collection.php
Here is the code I added to getSelectCountSql()
if(count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) { $countSelect->reset(Zend_Db_Select::GROUP); }
After this things get resolved but a new issue comes in .. In Layered navigation quantities for all the filters is 1.
I made it without touching Core files by overriding the getSize() method of my collection.
public function getSize()
{
if (count($this->getSelect()->getPart(Zend_Db_Select::GROUP)) > 0) {
// Create a new collection from ids because we need a fresh select
$ids = $this->getAllIds();
$new_coll = Mage::getModel('module_key/model')->getCollection()
->addFieldToFilter('id', array('in' => $ids));
// return the collection size
return $new_coll->getSize();
}
return parent::getSize();
}
Tell me if that works for you..
Bouni

Resources