If I am right, in Magento the renderCategoriesMenuHtml() function helps in displaying the menu of "categories included in the navigation menu bar".
I'd like to modify the renderCategoriesMenuHtml() function to display the menu of "categories that are not included in the navigation menu bar".
In short, I need to display a menu of categories that have the attribute "Include in navigation menu" set to no in the admin panel.
Thanks in advance.
Magento has a facility for changing or adding to functionality of classes known as class overrides or class rewrites. The following example assumes a namespace of "Custom" and a module name of "Nav".
First, register a module:
<?xml version="1.0" encoding="UTF-8"?>
<!-- app/etc/modules/whatever.xml -->
<config>
<modules>
<Custom_Nav><!-- must match your namespace & module folder names -->
<active>true</active>
<codePool>local</codePool>
</Custom_Nav>
</modules>
</config>
Based on the above, the application will look for a configuration file for your module:
<?xml version="1.0" encoding="UTF-8"?>
<!-- app/code/local/Custom/Nav/etc/config.xml -->
<config>
<global>
<blocks>
<catalog>
<rewrite>
<navigation>Custom_Nav_Block_Rewrite_Navigation</navigation>
</rewrite>
</catalog>
</blocks>
</global>
</config>
What this does is to rewrite the class name in the block creation factory method. The catalog navigation block is added in catalog.xml layout update XML (<block type="catalog/navigation" .../>). The above xpath will cause the class name to map to Custom_Nav_Block_Rewrite_Navigation rather than the usual Mage_Catalog_Block_Navigation, and it is this class which will be instantiated.
The final step is to create the class definition, extending from the original class for the sake of maintainability and to obey DRY:
<?php
/* app/code/local/Custom/Nav/Block/Rewrite/Navigation.php */
class Custom_Nav_Block_Rewrite_Navigation extends Mage_Catalog_Block_Navigation
{
//custom method overrides & additions belong here
}
Clear the config & block_html caches and the changes should be visible. To verify, enable template path hints + block class names via the admin panel, or create a simple script in the site root:
<?php
/* test.php in Magento root folder */
ini_set('display_errors',true);
include 'app/Mage.php';
Mage::setIsDeveloperMode(true);
Mage::app();
var_dump(Mage::getConfig()->getBlockClassName('catalog/navigation'));
Point the browser to http://site.com/test.php and the output should show the rewritten class name.
Related
I want to show all my reviews of all the products on a cms page. Does anybody know ho to do this? I'm using Magento 1.4.2
that all depends on what Module you're using to provide that extension to Magento's features. If you look in the folder of the module (let's say its Cmdcentral/Review)
app/code/community/Cmdcentral/Review/
This is where the module resides (it might be in local too)look in the etc for config.xml There will be a section that looks something like this:
<config>
...
<global>
....
<models>
<review>
<class>Cmdcentral_Review_Model</class>
</review>
<review_mysql4>
<class>Cmdcentral_Review_Model_Mysql4</class>
<entities>
<reviews>table_in_database</reviews>
</entities>
</review_mysql4>
</models>
.....
</global>
...
</config>
This will differ depending on what you've got. what's important is the name of the node inside <entities></entities> in my case it is <reviews></reviews>
You can then take a look at the controllers folder for IndexController.php create a new function that looks like this:
public function showallAction(){
$this->loadLayout();
$this->renderLayout();
}
Now you'll have to create a block for this, create a new block in app/code/community/Cmdcentral/Review/Blocks and call it Showall.php
Your block should look something like this:
<?php class Cmdcentral_Review_Block_Showall extends Mage_Core_Block_Template{
public function getAllReviews(){
return Mage::getModel('review/reviews')->getCollection();
}
}
review is module name and reviews is the entity we saw inside the <entities></entities> node in config.xml.
Next we're off to app/design/frontend/ from here, the file we're looking for is most likely in base/default but may also be in another theme's folder. The file we're looking for will be Modulename.xml so in my case it will be app/design/frontend/base/default/layout/Review.xml
Open your layout file, now simply add this inside the <layout></layout> node:
<review_index_showall>
<reference name="content">
<block type="review/showall" name="showall" template="review/showall.phtml"/>
</reference>
<review_index_showall>
This simply tells Magento that when we load our review/index/showall route and access our showallAction() function in our controller, to add our block inside content.
Now the block also has a template="review/showall.phtml" attribute. Go to app/design/frontend/base/default look for a review directory (or whatever the module is called). If it doesn't exist (which I doubt) create it! Inside this create showall.phtml. So now you should have it looking like app/design/frontend/base/default/review/showall.phtml
Open this file and now you create your page. ~Phew!
Just remember to use $this->getAllReviews() to get your review/reviews collection and then simply do something like this:
$reviews = $this->getAllReviews();
foreach($reviews as $review){
echo $review->getData('column_name');
#or
echo $review->getColumnName();
#does the same thing
}
I hope this helps and I didn't make any mistakes. Remember, at first Magento makes you cry, but when you get used to Magento, it's reduced to intermittent whimpers!
I need to do a bit of major editing to the sub navigation displayed from the standard Magento top level navigation.
I've gone into top.phtml and found that it calls a function in the core Mage code, Is it possible to have a file in my theme run before this is called or do I have to create a totally custom navigation/use a extension?
You're always more than welcome to simply replace the design/frontend/[package]/[theme]/catalog/navigation/top.phtml template with your own markup which you can then iterate over as you please.
The Block class already provides some basic methods that can be used to build your nav menu how you like it, such as getStoreCategories(), isCategoryActive(), getCurrenetChildCategories(), etc.
Alternatively, as mentioned by Peter, you can rewrite the Block class to change specific methods or include your own methods which are then accessible from the template file.
To override Mage_Catalog_Block_Navigation:
in app/etc/modules/Yourmodule_Catalog.xml:
<?xml version="1.0"?>
<config>
<modules>
<Yourmodule_Catalog>
<active>true</active>
<codePool>local</codePool>
<depends />
</Yourmodule_Catalog>
</modules>
</config>
in app/code/local/Yourmodule/Catalog/etc/config.xml:
<?xml version="1.0"?>
<config>
<modules>
<Yourmodule_Catalog>
<version>0.1.0</version>
</Yourmodule_Catalog>
</modules>
<global>
<blocks>
<catalog>
<rewrite>
<navigation>Yourmodule_Catalog_Block_Navigation</navigation>
</rewrite>
</catalog>
</blocks>
</global>
in app/code/local/Yourmodule/Catalog/Block/Navigation.php:
<?php
class Yourmodule_Catalog_Block_Navigation extends Mage_Catalog_Block_Navigation
{
.... the methods you want to override...
}
And that's it.
I'd like to add a static box under the price on each product page, but I dont want to overwrite an existing template file (e.g. catalog/product/view.phtml) to render it's child block.
I tried to add a block element via frontend/base/default/layout/local.xml
<layout version="0.1.0">
<default>
<reference name="product.info">
<block type="telllowerpricelink/linkbox" name="telllowerpricelink.linkbox" template="telllowerpricelink/link.phtml" before="product.description" output="toHtml" />
</reference>
</default>
</layout>
Then i built a rudimental module:
app/code/local/MyPackage/TellLowerPriceLink/Block/LinkBox.php
<?php
class MyPackage_TellLowerPriceLink_Block_Link extends Mage_Core_Block_Template
{
}
?>
app/code/local/MyPackage/TellLowerPriceLink/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<MyPackage_TellLowerPriceLink>
<version>0.1.0</version>
</MyPackage_TellLowerPriceLink>
</modules>
<global>
<blocks>
<mypackage_telllowerpricelink>
<class>MyPackage_TellLowerPriceLink_Block</class>
</mypackage_telllowerpricelink>
</blocks>
</global>
</config>
And my templatefile:
design/frontend/base/default/template/telllowerpricelink/link.phtml
<?php
echo 'Hello world!';
?>
So my questions are:
1. The main question: Is it possible to add the html-output (btw: I dont see it) at the end of the parent block element without editing its template (a la renderChildHtml)?
2. Is it possible to store my template file in this folder or have I to copy the hole default theme folder into a own theme?
Thanks a lot, I have googled and read a lot but didnt find a satisfying answer.
That's only possible with blocks derived from Mage_Core_Block_Text_List block so in your case it isn't possible but you could add your block to reference content (a container that renders all the children from layout files) and wrap your block into a div with style="display: none;" set and then move it with a javascript to the expected location.
It's possible but instead you could change the default theme in admin under system->configuration->general->design->package
The name that you will use here will be the name of your theme folder (note that this changes the theme for your entire store) so you can create your folder in desing/your_theme_name_from_admin/{layout, template} and put only files that you require to override in there. With this you could copy only the phtml file that you would like to override and change it on the new location while keeping the default copy in tact.
Is there a way we could changes the layout of a Magento page (let's say a product category page) dynamically by using system variable which have been set on our own module? I want to be able to set my category page's default layout via my own module admin config panel. So that I don't have to deal with those confusing XML layout file each time I want to change my default layout for a certain magento page.
I know, on a phtml file, we could simply call our own module's system variable by calling Mage::getStoreConfig('module/scope/...') to use that system variable. but what if we want to use that system variable to change the whole layout which is set on the XML layout file by default.
I don't see any ways to pull that system variable value on the XML Layout file.
But I'm pretty sure there must be a right way to do that. So far, this is the closest clue that I've got
Magento - xml layouts, specify value for ifconfig?
But, still, I couldn't find any direct answer for what I really want to achieve
this is the content of my config.xml
<config>
<modules>
<Prem_Spectra>
<version>0.1.0</version>
</Prem_Spectra>
</modules>
<global>
<models>
<spectra>
<class>Prem_Spectra_Model</class>
</spectra>
</models>
<helpers>
<prem_spectra>
<class>Prem_Spectra_Helper</class>
</prem_spectra>
</helpers>
</global>
</config>
This can be very easily achieved using layout xml and a simple method in your helper. I don't see any requirement for an observer here or anything else overly elaborate.
So, based on your requirements to change all category page layouts from your own modules store config value you will require the following in your layout xml:
<catalog_category_view>
<reference name="root">
<action method="setTemplate">
<template helper="yourmodule/switchTemplate" />
</action>
</reference>
</catalog_category_view>
And the following in your modules default helper:
public function switchTemplate()
{
$template = Mage::getStoreConfig('path_to/yourmodule/config');
return $template;
}
we are talking about the template of the root-element, so 3columns, 2columns, etc? correct?
Implement an observer, listen to the event controller_action_layout_generate_blocks_before and then get the block in the observer and set the template
Mage::app()->getLayout()->getBlock('root')->setTemplate($myFancyTemplatePath);
This should do it.
Other idea, try the event controller_action_layout_load_before, but I think this is too early.
In addition to Fabian's answer:
You could perhaps extend the functionality of the category 'display modes'.
Using the controller_action_layout_load_before event and then retrieve the display mode of the category and create a XML update handle for it.
$category = Mage::registry('current_category');
$handle = 'category_displaymode_' . strtolower($category->getDisplayMode());
$layout = $observer->getEvent()->getLayout();
$layout->getUpdate()->addHandle($handle);
This way you can pre-define all kinds of layouts in your local.xml and easily switch between them by adjusting the 'display mode' dropdown on the category edit page in the admin.
With some tweaking in the admin you can add additional display modes to the dropdown to make more types of custom display mode xml update handles available.
I have a custom module, which has several blocks. If I include these blocks in a CMS page after each other, they work as expected. If I include them through the layout XML files, they all display the source code of the last one called in the XML. A minimum test case (that for me is exhibiting this behavior) follows, along with expected and actual results.
Code
/app/etc/modules/Test_Tester.xml
<?xml version="1.0"?>
<config>
<modules>
<Test_Tester>
<active>true</active>
<codePool>local</codePool>
</Test_Tester>
</modules>
</config>
/app/code/local/Test/Tester/etc/config.xml
<?xml version="1.0"?>
<config>
<modules>
<Test_Tester>
<version>0.1.0</version>
</Test_Tester>
</modules>
<global>
<blocks>
<test_tester>
<class>Test_Tester_Block</class>
</test_tester>
</blocks>
</global>
</config>
/app/code/local/Test/Tester/Block/One.php
<?php
class Test_Tester_Block_One extends Mage_Catalog_Block_Product_List_Upsell
{
protected function _prepareData()
{
echo 'One.php';
//...MORE code here, it's not really relevant though
}
}
/app/code/local/Test/Tester/Block/Two.php
<?php
class Test_Tester_Block_Two extends Mage_Catalog_Block_Product_List_Upsell
{
protected function _prepareData()
{
echo 'Two.php';
//...MORE code here, it's not really relevant though
}
}
/app/design/frontend/INTERFACE/TEMPLATE/layout/page.xml (under
..
<block type="core/text_list" name="testa" as="testa" />
<block type="core/text_list" name="testb" as="testb" />
..
/app/design/frontend/INTERFACE/TEMPLATE/layout/cms.xml (under
<reference name="testa">
<block type="test_tester/one" template="tester/one.phtml"/>
</reference>
<reference name="testb">
<block type="test_tester/two" template="tester/two.phtml"/>
</reference>
/app/design/frontend/INTERFACE/TEMPLATE/template/page/home_template.phtml
<?php echo $this->getChildHtml('testa'); ?>
<?php echo $this->getChildHtml('testb'); ?>
/app/design/frontend/INTERFACE/TEMPLATE/tester/one.phtml
one.phtml
/app/design/frontend/INTERFACE/TEMPLATE/tester/two.phtml
two.phtml
Expected
This should print out (on the homepage, where the blocks are being included):
One.php
one.phtml
Two.php
two.phtml
Actual Output
If I include the blocks within the Homepage CMS page, like so:
{{block type="test_tester/one" template="tester/one.phtml"}}
{{block type="test_tester/two" template="tester/two.phtml"}}
...I get the expected output. However, using the layout as above in the code sample, I get:
Two.php
two.phtml
Two.php
two.phtml
I think I've gone insane - I can't see the bit I'm mucking up.
Try giving your blocks names in the homepage CMS page. Similar errors I've received have been resolved this way. I see that you're trying to wrap the blocks in text lists, but from what I see you never actually identify the blocks from within the CMS page. Try something to this effect instead:
{{block type="test_tester/one" template="tester/one.phtml" name="testa"}}
{{block type="test_tester/two" template="tester/two.phtml" name="testb"}}
If you cannot get away from the parent blocks as containers, you may have to rethink part of your layout. If that doesn't do it either way, let me know and we'll try something else. Hope that helps.
Thanks,
Joe