My intent is to track conversions through multiple channels by inserting third party javascript (for example google analytics, optimizely, pricegrabber etc.) into the footer of onepage success .
I've accomplished this by adding a block to the footer reference inside of the checkout success node within local.xml and everything works appropriately.
My questions are more about efficiency and extensibility.
It occurred to me that it would be better to combine all of the blocks into a single block reference and then use a various methods acting on a single call to the various related models to provide the data needed for insertion into the javascript for each of the conversion tracking scripts.
Some examples of the common data that conversion tracking may rely on(pseudo):
Order ID , Order Total, Order.LineItem.Name(foreach) and so on
Currently for each of the scripts I've made a call to the appropriate model passing the customers last order id as the load value and the calling a get() assigning the return value to a variable and then iterating through the data to match the values with the expectations of the given third party service.
All of the data should be pulled once when checkout is complete
each third party services may expect different data in different formats
Here is an example of one of the conversion tracking template files which loads at the footer of checkout success.
$order = Mage::getModel('sales/order')->loadByIncrementId(Mage::getSingleton('checkout/session')->getLastRealOrderId());
$amount = number_format($order->getGrandTotal(),2);
$customer = Mage::helper('customer')->getCustomer()->getData();
?>
<script type="text/javascript">
popup_email = '<?php echo($customer['email']);?>';
popup_order_number = '<?php echo $this->getOrderId() ?>';
</script>
<!-- PriceGrabber Merchant Evaluation Code -->
<script type="text/javascript" charset="UTF-8" src="https://www.pricegrabber.com/rating_merchrevpopjs.php?retid=<something>"></script>
<noscript><a href="http://www.pricegrabber.com/rating_merchrev.php?retid=<something>" target=_blank>
<img src="https://images.pricegrabber.com/images/mr_noprize.jpg" border="0" width="272" height="238" alt="Merchant Evaluation"></a></noscript>
<!-- End PriceGrabber Code -->
Having just a single piece of code like this is not that big of a deal, but we are doing similar things with a number of different third party services.
Pricegrabber is one of the simpler examples.
A more sophisticated tracking service expects a comma separated list of all of the product names, ids, prices, categories , order id etc.
I would like to make it all more manageable so my idea to do the following:
combine all of the template files into a single file
Develop a helper class or library to deliver the data to the conversion template
Goals Include
Extensibility
Minimal Model Calls
Minimal Method Calls
The Questions
1. Is a Mage helper the best route to take?
2. Is there any design pattern you may recommend for the "helper" class?
3. Why would this the design pattern you've chosen be best for this instance?
You could create a custom module that extend Google Analytics
In /app/code/local/MageIgniter/SiteTracker/etc/config.xml
<config>
<modules>
<MageIgniter_SiteTracker>
<version>0.1.0</version>
</MageIgniter_SiteTracker>
</modules>
<global>
<blocks>
<googleanalytics>
<rewrite>
<ga>MageIgniter_SiteTracker_Block_CustomTracking</ga>
</rewrite>
</googleanalytics>
</blocks>
</global>
</config>
Then modify this method as needed from see app/code/core/Mage/GoogleAnalytics/Block/Ga.php
In /app/code/local/MageIgniter/SiteTracker/Block/CustomTracking.php
class MageIgniter_SiteTracker_Block_CustomTracking extends Mage_GoogleAnalytics_Block_Ga
{
protected function _getOrdersTrackingCode(){
....
}
}
sounds like a lot of fun by getting to know Magento I'd suggest you to start from Alan Storm's blog and magento knowledge base
The reality is that you don't need another pattern on top of already designed framework and easiest way and maintainable way is to follow existing patterns and in your case it would be:
make your extension
make your templates by service provider
make your layout descriptors by provider
tie them together with one block or use multiple blocks (to be more manageable)
no matter what you do the most gain in performance in case of Magento comes from caching your block output and layout descriptors and handlers are cached by default for you
so think through what you can cache
* css, js can be minified and compressed
* templates that you need most probably contain new information cause each order is different so you can't cache those and you need new data to send to service provider
if you don't add new business logic then i'd suggest to code your output methods in blocks as most of the time you are just filling javascript variables with data here and don't need to calculate anything new
Related
I am a few weeks into using Magento, and this is a URL for which I'm trying to track the output file (I believe it would be a .phtml file):
http://mytest.shopland.com/smi130495/catalog/category/view/s/his-jewelry/id/312834/
the first parameter smi130495 is the store parameter, and obviously the last two are a name-value pair for the category. I'm pretty sure we have NOT touched core, so there might be files in local. However I'm also aware that there is a skin folder. Does anyone have a suggestion of how to interpret it? Thanks.
It would probably help you a lot to read an article about how Magento routing works, but I will explain briefly what your URL means:
smi130495: As you stated, this is your store code. Since Magento can support multiple tiers of websites/stores, this is an optional piece that depends on your setup.
catalog/category/view: This is the routing information (module, controller, action). This gets translated into a dispatch of Mage_Catalog_CategoryController::viewAction() found in the file app/code/core/Catalog/controllers/CategoryController.php.
s/his-jewelry: You are correct that this is where the params begin. This looks like a search term being passed from search results.
id/312834: This is the category ID that will be loaded by the dispatched controller action.
Knowing this information is the first clue to finding the code that will be used to create your output, but there is much more that goes into the rendering of the final output. It would be too long to explain everything here that can impact output since, for example, Magento uses an intermediate XML-based layout layer of “blocks” that in turn make use of templates to render specific pieces of content on the page.
However, I can point you to the main template for your route app/design/frontend/$package/$theme/template/catalog/category/view.phtml, which gets added to the layout like this in app/design/frontend/$package/$theme/layout/catalog.xml:
<reference name="content">
<block type="catalog/category_view" name="category.products" template="catalog/category/view.phtml">
</reference>
Hope that helps you some.
In Magento .phtml files are inside :
Admin panel files : app/design/adminhtml/default/default/template
Frontend files : /app/design/frontend/default/{theme name}/template
Like in query you are searching for category/view file
app/design/frontend/default/{theme name}/template/catalog/category/view.phtml
To make life easier, you can use several tools. Finding Templates in Magento sometimes is alot of work. Template Hints are a good way to find templates quicker. You can enable template-hints in the Magento backend in the Configuration under System->Development. In case you want a better solution with template hints, you can use this module from AOE:
https://github.com/AOEpeople/Aoe_TemplateHints
Hope this helps, regard, David
I'm confused while creating a block or call a block. in phtml file suppose in footer.phtml file if I want to call a static block then I write
<?php echo $this->getLayout()->createBlock('cms/block')->setBlockId('static_block_name')->toHtml(); ?>
and for newsletter(which is in template folder in my theme folder)
<?php echo $this->getLayout()->createBlock('newsletter/subscribe')->setTemplate('newsletter/subscribe.phtml')->toHtml(); ?>
so what should I write in footer.phtml to call a built in block(which is in base folder) like calendar,captcha etc ?
please tell me how can I call those in phtml file and xml file.
please tell me
1. <?php echo $this->getLayout()->createBlock('**?**')->setTemplate('**?**')->toHtml(); ?>
2. xml block code and where to put the code
3. rules to write block type and name.
-Thanks.
The only difference between the two blocks that you are mentioning is the type. The cms/block type is a built in way for you to create arbitrary text blocks with optional references to additional content (additional information native to Magento via widgets such as links or calls to other blocks).
The second block that you list is that of a block that represents a specific block which is used to output a specific model with a specific template. If you dive into the structure of Magento, you will find that the code that is core to Magento exists in the app/code/core/Mage folder. Inside of that, you will find items such as catalog/category, catalog/product, newsletter/subscribe etc. Additionally, according to MVC, you will need a way to present that model to the user via a view, or template by Magento's terms. Views into models will exist in the app/design/frontend/{package}/{theme}/template/ folder. You should find some continuity between the two sets of folders and will arrive to a set of views that you can use to output a block. In this case of a product, you will find app/code/core/Mage/catalog/product/ and app/design/frontend/base/default/template/catalog/product/view.phtml.
Hopefully this will set you on your way to better understanding the beast that is Magento. Magento, as described by Alan Storm, is not your father's PHP.
I have used this module creator to get an custom attribute (which takes the type 'file').
http://www.silksoftware.com/magento-module-creator/
This works and can be seen in the admin area. I also have other custom attributes for customers which I have used this tutorial to create:
http://www.fontis.com.au/blog/magento/know-more-about-your-customers-adding-custom-signup-attributes
This also works. The reason I used the module creator was because I was unsure of how to make the input type as 'file'.
The attributes created through the fontis tutorial can be displayed as needed on the front end (which was only needed in the registration form).
The problem I'm having is in the custom area in the logged in accounts area on the front end. What I need is to retrieve the value of the 'file' attributes which was created in the module creator. Could anyone point me in the right direction of how to display these please? I have tried getAttributeName but this is not working.
Thank you.
If you post the code from your custom module we could help you more.
Meanwhile, here is some info that could help you:
Whenever you store something in the DB using a module, there is a Model class (that allows you to access the necessary data)
You can find the class name by looking in your modules etc/config.xml file
In the file look for section named <models>
The sub nodes of <models> is the name of the namespace (see below)
The sub node of your 'namespace' called <class> contains the rest of the info you will need
Next you need to call the Model with Mage::getModel('namespace/class_name')->load($id); to get a collection of all the custom attribute records that are in the system
To break this down in to manageable pieces:
Let's assume this is what your config.xml contains:
<models>
<customattribute> // this is your namespace
<class>Mycompany_Customattribute_Model</class> //this tells you wher to find your model files
<resourceModel>customattribute_resource</resourceModel>
</customattribute>
...
</models>
This means that your 'namespace' is 'customattribute'.
Next you need to find the file that contains your Model.
In this case we look at the <class> node to give us the file location (in this case app/code/local/Mycompany/Customattrbute/Model), now we need to go there and see the file that is there (let's say it's called 'File.php')
To get all the data we call the follwoing function:
Mage::getModel('customattribute/file')->load();
This will give us all the data.
If we want to narrow it down we can use the following function:
Mage::getResourceModel('customattribute/file')->addFieldToFilter('name_of_filed_in_db', 'value_we_want');
I've been scouring the net in pursuit of this one. Magento Commerce comes us dry for me. grepping core code, reading Alan Storm, perusing Inchoo, and even finding related questions on SO turn up no answers for me.
With that said, my problem is with a transactional email template that works when processed from the backend but not from the frontend. Here's a snippet:
<td width="100%" colspan="2" align="left">
<!-- inject products quote table -->
{{block type="adminhtml/sales_quotation_email" template="sales/quotation/email_quote_items.phtml" inherits=$template quote=$quote salesrep=$salesrep}}
<!-- inject cross-sell products table -->
{{block type="adminhtml/sales_quotation_email" template="sales/quotation/email_quote_cross_sells.phtml" inherits=$template quote=$quote salesrep=$salesrep}}
</td>
In the backend, these blocks are rendered as expected. In the front-end, everything above and below these block directives is rendered, but it appears that the directives die in processing when it comes time to render the template. No errors are thrown.
I followed the advice here, but no luck. Originally I tried to use setDesignConfig on the email template model, but that didn't work. I even tried to set the area as an attribute in the directive, but that also did not work. A colleague suggested that I have two copies of the above templates: one set in design/adminhtml and the other design/frontend. I'd rather not have to worry about extra maintenance. Plus, I fear that I'd encounter the same problem if the block type specified in the directive comes from adminhtml. I don't want that solution.
So what am I doing wrong? What do I not understand?
How does Magento resolve the real path to the template, and is a template forced to reside in the area of its parent block?
Help is needed! Thanks.
SOLVED
I found a related post on Magento Commerce that put me back on track. I started dumping out the design configuration in two controllers: 1 in frontend and one in adminhtml. I noticed immediately that theme information was missing in the frontend request. See some sample output from my frontend controller:
Mage_Core_Model_Design_Package Object (
[_store:protected] =>
[_area:protected] => frontend
[_name:protected] => mypackage
[_theme:protected] => Array
(
[layout] =>
[template] =>
[skin] =>
[locale] => mytheme
)
[_rootDir:protected] =>
[_callbackFileDir:protected] =>
[_config:protected] =>
[_shouldFallback:protected] => 1 )
Notice that layout, template, and skin are empty in the theme property. When I dumped the design configuration from an adminhtml controller, these properties were set.
So going back to my frontend controller, I added the following line before I instantiated my email template model:
Mage::getDesign()->setArea('adminhtml');
Mage::getDesign()->setTheme('mytheme');
And poof! It worked! My blocks directives were processed and the fully rendered content was returned as expected.
So although my thinking was correct to set the area, that alone wasn't enough. I also has to configure the theme.
I'm happy with the solution. I hope it helps others. But to fully answer this question, I'm still curious if anyone knows why package information is missing from the design configuration during a frontend request. Does it have to do with the block type in the directive coming from adminhtml? That would make sense, because adminhtml has no need to worry about theme information. I just don't know where those decisions would be made in core code. See update below.
UPDATE:
Learned even more since the original post. My question gave a code sample that built a block of a type that came from adminhtml. The path to the template, I thought, was resolving to the front-end, and that was why no template could be found. That wasn't actually the case. An adminhtml block, because of its class naming convention, will look in design/adminhtml/package/default/module for your template.
However, in my particular Magento installation, I have a design override in local.xml that changes the admin theme so that it admin requests check design/adminhtml/package/mytheme/module for templates. And that is where my phtml templates are stored. So on a front-end request, the controller has no clue about this override, and is only building up the design configuration based on what is set in the store configuration for the particular package and theme.
In summary, my call to setTheme() must utilize that modified config data, like so:
Mage::getDesign()->setTheme(
(string) Mage::app()
->getConfig()
->getNode('stores/admin/design/theme/default')
);
I guess that goes to say, then, that a simple call to setArea() would be sufficient for most installations.
Finally, you will need to revert the design configuration changes after your work is done, otherwise subsequent actions might produce undesired results.
I wish to remove the following setting:
<cms>enterprise_pagecache/processor_default</cms>
... from the config.xml of the core / Enterprise / PageCache / config.xml file so that the home page will not be cached, (because we have a complicated custom store switch in place).
Since this value is not stored in core_config_data I am unsure of the best way to override the out of the box value. The comments above the line in the core file do hint that it is not actually bad practice to edit this file, however, can I open this to the community to see what they think?
PS = This is a multi website setup with a custom store switcher.
Hole punching is what it sounds like you may need.
Add a etc/cache.xml file with a <config> root to your module. (see Enterprise/PageCache/etc/cache.xml). Choose a unique [placeholder] name.
The placeholders/[placeholder]/block node value must match the class-id of your custom dynamic block, e.g. mymodule/custom
The placeholders/[placeholder]/container node value is the class to generate the content dynamically and handle block level caching
The placeholders/[placeholder]/placeholder node value is a unique string to mark the dynamic parts in the cached page
placeholders/[placeholder]/cache_lifetime is ignored, specify a block cache lifetime in the container’s _saveCache() method if needed
Implement the container class and extends Enterprise_PageCache_Model_Container_Abstract. Use _renderBlock() to return the dynamic content.
Implement the _getCacheId() method in the container to enable the block level caching. Use cookie values instead of model ids (lower cost).
One last note: You DON’T have the full Magento App at your disposal when _renderBlock() is called. Be as conservative as possible.
SOURCE: http://tweetorials.tumblr.com/post/10160075026/ee-full-page-cache-hole-punching