Apply Prestashop Cart to custom Hook - prestashop

First let me explain myself. I'm new to Prestashop Development, I've a background using Wordpress. The thing is, I'm trying to hook 'blockcart.php' to my custom hook 'HOOK_SHOPPINGBAG'. I have tried a lot and after a couple of hours I have decided to just ask the question here.
First I have created the Hook inside ps_hook inside the Prestashop Database. This hook is functioning and Prestashop reads it. After that I have added my new hook to FrontController.php, the code is shown below:
public function initContent()
{
$this->process();
if (!isset($this->context->cart))
$this->context->cart = new Cart();
if (!$this->useMobileTheme())
{
// These hooks aren't used for the mobile theme.
// Needed hooks are called in the tpl files.
$this->context->smarty->assign(array(
'HOOK_HEADER' => Hook::exec('displayHeader'),
'HOOK_TOP' => Hook::exec('displayTop'),
'HOOK_SHOPPINGBAG' => Hook::exec('displayShoppingBag'),
'HOOK_LEFT_COLUMN' => ($this->display_column_left ? Hook::exec('displayLeftColumn') : ''),
'HOOK_RIGHT_COLUMN' => ($this->display_column_right ? Hook::exec('displayRightColumn', array('cart' => $this->context->cart)) : ''),
));
}
else
$this->context->smarty->assign('HOOK_MOBILE_HEADER', Hook::exec('displayMobileHeader'));
}
I also have added the Hook to the second bunch of lines inside FrontController.php:
// Call hook before assign of css_files and js_files in order to include correctly all css and javascript files
$this->context->smarty->assign(array(
'HOOK_HEADER' => $hook_header,
'HOOK_TOP' => Hook::exec('displayTop'),
'HOOK_SHOPPINGBAG' => Hook::exec('displayShoppingBag'),
'HOOK_LEFT_COLUMN' => ($this->display_column_left ? Hook::exec('displayLeftColumn') : ''),
'HOOK_RIGHT_COLUMN' => ($this->display_column_right ? Hook::exec('displayRightColumn', array('cart' => $this->context->cart)) : ''),
'HOOK_FOOTER' => Hook::exec('displayFooter')
));
I want to show the Cart inside header.tpl so I have added the Hook to this file:
<div class="shoppingbag">
{$HOOK_SHOPPINGBAG}
</div>
To make sure Blockcart.php can be hooked to my new hook I have added the following line to blockcart.php:
public function hookShoppingBag($params) {
return $this->hookheader($params, 'displayShoppingBag');
}
I've already tried so many things, but when I try to Hook the module to the new Hook it keeps telling me "This modules can't transplant to this hook!"
Maybe I have just made some stupid mistakes, but anyway I hope you guys can help me. Thanks!

I assume you need a custom hook for blockcart module to be placed somewhere.
This is how to achieve it through Presta's custom hook way.
|| $this->registerHook('shoppingBag') == false
Add this to the module's install method.
public function install()
{
if (
parent::install() == false
|| $this->registerHook('top') == false
|| $this->registerHook('header') == false
|| $this->registerHook('actionCartListOverride') == false
|| Configuration::updateValue('PS_BLOCK_CART_AJAX', 1) == false
|| Configuration::updateValue('PS_BLOCK_CART_XSELL_LIMIT', 12) == false)
|| $this->registerHook('shoppingBag') == false
return false;
return true;
}
Create a public method hookShoppingBag like this.
public function hookShoppingBag($params)
{
return $this->hookProductActions($params);
}
To hook it to any tpl use this.
<div class="shoppingbag">
{hook h='presetWishlist'}
</div>

Related

Prestashop displayPaymentReturn hook url

