I have created one Magento module. It's working perfectly. But my problem is i want to create a module with more than one front page like:
Page 1:
www.magento.com/part/
Page 2:
www.magento.com/part/view/
In my part page there is one form and when i submit this it redirect to view page and i want to display some data whatever pass from part page.
Following is my directory structure:
app\code\local\HK\Part\Block
app\code\local\HK\Part\controllers
app\code\local\HK\Part\etc
app\code\local\HK\Part\Helper
app\code\local\HK\Part\Model
app\code\local\HK\Part\sql
app\design\frontend\default\default\layout
app\design\frontend\default\default\template
app\etc\modules
How can i achieve this?
Assuming you have setup your router correctly you just have to add another action in your controller. In your case it should be viewAction in PartController.php
A basic Magento URL structure can be broken down as follows:
<base url>/<module front-name>/<controller>/<action>/<any other params, optional>
So, from the provided URL structure
base url = http://www.magento.com/
module front name = part
controller = view
action = index (as its the default value, when no action name is provided)
A modules front name is defined in the config.xml file of the module, as follows:
<frontend>
<routers>
<namespace_custom_module_name>
<use>standard</use>
<args>
<module>Namespace_Custommodule</module>
<frontName>custom_frontname</frontName>
</args>
</namespace_custom_module_name>
</routers>
</frontend>
Replace custom_frontname inside frontName tag with part, and this should set you router correctly.
As per the first example, http://www.magento.com/part/, you have to create a IndexController.php with a function indexAction().
For the second example, http://www.magento.com/part/view/, you have to create a controller named PartController.php, with method name as indexAction().
Each action you create, inside a controller represents a page, so use it wisely. As a best practice, actions that works with similar data are always grouped inside a single controller.
For e.g., in CRUD applications, various operations like listing, add, edit, delete, save all actions are usually added to a single controller.
Related
I want to create a new page on my prestashop. I dont want to use the CMS to create the page, I need essentially a totally new page.
I have tried duplicating current .tpl's and renaming them - but I can never navigate to them - what is the url to access the new template?
E.g. say my site is www.xyz.com the "my account" template, sits under template/customer/my-account.tpl this my account page is normally accessed at xyz.com/my-account
I want a new but similar page - so I duplicate this template, rename it to my-account-new and change something in it, why can you not access the new template by change the URL to end with my-account-new - I just get a 404.
What am I missing?
Thanks
:)
you can add a new front controller in a custom module :
ModuleName/controllers/front/ControllerName.php
Then your new controller is a class that should be defined like :
Module::getInstanceByName('<ModuleName>');
class <ModuleName><ControllerName>ModuleFrontController extends ModuleFrontController
Then you add the method
public function initContent(){
parent::initContent();
$this->setTemplate('<templateFolder>/<templateName>');
}
You can now navigate to the template by going to index.php?fc=module&module=ModuleName&controller=ControllerName
So in this example replace every ModuleName with the name of your custom module and ControllerName with the name of your controller (for example MyCustomModule and MyCustomController).
The template will be in the your theme folder for example you can add customAddress in themes/ThemeName/templates/customer/customAddress.tpl
in which case the call to setTemplate would become :
$this->setTemplate('customer/customAddress');
I hope this helps.
For a Magento module I need to load template file and let it replace the complete page. It is a XML file (but could also be any content whatsoever).
Generally speaking when
MYNS_MYMODULE_controllernameController is triggered and calls fooAction() I need to be able to display a clean site with the content from my template file.
Please let me know where to place the template file and how to tell Magento to load this file as a root template without anything else around.
Edit, to clarify it more:
For http://domain.tld/modulename/controller/action/
Where do I have to place template files and how should I reference them?
You could do it like this
$this->loadLayout()->getLayout()->getBlock('root')->setTemplate('page/1column.phtml');
$this->renderLayout();
or to set a custom response
//$file = myfile or html
$this->getResponse()->setBody($file);
$this->renderLayout();
Ideally your template should sit in /app/design/frontend/mypackage/mytheme/template/mytemplate.phtml
You should read Magento doc and Alan Storm Blog. Alan also wrote a book about Magento Layout: No Frills Magento Layout.
Your url: http://domain.tld/modulename/controller/action/
The modulename_controller_action Handle is created by combining the route name (modulename), Action Controller name (controller), and Action Controller Action Method (action) into a single string. This means each possible method on an Action Controller has a Handle associated with it.
In your layout xml handles this request:
<modulename_controller_action>
......
</modulename_controller_action>
Hope my suggestion is useful for you.
I currently work on a magento payment module which has to check if certain fields in a users profile/account are set.
If they do not exist/have no content, I want to either
1. redirect to /customer/account/edit/
2. display a notice that the fields in question has to be filled
or the other way around.
This is initialized by an AJAX call from Magentos core OnePage Checkout.
I tried several things like
Mage::app()->getFrontController()->getResponse()->setRedirect(Mage::getUrl('customer/account/edit/'));
Mage::app()->getResponse()->sendResponse();
exit;
and other things.
From the observer I somehow get a redirect but always end at /default/checkout/cart (which is default?)
In the model I see in chromes network tab that the correct page gets loaded but somehow it wont redirect to the page.
Please let me know if you need more Infos on the problem.
Edit 1: got rid of the second Mage::getURL, still no redirect.
Edit 2: I guess that if I could somehow 'hijack' the response for opcheckout.js it could do the redirect. Or should I maybe just add an extra js which listens as well? I think because the hole thing is triggered by an AJAX call the redirect just doesn't take place at the correct place. More ideas are welcome.
Edit 3: I try to figure at the moment out how to build a response fo the mentioned opcheckout.js which does not trigger the next step but does trigger redirect
Solved it
Solution:
Create an an Override for
/app/code/core/Mage/Checkout/controllers/OnepageController.php
This should be for example
app/code/local/{NameSpace}/{ModuleName}/controllers/OnepageController.php
Pay special attention to the "s" the folder is plural not singular. Took me ten minutes to see why my controller was not working.
The controller should be build like this:
require_once Mage::getModuleDir('controllers', "Mage_Checkout").DS."OnepageController.php";
class MOOD_BonimaScoreIdent_OnepageController extends Mage_Checkout_OnepageController {
public function indexAction(){
parent::indexAction();
}
public function savePaymentAction(){
//just an example
$result['redirect']=Mage::getUrl('customer/account/edit/');
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($result));
return;
}
}
The config.xml part to include the controller override is simply:
<frontend>
<routers>
<checkout>
<args>
<modules>
<MyModuleName before="Mage_Checkout">Namespace_MyModuleName</MyModuleName>
</modules>
</args>
</checkout>
</routers
</frontend>
After trying to debug for hours I'm out of ideas and hope for some clarification (I guess I missunderstood a concept at some point).
The backstory: Some base categories need an "overview page" which should be generated automatically from child categories and products. So my approach was to add a sub category to every base category and create a custom page layout which is being used from all these sub categories. For my client this would be very easy to manage in the Magento backend since he would only need to change the value in one drop down. So I created a simple module defining the new page layout. Within the backend I was able to select this one as well.
The module config:
<?xml version="1.0"?>
<config>
<modules>
<Company_Layouts>
<version>0.1.0</version>
</Company_Layouts>
</modules>
<global>
<page>
<layouts>
<company_category_overview module="page" translate="label">
<label>Kategorie-Übersicht</label>
<template>page/1column.phtml</template>
<layout_handle>company_category_overview</layout_handle>
</company_category_overview>
</layouts>
</page>
</global>
<frontend>
<layout>
<updates>
<company_layouts>
<file>company_layouts.xml</file>
</company_layouts>
</updates>
</layout>
</frontend>
</config>
Since these special overview pages require some layout changes I was hoping to reference the layout in a specific layout file (company_layouts.xml)... and here my logic is leaving me:
With <layout_handle>company_category_overview</layout_handle> I was hoping to define a handle which I can use to change the layout only when this specific page template is being used. Exactly this is not the case. My layout updates which are inside the handle company_category_overview are just being ignored.
After digging deeper I realized, it doesn't seem to be my code but more like a general issue. In an old Magento 1.4 installation the page layout handle is being carried to all sites, like page_one_column. In Magento 1.7 and (what I'm using now) 1.8 this is only on the home page the case. I'm using Commerce Bug for debugging. I just tried this with a fresh 1.7 and a freh 1.8 installation.
Is this some concept I don't understand or just a plain bug?
Also, I'm aware that layout updates can be achieved within the backend but this would only be my last option since I feel it's much cleaner having this in a seperate file without the need of copy/pasting such stuff.
Is this some concept I don't understand or just a plain bug?
Both? Neither? The information in the <page><layout>...</layout></page> node is used by both the category pages and CMS pages, but each system uses the the information differently, and neither system uses it in a way you'd expect. Here's a rundown on how category pages use this information.
The category page is rendered by the following controller action
#File: app/code/core/Mage/Catalog/controllers/CategoryController.php
public function viewAction()
{
...
}
This controller action doesn't have the standard loadLayout and renderLayout method calls. Instead, there's a lot of extra code in this method for adding layout handles and doing things between generating the blocks and rendering the final layout. The section we're interested in is this
$design = Mage::getSingleton('catalog/design');
$settings = $design->getDesignSettings($category);
#...other stuff we don't care about...
if ($settings->getPageLayout()) {
$this->getLayout()->helper('page/layout')->applyTemplate($settings->getPageLayout());
}
When you save a category with your "Page Layout" in the Custom Design tab, the getPageLayout method call above should return company_category_overview. On category pages, Magento doesn't use this to apply a handle, instead it passes the values to the applyTemplate method. Here's that method in full.
#File: app/code/core/Mage/Page/Helper/Layout.php
public function applyTemplate($pageLayout = null)
{
if ($pageLayout === null) {
$pageLayout = $this->getCurrentPageLayout();
} else {
$pageLayout = $this->_getConfig()->getPageLayout($pageLayout);
}
if (!$pageLayout) {
return $this;
}
if ($this->getLayout()->getBlock('root') &&
!$this->getLayout()->getBlock('root')->getIsHandle()) {
// If not applied handle
$this->getLayout()
->getBlock('root')
->setTemplate($pageLayout->getTemplate());
}
return $this;
}
The pertinent parts are this line,
$pageLayout = $this->_getConfig()->getPageLayout($pageLayout);
which will load the information from your configuration
<label>Kategorie-Übersicht</label>
<template>page/1column.phtml</template>
<layout_handle>company_category_overview</layout_handle>
as a Varien_Object. Then, it will use this information to apply a template to the root block.
$this->getLayout()
->getBlock('root')
>setTemplate($pageLayout->getTemplate());
So, for category pages, the information in the <layout_handle/> node is never used. That's why your layout updates aren't being applied — Magento actually applies your handle.
I'm attempting to use an observer to modify the response of the add to cart controller action, but only in the context of an AJAX request.
My observer is called and my JS is retrieving data fine, I have verified this by putting a die() in my observer function cartAdd() and verifying the response developer console, which I am using to see the result of my response from Magento. So JS isn't the issue here.
My primary problem is that I can't seem to modify the response through the normal functions. I get the request by using $observer->getEvent()->getControllerAction()->getResponse() and then make changes to it by setHeader(), or setBody(), or any other function that modifies the response, but there is absolutely no effect to the response!
Does anybody have any clue as to why I'm not able to modify the response in my observer?
In /app/code/local/mynamespace/mymodule/etc/config.xml:
<frontend>
....
<events>
<controller_action_predispatch_checkout_cart_add>
<observers>
<mymodule_cart_add>
<type>singleton</type>
<class>mymodule/observer</class>
<method>cartAdd</method>
</mymodule_cart_add>
</observers>
</controller_action_predispatch_checkout_cart_add>
</events>
</frontend>
In /app/code/local/mynamespace/mymodule/Model/Observer.php:
public function cartAdd(Varien_Event_Observer $observer)
{
$controllerAction = $observer->getEvent()->getControllerAction();
if($controllerAction->getRequest()->isAjax()) {
$response = $controllerAction->getResponse();
// I've even tried using:
// $response = Mage::app()->getResponse();
$response->setHeader('HTTP/1.1','403 Forbidden'); //using this because i will need it in my final code and it will make it immediatly obvious the response has been changed
$response->setHeader('Content-type', 'application/json');
$response->setBody('hello world!!!!');
// this is to stop the product from being added to the cart
$controllerAction->setFlag('', Mage_Core_Controller_Varien_Action::FLAG_NO_DISPATCH, true);
}
}
Please note: I know this code isn't going to at all AJAXify adding to cart (which is my end goal). At the moment I am just trying to resolve this issue
I end up just getting the contents of the page that you would end up on as a result of running an add to cart action:
When a product is added to cart there is admin-configurable behavior to send a person to the cart page or to redirect them back to the product page. See the System > Configuration > Checkout > Shopping Cart: After Adding a Product Redirect to Shopping Cart field.
This redirect behavior is accomplished via a redirect which will displace any redirect set in the dynamic controller_action_predispatch_checkout_cart_add event; ref. the final bit of logic from the Mage_Checkout_CartController::addAction(). Have no fear, though! Magento core developers have the need to override this behavior as well, so it is possible to inform the Mage_Checkout cart controller's addAction() method to bypass the normal redirect behavior if a flag has been set on the checkout/session object. Not only is there a hook and supporting logic to make it work, but there is actually a working example from the core - always a good thing for developers.
Just prior to the final redirect logic in the addAction() method, the cart controller's addAction() method dispatches the checkout_cart_add_product_complete event. This event is observed by the Mage_Wishlist observer. A quick review of relevant final logic from the Mage_Wishlist_Model_Observer::processAddToCart() method shows how to prevent the cart controller's addAction() method from redirecting - namely by setting the no_cart_redirect flag on checkout/session object, which preserves the redirect set on the response object.
There is one more consideration in this case. It's likely that the Mage_Wishlist observers behavior should be preserved, namely: after adding a product to cart from the wishlist, a customer may be redirected to the next product in their wishlist. This is one of the instances when observer processing order matters. To make sure that the Mage_Wishlist module's add to cart behavior is preserved, other modules which consume the checkout_cart_add_product_complete event should fire before the Mage_Wishlist observer. In the declaration file for the custom module, the Mage_Wishlist module should be set as dependent on the custom module, which will ensure that the custom module's observer will fire before the Mage_Wishlist module:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<modules>
<Custom_Module>
<active>true</active>
<codePool>local</codePool>
</Custom_Module>
<Mage_Wishlist>
<depends>
<Custom_Module />
</depends>
</Mage_Wishlist>
</modules>
</config>
If the Mage_Wishlist module were not a factor, the better targeted event to consume would be the dynamically-generated controller_action_postdispatch_checkout_cart_add event, which is the last targeted event before the generic controller_front_send_response_before event.