Monday, August 27, 2012

How to make CMS pages available only to logged in customers

Hello
Here is a possible solution on how to make cms mages available only to logged in customers.
Override the Mage_Cms_PageController. Here is a how to do it: http://www.extensionprogrammer.com/skin/frontend/default/dermodpro/pdf/magento-cheatsheet.pdf

Now add the following method in your new controller

public function preDispatch(){
		$restrictedIdentifiers = array('about-magento-demo-store');
		$pageId = $this->getRequest()
            ->getParam('page_id', $this->getRequest()->getParam('id', false));
        $page = Mage::getModel('cms/page')->load($pageId);
    	parent::preDispatch();
    	if (in_array($page->getIdentifier(), $restrictedIdentifiers)){
	    	if (!Mage::getSingleton('customer/session')->authenticate($this)) {
	            $this->setFlag('', 'no-dispatch', true);
	        }
    	}
    }
That's it. Enjoy. I know it's not 100% clean solution. If you want the clean solution, add a new field for the cms_page table (let's call it 'password_protect'), add the field in the admin form. After doing this the code above becomes:
public function preDispatch(){
		$pageId = $this->getRequest()
            ->getParam('page_id', $this->getRequest()->getParam('id', false));
        $page = Mage::getModel('cms/page')->load($pageId);
    	parent::preDispatch();
    	if ($page->getPasswordProtect()){
	    	if (!Mage::getSingleton('customer/session')->authenticate($this)) {
	            $this->setFlag('', 'no-dispatch', true);
	        }
    	}
    }
Marius.

Monday, August 13, 2012

Tips & tricks to speed up Magento

I've found on LikedIn a comment about tips and tricks for speeding up Mangeto.
It seams like a good list to consider when having troubles with the site speed.
The list was provided by Pieter Pabst.
Here it goes:


- Use KeepAlive in Apache.
- Make sure the query buffer on your MySQL instance is large enough.
- Hosting MySQL on another (V)Machine will help
- Migrate .htaccess to you apache config and turn off AllowOverride.
- Use some kind of opcode cashing, like APC of even better, Zend Server
- Use mod_deflate
- Use mod_expires
- Put var/cache in a /dev/ramdisk of tmpfs
- Use the CDN option, or at least something that is accessible via another DNS name (like content.yoursite of static.yoursite) as browsers are limited to X connections to a certain host at one time (use the URLs in System -> Configuration -> Web to accomplish this), but be aware of the fall-back mechanism for skins. Also beware that the upload script in the backend does not like it when it's hosted on another hostname (potential XSS). Your uploads will fail. To overcome this, make sure the backend uses local JS and the frontend uses CDN. To accomplish this use the configuration scope in the Web config section (default to local, storeviews to CDN).
- Move /media to another server
- After putting var/cache in ramdisk, put the rest somewhere with fast I/O. Like SAS disks or a SSD. Don't put it on something like iSCSI or SATA. Put media on cheap I/O like SATA, preferably on another server, or something assebeble via another hostname.
- If you have the option, don't use apache at all. Try ngnix.

Magento:
- Use flat catalog (System -> Configuration -> Catalog -> Frontend)
- Enable cache (System -> Cache management)
- Compile Magento when opcode caching is no option (System -> Tools -> - Compiling)

Hacking
- Disabling the fall-back mechanism for themes / skins and merging the base and your current into one will save you a lot of IO
- Try to code your modules in a way they can use cache
- Try full page caching, all tough you will have to buy a license for products like Zend Server, this will boost performance.
- Try cashing frequently used queries (in a request kind of context I mean) in f.e.a arrays. But beware of the memmory limit. Unset things of necessary.

Webdesign
- Use sprites
- Combine everything in one CSS file or use one of the extensions already mentioned.
- The same goes for javascript
- Use robots.txt to stop robots from crawling certain URLs with producs they probably already indexed trough other URLs. It will just cause additional load.

After you've done all that, you site needs to be immense popular to require load balancing of MySQL clustering.

Friday, April 20, 2012

Retrieve bestsellers

Here is how you can retrieve a list of bestsellers
$collection = Mage::getResourceModel('sales/report_bestsellers_collection')
            ->setModel('catalog/product')
            ->addStoreFilter(Mage::app()->getStore()->getId())//if you want the bestsellers for a specific store view. if you want global values remove this
            ->setPageSize(5)//se there the number of products you want returned
            ->setCurPage(1);
foreach ($collection as $_product){
    $realProduct = Mage::getModel('catalog/product')->load($_product->getProductId());
    //do something with $realProduct;
}
Make sure you refresehd the statistic for bestsellers. Reports->Refresh statistics. Select refresh lifetime statistics for bestsellers. Enjoy.

Wednesday, March 7, 2012

Add files to products - no extension required

Here is how you can add files to products without using an extension. It can be useful for adding specification files, pdf catalogs or any other files you want. Put all your files in one folder let's say (media/productfiles/). Now in the product description you just add a simple link to that file using the WYSIWYG editor. If you don't want to use the description field for this you can create a new attribute (let's call it 'attachment') type 'Textarea', scope 'Store view' (in case you want to have different files for different languages), 'Enable WYSIWYG' Yes, 'Allow HTML Tags on Frontend' Yes. If you want to show the link(s) to file(s) in the product list not only the product details page set 'Used in Product Listing' to 'Yes'. If not set it to 'No'. Now add your new attribute to the attribute set that you need and start editing products. Add links to your files just like described above, but use the 'Attachment' attribute instead of Description. now all you have to do is edit the app/design/frontend/{interface}/{theme}/template/catalog/product/view.phtml and add this line where ever you want the links to appear:
<?php echo $this->getProduct()->getAttachment();?>
If you want to add the links to the list of products also edit app/design/frontend/{interface}/{theme}/template/catalog/product/list.phtml and add this piece of code inside the foreach loop for the products:
<?php echo $_product->getAttachment();?>
Cheers, Marius.

Thursday, February 16, 2012

Create admin user by code

Here is a piece of code that will allow you to create admin users. It's really useful if you forget the admin password: Create a file called adminuser.php on the same level as index.php (in the root of the application) with the following content:
<?php
error_reporting(E_ALL | E_STRICT);
$mageFilename = 'app/Mage.php';
require_once $mageFilename;
Mage::setIsDeveloperMode(true);
ini_set('display_errors', 1);

umask(0);
Mage::app('default');//if you changed the code for the default store view change it here also
Mage::app()->setCurrentStore(Mage::getModel('core/store')->load(Mage_Core_Model_App::ADMIN_STORE_ID));
$username = 'yourUsername';//desired username
$firstname = "Firstname";//desired firstname
$lastname = "Lastname";//desired lastname
$email = "email@example.com";//desired email
$pass = 'yourPaSSWordHere';//desired password
$user = Mage::getModel('admin/user')->load($username, 'username');
if ($user->getId()){
 echo "User {$username} already exists";
 exit;
}
$user->setUsername($username)
  ->setFirstname($firstname)
  ->setLastname($lastname)
  ->setEmail($email)
  ->setPassword($pass)
  ;
$result = $user->validate();
if (is_array($result)){
 foreach ($result as $res){
  echo $res."\n";
 }
 exit;
}
try{
 $user->setForceNewPassword(true);
 $user->save();
 $user->setRoleIds(array(1))->saveRelations();
 echo "User {$username} was created";
 exit;
}
catch (Exception $e){
 echo $e->getMessage();
}
Now call in you browser this url www.mysite.com/adminuser.php. You should see a message on the screen with the result of your action. Cheers, Marius.

Friday, February 10, 2012

Keep products in the wishlist after adding them to cart.

Here is an interesting question I found on the Magento forum:
Leave Wishlist as it is after adding item to shopping cart?

Here is what you can do.
Override the wishlist index controller (app/code/core/Mage/Wishlist/controllers/IndexController.php) or edit it if you don't care about keeping the core clean (I recommend to keep it clean though)
and inside the method cartAction() there is this line:
$item->addToCart($cart, true);
The second parameter of the method addToCart means 'Remove from wishlist'.
You can change the second parameter to false or remove it completely - it defaults to false.

Marius.

Monday, December 5, 2011

Add category names in product view page

Here is an other short but useful for some people thing you can do in Magento.
Here is how you can add the category tree path in the product view page.

Edit file app/design/frontend/{interface}/{theme}/template/catalog/product/view.phtml

And in the section that you want the categories to appear add this code:
<?php $categoryIds = $_product->getCategoryIds();?>
 <?php foreach ($categoryIds as $categoryId) :?>
  <?php $tmpId = $categoryId;?>
  <?php $categories = array();?>
  <?php while($tmpId != Mage::app()->getStore()->getRootCategoryId()) : ?>
   <?php $category = Mage::getModel('catalog/category')->setStoreId(Mage::app()->getStore()->getId())->load($tmpId);?>
   <?php $categories[] = $category;?>
   <?php $tmpId = $category->getParentId();?>
  <?php endwhile;?>
  <?php for ($i = count($categories) - 1; $i>=0;$i--) :?>
   <a href="<?php echo $categories[$i]->getUrl() ?>"><?php echo $categories[$i]->getName() ?></a>
   <?php if ($i >0 ):?>
    -&gt;<!-- this is the tree separator. change to whatever you like-->
   <?php endif;?>
  <?php endfor;?>
  <br />
  <?php //break;//uncomment this if you want only one category tree to appear.?>
 <?php endforeach;?>

I hope this helps someone.
Keep in mind that this will make your page load a little slower, but I don't think it's something you should worry about.
Any comments are welcomed.

Marius.

Thursday, October 6, 2011

New Customer Account Breadcrumbs Extension

I've just developed & released under the name AnaisSoftware (the company I work worked for) a new FREE Magento Extension.
It is called 'Customer Account Breadcrumbs' (Anais_Breadcrumbs). It's not a big technical achievement but I saw some people on the forum requesting this.
All it does is it adds breadcrumbs to the customer account pages.
You can select from the back-end to enable the breadcrumbs for all the available account pages or select from a list the pages you want to have breadcrumbs.

It works Magento 1.4.2.0, 1.5.0.1, 1.5.1.0 and 1.6.0.0.
I have a hunch it works for previous versions also, I just didn't test them.
It has also been tested on Magneto Enterprise 1.9.1.1 but it doesn't work for enterprise specific pages (Gift registry, Reward points, ...).
The extension can be found here http://www.magentocommerce.com/magento-connect/AnaisSoftware/extension/8220/anais_breadcrumbs

Waiting for your feedback.

Cheers,
Marius.

Friday, September 30, 2011

Upload issue for Magento 1.6.0.0

I've seen lately the magento forum flooded with this issue.
When trying to upload an image for the product the section with the image name gets a red border and an error message appears.
When trying to upload something for the downloadable products...well..
same s**t different a**h**e (pardon my French).

Here is what I did to fix it:
The problem seems to be caused by the prototype v1.7.
It works great with prototype 1.6
Get the 1.6 version from here http://prototypejs.org/assets/2009/8/31/prototype.js
Create this file: js/prototype/prototype1.6.js and put the contents from the link above in it.
Now edit app/design/adminhtml/default/default/layout/main.xml and add this line
<action method="addJs"><script>prototype/prototype1.6.js</script></action>
right below
<action method="addJs"><script>prototype/prototype.js</script></action>

I don’t think it’s a problem if you edit this core file. I can assume that the guys at Magento will fix the issue with the uploader untill the next version (at least I hope it’s the same issue as reported here: http://www.magentocommerce.com/bug-tracking/issue?issue=12265 - and they claim it’s fixed)

I hope this helps someone
Cheers,
Marius.

Friday, September 9, 2011

Why can't you override some classes in Magento?

I saw a lot of pleaople having this issue on the magento forum.
Some classes cannot pe overridden the clasical way.
First of all, this is the classical way: http://magedev.com/2009/06/03/magento-overriding-model-block-or-helper/
It's a old post but is still very useful and it saved me a lot of time in the past.

But there are some classes that cannot be overridden this way.
Here are some examples: Mage_Core_Block_Template, Mage_Core_Model_Abstract, Varien_Object, Mage_Core_Block_Abstract, Mage_Customer_Model_Address_Abstract and the list can go on.

Basically these are the classes that are not instantiated in the application. They are used just to create other classes with common behavior.

But if you need to override these classes here are your 2 options. (I only know 2. If you know others please share.)

1. Quick and dirty. Using this there is a small change that on an upgrade you will lose some functionality or even crash. but don't dismiss it yet. Using the second method it's even worse.
The basics of this method is that Magento uses an autoloader to load classes. The autoloader first searches in the 'app/code/local' folder then in 'app/code/community' and in the end 'app/code/core'.
What you have to do is to copy the class you want to override in the app/code/local folder.
Let's take as an example Mage_Core_Model_Abstract. You need to copy the file app/code/core/Mage/Core/Model/Abstract.php to app/code/local/Mage/Core/Model/Abstract.php.
You can make the changes in this file.
Now when all the other classes that extend this are declared
class Mage_Customer_Model_Customer extends Mage_Core_Model_Abstract
{ ...}
they will extend your own class because when searching for Mage_Core_Model_Abstract magento will find it in your app/code/local folder and will stop looking for the one in app/code/core.

2. Long and 'clean?' - You can still lose functionality on the upgrade, it's more time consuming
and a bigger source of errors.
You can create your own class. Let's call it 'Mycomp_Core_Model_Abstract' that extends Mage_Core_Model_Abstract and put your custom code in this.
In order for this to affect all the other models that extend Mage_Core_Model_Abstract you need to override each class that extend Mage_Core_Model_Abstract and make them extend the class you just created. Using the same example as above..
class Mycomp_Customer_Model_Customer extends Mycomp_Core_Model_Abstract
{ ...}
But now you need to copy all the functionality from Mage_Customer_Model_Customer to Mycomp_Customer_Model_Customer because, unfortunately, PHP does not support multiple inheritance (yet?)
And for Mage_Core_Model_Abstract there are around 70 classes that extend it. You have to do this 70 times.

Pick your own method. I strongly recommend the first one.
I hope this helps someone.

Cheers,
Marius.