I am new as Prestashop developer and I am trying to create a PaymentModule. I have got to show my payment method but I can not proceed with purchase because I do not know very well hot it works.
Does anyone know where I should redirect to run my hoodDisplayPaymentReturn method?
I will be very happy if someone explain me the complete navigation map to make a purchase.
Anyway, where can I find a relation between hooks and pages?
To develop a payment module you should use 2 main hooks: payment and paymentReturn.
In payment hook you must display your payment option with the specific information. Check bankwire module to see a working example.
In paymentReturn you should show the payment confirmation (or error) information.
When a user click on your payment option link (displayed in payment hook) you should do some validation and processing. After a payment is done (successfully or not) you must call to your module function validateOrder (this is a function of PaymentModule parent class of your module). After that you should be redirected to a controller that will execute paymentReturn hook.
That is the basic process. I strongly recommend you that check bankwire and other payment modules to understand better how to do your own payment module, because is not an easy task for beginner.
Good luck.
when I have a new module for the payment I rely on the simplest provided by PrestaShop: bankwire.
inside you can find 3 hooks.
HookPayment:
public function hookPayment($params)
{
if (!$this->active)
return;
if (!$this->checkCurrency($params['cart']))
return;
$this->smarty->assign(array(
'this_path' => $this->_path,
'this_path_bw' => $this->_path,
'this_path_ssl' => Tools::getShopDomainSsl(true, true).__PS_BASE_URI__.'modules/'.$this->name.'/'
));
return $this->display(__FILE__, 'payment.tpl');
}
hookDisplayPaymentEU:
public function hookDisplayPaymentEU($params)
{
if (!$this->active)
return;
if (!$this->checkCurrency($params['cart']))
return;
$payment_options = array(
'cta_text' => $this->l('Pay by Bank Wire'),
'logo' => Media::getMediaPath(_PS_MODULE_DIR_.$this->name.'/bankwire.jpg'),
'action' => $this->context->link->getModuleLink($this->name, 'validation', array(), true)
);
return $payment_options;
}
hookPaymentReturn:
public function hookPaymentReturn($params)
{
if (!$this->active)
return;
$state = $params['objOrder']->getCurrentState();
if (in_array($state, array(Configuration::get('PS_OS_BANKWIRE'), Configuration::get('PS_OS_OUTOFSTOCK'), Configuration::get('PS_OS_OUTOFSTOCK_UNPAID'))))
{
$this->smarty->assign(array(
'total_to_pay' => Tools::displayPrice($params['total_to_pay'], $params['currencyObj'], false),
'bankwireDetails' => Tools::nl2br($this->details),
'bankwireAddress' => Tools::nl2br($this->address),
'bankwireOwner' => $this->owner,
'status' => 'ok',
'id_order' => $params['objOrder']->id
));
if (isset($params['objOrder']->reference) && !empty($params['objOrder']->reference))
$this->smarty->assign('reference', $params['objOrder']->reference);
}
else
$this->smarty->assign('status', 'failed');
return $this->display(__FILE__, 'payment_return.tpl');
}

How to remove delivery shipping step on prestashop 1.6.1?

