I have a custom module I wrote that is pretty basic...it just adds a small block to the footer for tracking using Media Forge. The tag it adds is different depending on whether you're on a product view page or not. This worked GREAT....until I turned on caching. Now, if you flush the cache and load a product view page, you get the correct block for the product view page. If you then go to another page (home, for instance), it still uses the product view page's block. If I flush the cache and reload the home page, it's now using the right one, but if I go to a product page now, it's using the wrong one there. So it's definitely a cache issue, I just don't understand how I'm supposed to correct this problem.
I'll paste the contents of my files below. I look forward to any responses!
Layout XML file:
<layout version="0.1.0">
<!-- DEFAULT TAG -->
<default>
<reference name="footer">
<block type="core/template" name="mediaforge_footer" as="mediaforge_footer" template="tracking/mediaforge_default.phtml"/>
</reference>
</default>
<!-- PRODUCT VIEW PAGES -->
<catalog_product_view>
<reference name="mediaforge_footer">
<action method="setTemplate"><template>tracking/mediaforge_product.phtml</template></action>
</reference>
</catalog_product_view>
</layout>
config.xml for my custom module:
<config>
<modules>
<VPS_Tracking>
<version>0.1.0</version>
</VPS_Tracking>
</modules>
<frontend>
<layout>
<updates>
<vps_tracking>
<file>vps_tracking.xml</file>
</vps_tracking>
</updates>
</layout>
</frontend>
</config>
Added this to the end of footer.phtml:
<?php echo $this->getChildHtml('mediaforge_footer'); ?>
The module definition is pretty basic and the two template files mediaforge_default.phtml and mediaforge_product.phtml are pretty simple so I won't bother including them.
Any ideas?
In a nutshell, you need to define a cache key for your block, which means you'll need to use something other than Mage_Core_Block_Template. When you create your own block, add this to the constructor:
protected function _construct() {
$this->addData(array(
'cache_lifetime' => 3600,
'cache_key' => $this->someMethodToDifferentiatePages(),
));
}
That last method needs to return a different string to every use case of the block (e.g. one for catalog pages, one for "other" if that's all you need). This will tell Magento which cached version to use
Hope that helps!
Thanks,
Joe
Related
I am currently trying to get a better understanding of how blocks work in Magento. I have looked at some of the files to get a better idea and it has helped a little, but they are a too to complex for my limited skills at the moment and I still do not have proper understanding of what is going on and how to implement them into my site. I realise they are essential to understand for working with Magento so I thought I would set up a list of things to try and achieve:
display a block (done)
display a block and child block
display a block within a magento layout
position a block on the page of a magento layout
learn the most commonly used 'type' attributes and when to use them
So far I have put together
_index_index
Namespace/Module/etc/config.xml
<frontend>
....
<layout>
<updates>
<learningblocks>
<file>Namespace/Module/childblocks.xml</file>
<file>Namespace/Module/blocks.xml</file>
</learningblocks>
</updates>
</layout>
</frontend>
Namespace/Module/controllers/IndexController.php
class Namespace_Module_IndexController
extends Mage_Core_Controller_Front_Action
{
public function indexAction()
{
$this->loadLayout('learningblocks')->renderLayout();
}
public function blocksAction()
{
$this->loadLayout('blocknode')->renderLayout();
}
}
frontend/base/default/layout/namespace/module/blocks.xml
<layout>
<blocknode>
<block type="core/text" name="blocktest" output="toHtml" >
<action method="setText">
<args>some text to display on screen</args>
</action>
</block>
</blocknode>
</layout>
The above worked as expected and displayed the string 'some text to display on screen' on a white page. But thats all i've been able to do, I cannot get child blocks to render onto the screen and I cannot display anything within a theme, let alone try and move it about within that theme
Below is one of my attempts that I cant seem to get to work. Why is this not working?
frontend/base/default/layout/namespace/module/childblocks.xml
<layout>
<abcde>
<block type="core/template" name="childblocks" output="toHtml" template="namespace/module/childblocks.phtml">
<block type="core/text" name="anyname">
<action method="setText">
<args>Some text to add to this page</args>
</action>
</block>
</block>
</abcde>
<learningblocks_index_index>
<update handle="abcde" />
</learningblocks_index_index>
</layout>
frontend/base/default/template/namespace/module/childblocks.phtml
<p>from the childblock.phtml page</p><?php $this->getChildHtml(); ?>
NB: I have changed the namespaces and module names to be more generic, in the hope it is easier to read (they wern't very well chosen names).
I know this is not a complete answer, but it may help those who have struggled with the same problem. I have not gone into great depth as I assume if your searching for an answer you will have already read THIS ARTICLE and that covers it all, I assume you have the same issue as I did i.e. a misunderstanding of what you had learnt from this tutorial.
On reading this answer please be aware I am very new to Magento and there could be some inaccuracies in here, if there are I am sure someone will correct me and edit accordingly.
Firstly this is wrong
public function indexAction()
{
$this->loadLayout('learningblocks')->renderLayout();
}
It should be this
public function indexAction()
{
$this->loadLayout()->renderLayout();
}
and then you will have to map learningblocks node in layout xml to that action module_controller_action. Doing this will display the block in the page within your theme.
So to render a child block
Add something like this in you layout.xml
<module_controller_action>
<reference name="content">
<block type="module/blockname" name="unique_name" output="toHtml" template="path/toyou/template.phtml" >
<block type="module/blockname" name="another_unique_name" output="toHtml" template="path/toyou/template.phtml" />
</block>
</reference>
</module_controller_action>
then in your template file echo out
$this->getChildHtml('another_unique_name')
If you want to remove blocks from your page use the remove node such as
<remove name="right"/>
<remove name="left"/>
This page will offer a list of attributes that can be used to be honest I found that looking through the magento files helped more than that page though
I created my custom block which should replace an existing Magento block.
Wanna to replace the existing Magento block with my block on the whole site, independetly upon the page and the place where the existing Magento block exists. What should be the reference ?
Actually I have something like this:
<default>
<reference name="left">
<remove name="left.newsletter" />
<block type="newsletter/subscribe" name="newsletter" after="-" template="mynewsletter/subscribe.phtml"/>
</reference>
</default>
I remove there the default newsletter on the left and then create my newsletter block. It works but replaces only the newsletter block on the left. Wanna to use my block on the whole site in place of left.newsletter even if the block is in other references like content or right etc. What should I do ?
If you want to replace every occurance of Mage_Newsletter_Block_Subscribe with your own block My_Module_Block_Subscribe, use a class rewrite. In your modules config.xml:
<global>
<blocks>
<newsletter>
<rewrite>
<subscribe>My_Module_Block_Subscribe</subscribe>
</rewrite>
</newsletter>
</block>
</global>
But judging by your code, you actually do not have a custom block, just a custom template. You could change the template with an observer for the core_block_tohtml_before event, that calls setTemplate('mynewsletter/subscribe.phtml') on the block if its class is Mage_Newsletter_Block_Subscribe.
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.
Previously in Magento, the wishlist link was added using the following (in wishlist.xml):
<action method="addWishlistLink"></action>
And you could override that and remove it using the following (in your local.xml):
<remove name="wishlist_link"/>
However, in the newest Magento, 1.4.2, they've changed how the wishlist link is added to the following:
<action method="addLinkBlock"><blockName>wishlist_link</blockName></action>
Anyone know how to remove the wishlist link now they’ve changed how it’s added?
It appears there's no publicly available way to reliably remove the wishlist link block from the layout. (you can skip to the end for a workaround)
The addLinkBlock assumes the presence of the block that's been passed, so using remove in the way you describe results in a fatal error being thrown
Fatal error: Call to a member function getPosition() on a non-object in /Users/alanstorm/Sites/magento1point4.2.dev/app/code/core/Mage/Page/Block/Template/Links.php on line 112
Here's the core code that causes that error
app/code/core/Mage/Page/Block/Template/Links.php
public function addLinkBlock($blockName)
{
$block = $this->getLayout()->getBlock($blockName);
$this->_links[$this->_getNewPosition((int)$block->getPosition())] = $block;
return $this;
}
This method assumes its going to be able to pull out a block by whatever name gets passed, so we can't just remove the wishlist_link block as we could in previous versions.
The only mechanism for removing a link appears to be the following method on the same block class
app/code/core/Mage/Page/Block/Template/Links.php
public function removeLinkByUrl($url)
{
foreach ($this->_links as $k => $v) {
if ($v->getUrl() == $url) {
unset($this->_links[$k]);
}
}
return $this;
}
However, this is done using string comparison, and there's no reliable way (that I know of) to generate a URL Object from a layout file, cast it as a string, and pass it into the method (this would be required, as there are numerous configuration settings that can change what the final string URL will be). That makes this method not helpful for our needs.
So, what we can do it modify the existing wishlist_link block to use a blank or non-existant template. This way the block still renders, but it renders as an empty string. The end result is we avoid the fatal error mentioned above, but still manage to remove the link from our selected pages.
The following would remove the link from all the pages using the default handle.
<!-- file: local.xml -->
<layout>
<default>
<reference name="wishlist_link">
<action method="setTemplate"><template>blank-link.phtml</template></action>
</reference>
</default>
</layout>
In your local.xml file,
<?xml version="1.0"?>
<layout version="0.1.0">
<default>
<reference name="root">
<reference name="top.links">
<!-- Remove wishlist link in magento 1.4.x and newer -->
<remove name="wishlist_link"/>
</reference>
</reference>
</default>
</layout>
You can remove the wishlist link from the admin panel System > Configuration > Wishlist > Enabled = "No"
Add the following to your local.xml file.
<reference name="top.links">
<remove name="wishlist_link"/>
</reference>
This works! I have removed Wishlink from Toplinks and wanted to add it back into another block but that doesn't seem possible when you remove it in this way. Sadly.
I know I'm years late here, but for all of those people who are still looking for answers to this.
I have a way to work around this issue that is only a bit of extra work but it's not hacky and it gives you FULL control of your top.links block.
Simply unset the top.links block and re-create it, it will be empty (no more wishlist_link block) and all you have to do is add whichever links you want inside of it! (Do all of this in your theme/layout/local.xml file of course).
<layout version="0.1.0">
<default>
<!-- HEADER -->
<reference name="header">
<!-- Unsetting the already existing top links block -->
<action method="unsetChild">
<name>topLinks</name>
</action>
<!-- Re-creating a new top links block -->
<block type="page/template_links" name="top.links" as="topLinks">
<!-- EXAMPLE: Account Dashboard Link -->
<action method="addLink" translate="label title" module="catalog">
<label>Account Dashboard</label>
<url helper="customer/getAccountUrl"/>
<title>Account Dashboard</title>
</action>
<!-- You can add any other links that you want -->
</block>
</reference>
</default>
</layout>
Also remember that for some links like Sign In and Log Out you will need to reference your top.links block inside the appropriate <customer_logged_out> and <customer_logged_in> handles instead of inside of <default> as a guide for this you can look at Magento's customer.xml file.
IMPORTANT: If there are any modules included in your project that add links to the top.links block, those links won't show up because local.xml is processed last, so just keep that in mind when using this method :)
I am a Certified Magento Front End Developer with over 3 years of experience and I have overcome LOTS of layout XML headaches to the point where we became best friends.
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