Unobtrusively add block in cart - layout

For a module I'm working on, I want to add a block in the shopping cart screen, I want to do it unobtrusively and I'd like to place it beneath the cart content and before the other blocks (coupon, shipping estimation, totals, ...).
I've managed to do the unobtrusive part: an observer listens to controller_action_layout_load_before and if the FullNameAction is checkout_cart_index it adds a handle of my layout update xml file:
the observer:
public function showUpperGifts($observer)
{
$fullNameAction = $observer->getEvent()->getAction()->getFullActionName();
if ($this->_isEnabled &&
($fullNameAction == 'checkout_cart_index')) {
$layoutUpdate = $observer->getEvent()->getLayout()->getUpdate()
->addHandle('my_special_handle');
}
}
and the layout file:
<my_special_handle>
<reference name="content">
<block type="module/block" name="module_block" template="module/block.phtml"/>
</reference>
</my_special_handle>
With this, the content of my phtml file shows up, but I'm not able to place it where I want.
My first try was to use the before="name.of.block" attribute, but it doesn't work. If I use before="whatever" it goes before everything inside the checkout.cart block, and if I use after="whatever" it goes after everything. In short it doesn't take the content of before or after into consideration.
Looking at the XML layout files of Magento's core modules, I realized that those argument for before and after only appears when the blocks they are placing after or before are inside the right/left columns. So my guess is that it's something special for those columns.
So my question is, can I specify the location of my block inside content? And yes, how?
Another solution would be to load the block asynchronously, as I could then append to the div of my choice the result of the AJAX call, but I'd rather do it in a "normal" way if I can.
Thanks for reading :)

Related

Can I render all zones to an HTML string in a controller method

I'm trying to render the HTML for a content item to a string from within a controller action. Technically I just want to get the "body" part of it without any header/footer stuff. I want to do this so I can get a content item rendering the way I want once, and then display it as a normal orchard page OR by requesting the HTML for the content item via ajax to display it in a div in a JavaScript app. I don't want to have to manually render everything in the JavaScript as that would be duplicating the layout logic I already did. I want to re-use the bulk of the server side rendering so any changes are reflected in my normal orchard page and my JavaScript page. I've been digging into the code and searching everywhere and have gotten close but not all the way there.
I found these:
How to render shape to string?
Using FindView in Orchard
In my controller I have:
var shape = _contentManager.BuildDisplay(contentItem);
Using either of the two methods above, I can render that shape to an HTML string in my controller. All was golden. I was getting the body of that page and using it in JS. Then, I changed a placement file:
<Place Parts_Common_Body="Content:1" />
was changed to:
<Place Parts_Common_Body="/AsideFirst:1" />
The body moved where I wanted it (AsideFirst) in my normal Orchard page but disappeared from the HTML retrieved using the two methods above.
If I look at shape.Content.Items after the BuildDisplay call, I can see the item for the body is no longer there... why is it not rendering all the zones? Or, I guess a more specific question is why is the BuildDisplay method not building the complete shape? Is there a way I can make this work?
I tried a million different things and eventually got this working. Not sure I totally get it yet, but I think the problem had to do with the fact that I was using shape.Content and I'd moved stuff out of the Content zone. And maybe when I was looking at what the BuildDisplay method was returning I was just not looking at some newly created zone that actually did had the stuff I thought was missing. Clearly I need to learn more about zones and shapes... Anyway, I have a new zone called "MainInfo" now that I created in a placement file. I get a MainInfo property on the main shape returned form BuildDisplay and pass shape.MainInfo to the view rendering code and all seems to be working well now.

Orchard CMS ContentShapes - can I add a wrapper?