I'm new to prestashop and I'm having major trouble removing the delivery shipping step because I only sell virtual products. I am using prestashop 1.6.1.
I know I have to modify order-carrier.tpl file and have followed several posts here and there but couldn't get it done right.
Does any of you have any actual idea on how to do this ?
Bonjour, here is what i did
Override AdminOrderPreferencesController and add a boolean configuration field to toggle this functionnality
$this->fields_options = array(
[...]
'PS_ORDER_PROCESS_BYPASS_SHIPPING' => array(
'title' => $this->l('Bypass shipping step'),
'hint' => $this->l('Do not show shipping step in order process.'),
'validation' => 'isBool',
'cast' => 'intval',
'type' => 'bool'
)
);
You can now find a toggle button in Backoffice under Preferences > Orders
Override OrderController and add an if in init() method to set the current step to payment step if the controller inits itself on delivery step
public function init()
{
global $orderTotal;
parent::init();
$this->step = (int)Tools::getValue('step');
// HERE IT IS
if((bool)Configuration::get('PS_ORDER_PROCESS_BYPASS_SHIPPING') && $this->step == self::STEP_DELIVERY){
$this->step = self::STEP_PAYMENT;
}
if (!$this->nbProducts) {
$this->step = -1;
}
Also bypass the CGV checking verification on payment step in initContent() method.
If you don't, CGV will never be checked, it will redirect you on delivery step, you will tell him that he is in fact on payment step, he will check for CGV again, he will do the same redirection ... and you are in an infinite loop
case OrderController::STEP_PAYMENT:
$cgv = Tools::getValue('cgv') || $this->context->cookie->check_cgv;
if (
!(bool)Configuration::get('PS_ORDER_PROCESS_BYPASS_SHIPPING') && // HERE IT IS
$is_advanced_payment_api === false && Configuration::get('PS_CONDITIONS')
&& (!Validate::isBool($cgv) || $cgv == false)
) {
Tools::redirect('index.php?controller=order&step=2');
}
Pass the configuration parameter to the view to modify display
$this->context->smarty->assign('bypass_shipping_step', (bool)Configuration::get('PS_ORDER_PROCESS_BYPASS_SHIPPING'));
And in your views, do you styling stuff with some if
In order-steps.tpl you can add an {if not $bypass_shipping_step}...{/if} around the fourth li to hide it, and do something like :
{if $bypass_shipping_step}
<style>
ul.step li{
width:25%;
}
</style>
{/if}
or import a dedicated stylesheet which would be cleaner.
Hope it helped.
In shopping-cart.tpl, remove call to order-carrier.tpl. If you are not using one pagecheckout, in orderController.php, you have to change all redirection to step 2 (shipping method choosing), to redirection step 3 Tools::redirect('index.php?controller=order&step=2'); to Tools::redirect('index.php?controller=order&step=3');

why using viewSimple renderer in Phalcon corrupts main renderer

First I declare simple view like this:
$di->set('viewSimple', function() {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir('../app/views/');
$view->registerEngines(array(
".volt" => 'volt'
));
return $view;
});
then to generate html email, I use it as following:
public function renderHTMLEmail($template_name, $template_params) {
$content = $this->viewSimple->render("emails/$template_name", $template_params);
return $this->viewSimple->render("emails/master", array( 'content' => $content) );
}
My emails are being generated just fine, but whenever I call my renderHTMLEmail function actual page rendering is somehow corrupted and page appears totally blank (I have to use redirect as workaround). This is a mystery to me as main view renderer is completely different object. Can I prevent this?
Or does anybody have recommended method of generating arbitrary pieces of html outside of main view rendering process which would not interfere with it? There is couple of similar questions on SO, but none of solutions work. They either don't generate my email or they corrupt main view.
Found a solution, when registering the "\Phalcon\Mvc\View\Simple" component into the DI container make sure to use a new volt instance otherwise it will join up with the application's \Phalcon\Mvc\View volt instance somehow. This is what lot (https://stackoverflow.com/users/1672165/lot) was suggesting in the comments.
Code sample:
public function getTemplate($name, $params)
{
$parameters = array_merge(array(
'publicUrl' => $this->getDI()->getApp()->url->host . $this->getDI()->getApp()->url->baseUri
), $params);
$app = $this->getDI()->getApp();
$this->getDI()->set('simpleView', function() use ($app) {
$view = new \Phalcon\Mvc\View\Simple();
$view->setViewsDir(APP_DIR . $app->application->viewsDir);
$view->registerEngines(array(
".volt" => function ($view, $di) {
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
$volt->setOptions(array(
'compiledPath' => APP_DIR . '/cache/volt/',
'compiledSeparator' => '_',
'compiledExtension' => '.compiled'
));
$compiler = $volt->getCompiler();
$compiler->addFunction('is_a', 'is_a');
return $volt;
}
));
return $view;
});
/* #var $simpleView \Phalcon\Mvc\View\Simple */
$simpleView = $this->getDI()->get('simpleView');
foreach ($parameters as $key => $value) {
$simpleView->{$key} = $value;
}
$html = $simpleView->render('emails/' . $name, $parameters);
return $html;
}
Sample was pulled straight from our working app so may need some re-working but should help solve the original issue.
This works for me using \View as the application DI registered view component which renders controller action volt views and the above \View\Simple with fresh volt registration successfully emails and allows the original view with volt to carry on.
This was asked a while ago however i've not seen a working solution anywhere else.
For completeness I've registered a github issue with the findings: https://github.com/phalcon/cphalcon/issues/3096
I recently had to deal with a similar problem, I'm not certain where you're falling short, but one important thing was to use a separate view from the one used by the application – you're already doing this. See if the following works.
protected function renderView($view, $template, array $data = null)
{
return $view
->reset()
->pick('emails/' . $template)
->setVars($data)
->start()
->render(null, null)
->finish()
->getContent();
}
public function renderHTMLEmail($template_name, $template_params)
{
$content = $this->render($template_name, $template_params);
return $this->render('master', array('content' => $content));
}

Is it possible to render custom view (just custom .phtml) template with Phalcon\Mvc\View?

I need to render email templates in variable to send them later (which are stored in .phtml files), and i really don't want to implement my special class for handling this.
Is it possible to render not controller action view, but custom one?
I tried following code, but it outputs NULL :((
// Controller context
$view = new Phalcon\Mvc\View();
$view->setViewsDir('app/views/');
$view->setVar('var1', 'var2');
// Setting some vars...
$view->start();
$view->partial($emailTemplatePath);
$view->finish();
$result = $view->getContent();
var_dump($result); // Gives null
In addition to the response by Nikolaos, you can use $view->getRender() to render a single view returning its output.
$view->setViewsDir('apps/views/');
echo $view->getRender('partials', 'test'); // get apps/views/partials/test.phtml
You need to check the path of the $emailTemplatePath. It should point to the correct file i.e.
// points to app/views/partials/email.phtml
$view->partial('partials/email');
If you are using Volt and have registered that as your engine, then your file will need to be:
// app/views/partials/email.volt
I have a project where I use email and pdf templates and what I did was to have the rendering all take place within components.
Firstly, my folder structure contains (and I will only put here what is relevant) a cache, components and views directory. Let's look at the email setup rather than the PDF as this is more relevant to your situation.
/app
/cache
/email
/components
/views
/email
/elements
Of course there is public, controllers etc but let's not think about them for this.
I'm using Swift mailer for mine but I hope you will be able to use this all the same. In /app/components/Swift.php I have a __construct that calls for this->init_template_engine();
/**
* Create a volt templating engine for generating html
*/
private function init_template_engine() {
$this->_template = new \Phalcon\Mvc\View\Simple();
$di = new \Phalcon\DI\FactoryDefault();
$this->_template->setDI($di);
$this->_template->registerEngines([
'.volt' => function($view, $di) {
$volt = new \Phalcon\Mvc\View\Engine\Volt($view, $di);
$volt->setOptions([
'compiledPath' => APP_DIR."cache".DS."email".DS, // render cache in /app/cache/email/
'compiledSeparator' => '_'
]);
return $volt;
// or use ".phtml" => 'Phalcon\Mvc\View\Engine\Php' if you want,
// both will accept PHP code if ya don't fancy it being a 100% volt.
},
]);
// tell it where your templates are
$this->_template->setViewsDir(APP_DIR.'views'.DS.'email'.DS);
return $this->_template;
}
The constants above (like APP_DIR) are something I have already made in my bootstrap and all they do is store full paths to directories.
Once the $_template variable has a template engine set up I can then use it to render my templates.
/**
* Returns HTML via Phalcon's volt engine.
* #param string $template_name
* #param array $data
*/
private function render_template($template_name = null, $data = null) {
// Check we have some data.
if (empty($data)) {
return false; // or set some default data maybe?
}
// Use the template name given to render the file in views/email
if(is_object($this->_template) && !empty($template_name)) {
return $this->_template->render($template_name, ['data' => $data]);
}
return false;
}
A sample volt email template may look like this:
{{ partial('elements/email_head') }}
<h2>Your Order has been dispatched</h2>
<p>Dear {{ data.name }}</p>
<p>Your order with ACME has now been dispatched and should be with you within a few days.</p>
<p>Do not hesitate to contact us should you have any questions when your waste of money arrives.</p>
<p>Thank you for choosing ACME Inc.</p>
{{ partial('elements/email_foot') }}
All I have to do then is grab the html and use swiftmailer's setBody method and I'm done:
->setBody($this->render_template($template, $data), 'text/html');
You don't need to place separate view engines like this in components, it could become memory hungry like that, but it does show the whole process. Hope that makes sense :)
The easiest way to render a view and return it as a variable is to use the Phalcon\Mvc\View\Simple class. In your controller, declare a new instance of the Simple view class and attach a rendering engine to it. You can then use its render() method to select a view file and pass in variables:
// create a simple view to help render sections of the page
$simple_view = new \Phalcon\Mvc\View\Simple();
$simple_view->setViewsDir( __DIR__ . '/../views/' );
$simple_view->setDI( $this->di );
$simple_view->registerEngines(array(
'.volt' => 'Phalcon\Mvc\View\Engine\Volt'
));
// use the simple view to generate one or more widgets
$widget_html = array();
$widget_objects = $widget_search->getWidgetObjects();
forEach( $widget_objects as $widget ){
$widget_html[] = $simple_view->render('index/widgetview',array('widget'=>$widget));
}
// pass the html snippets as a variable into your regular view
$this->view->setVar('widget_html',$widget_html);
use $view->render('partials/email') instead of calling partial method.
I usually use Volt engine and a simple way is a redefine view in DI container, like that:
$view = $this->view;
$content = $view->getRender('mail', 'show',
array(
"var1" => "some value 1",
"var2" => "some value 2"
),
function($view) {
$view->setRenderLevel(\Phalcon\Mvc\View::LEVEL_LAYOUT);
}
);
echo $content;

Prestashop - How to display an existing module to a new hook?

Ive created a new hook and I want to add an existing module (blocktopmenu) to that hook.
The hook's name is: topMenu
Ive added this to blocktopmenu.php:
public function hookTopMenu($param)
{
global $smarty;
$this->makeMenu();
$smarty->assign('MENU_SEARCH', Configuration::get('MOD_BLOCKTOPMENU_SEARCH'));
$smarty->assign('MENU', $this->_menu);
$smarty->assign('this_path', $this->_path);
return $this->display(__FILE__, 'blocktopmenu.tpl');
}
Ive added the module to the new hook in Modules --> Position.
Then Ive added this to override/classes/FrontController.php:
function displayHeader(){
parent::displayHeader();
self::$smarty->assign(array(
'HOOK_HEADER' => Module::hookExec('header'),
'HOOK_TOP' => Module::hookExec('top'),
'HOOK_TOP_MENU' => Module::hookExec('topMenu'),
'HOOK_LEFT_COLUMN' => Module::hookExec('leftColumn')
));
}
Finally in themes/mytheme/header.tpl I have:
<div class="my_top_menu">{$HOOK_TOP_MENU}</div>
But nothing happens... the output is:
<div class="my_top_menu"></div>
Any idea how to get it ?
Thanks!
You also need to change the install function in the module to add you hook:
public function install(){
if (!parent::install() OR
!$this->registerHook('header') OR
!$this->registerHook('topMenu') )
return false;
return true;
}
Of course you need to uninstall and re-install the module after that.