I have a resource in OrchardCMS that I'm displaying through a number of smaller shapes (so that I can adjust the layout order in placement.info).
In the Driver I am returning these parts through the use of returning a Combined(ContentShape(...), ContentShape(...), ContentShape(...)) etc
However I would like the HTML of each of the smaller shapes to appear within an HTML wrapper (such as a div or article or suchlike)
How do I go about doing this?
Thanks
I understand what you are trying to achieve but it isn't really a feasible scenario. A wrapper is applied to a shape and combined returns several shapes. As you say, each shape has an entry in the placement.info file, so you could easily have these shapes within different content zones or zones spread around your page, where a wrapper would just not work. Make sense?
The answer is probably that you need to create an override for the content view of the content type you are displaying and add the stuff you want to put in your wrapper in there. e.g. if your content type is called MyType and the displayed type was detail, your view would be called Content-MyType.Detail.cshtml.
Do you mean an Orchard wrapper (whole new cshtml file), or just a HTML element?
In the latter case you can do in your part view:
#{
var tag = Tag(Model, "article");
}
#tag.StartElement
stuff
#tag.EndElement
If you want to wrap a (common) wrapper around your elements, you can do the following in your placement.info:
<Place Parts_MyPart="Content:1;Wrapper=MyWrapper" />
<Place Parts_MyOtherPart="Content:2;Wrapper=MyWrapper" />
And create a MyWrapper.cshtml:
<article>
#Display(Model.Child)
</article>

Stash : Conditional Content

First off, a caveat ... I am brand new to Stash. I've heard a lot about it but this is my first time actually playing with it. I get the concept, but am having a hard time figuring this one thing out.
I have a main "wrapper" file and everything within that wrapper stays the same. I would like the option however, to be able to toggle the sidebar on and off if I need to.
I wouldn't think I would need a totally separate layout wrapper would I?
Is there a way to use a boolean variable within stash? (e.g. 2col=TRUE) or am I thinking about it wrong?
Thanks in advance for your help!
Generally what I'd do here is setup multiple Stash gets within the wrapper. Then in your individual templates you can set both the sidebar and the main content area. For parts where you might be repeating content, like the opening and closing divs of a sidebar, you can always drop some snippets inside the stash.
You can also use exp:stash:not_empty [docs] to wrap around the div or container for your sidebar within the wrapper.
I usually use one wrapper for every template. It'll contain an {exp:stash:get name="content"} tag, like yours, which contains the only variable content within.
In my individual templates, I embed the wrapper at the beginning using a regular EE embed ie. {embed="includes/wrapper"}.
Then I stash the content to be inserted into the wrapper using the {exp:stash:set name="content"} tag.
This seems like what you're doing anyway.
If I want to conditionally show a sidebar, I might just pass a variable into the embed.
eg. {embed="includes/wrapper" show_sidebar="yes"}
In my wrapper I would do this:
{if embed:show_sidebar}
Sidebar stuff.
{/if}

What is the difference between remove and unsetChild methods in layout?

What is the difference between remove and unsetChild methods in layout?
For example (in poll.xml layout file):
<customer_account_index>
<reference name="right">
<action method="unsetChild"><name>catalog_compare_sidebar</name></action>
</reference>
</customer_account_index>
Why unsetChild and not just remove?
Remove nodes will be processed after all layout handles are merged, and are a good way to remove a block regardless of which layout handle loaded the block; you just want to get rid of it entirely for some handles! It also removes recursively, so all you need to specify is the layout handle.
On the other hand, you may only want to remove a block from a reference in a specific layout handle, in which case you should use unsetChild. It is often used to remove a block from a reference, but then re-insert the same block with a different position. This would not have been possible with remove.
In your very specific example, the magento developers used it to give magento some flexibility. Let's say I added a subpage for the account index page, and the following layout handles were loaded:
default
...
customer_account_index
customer_account_index_subpage
And now assume on this subpage I would actually want the 'catalog_compare_sidebar' block. If they had used 'remove', I would not be able to add this block (with this specific name) because 'remove' would be processed -after- I had added the block myself.
This allows you to easily make changes from one single file; local.xml.
Taking your code as an example,if you use unsetchild,compare sidebar block removed from right column,but you can use it anywhere like left column,footer etc..,remove removes entirely from the template,and cannot be used anywhere.
Remove the compare sidebar using remove and if you call it somewhere else,error will be thrown.

Magento - display block but only show when I call it with getChildHtml

I have created a block and I have placed it in to the layout xml and it is showing correctly in my theme. My problem is that I actually don't want it to display until I explicitly call it with getChildHtml('myblock').
My block xml looks like this:
<block type="page/html" name="myblock" as="myblock" template="page/html/myblock.phtml"/ >
Anyone have a clue how to achieve this?
Thanks
Place your block inside another that is neither a core/list type nor calls $this->getChildHtml('') (note the empty string). That way it will not be shown automatically and you are free to call it at your discretion.

Resources