Specific payment methods for virtual products in Prestashop

In this quick tip we will see how to enable or disable payment methods for virtual products in Prestashop

If you are selling both virtual and normal products, it might be worth displaying your customers specific payment methods depending on what they’re buying. It’s useless, for example, to allow them to pay by cash on delivery something they can download soon after purchase! Similarly, you might want to offer a specific digital payment for virtual products only.

It is important to know that the modification we are about to apply needs to be made on every single payment module you want to restrict. This means having to hard-modify core files on older prestashop versions, or using overrides on newer than 1.6.0.11. For simplicity, I will modify core files, but have a look at my tutorial on how to override Prestashop Modules’ core files.

The hookPayment method

The simplest way to restrict our payment methods is to modify the method named hookPayment, used by every single Prestashop Payment module. It’s the function responsible of displaying payment methods during the checkout, so hiding them here will prevent people from continuing the purchase with them.

We will use bankwire as an example, but any other will equally do. Since non-standard modules might have their own rules, it’s better to add these lines of code at the very beginning of the method.

Therefore, open up modules/bankwire/bankwire.php (or use overrides), and scroll to the hookPayment method, which looks like this:


	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');
	}

First of all, we need to check which products are in the cart

$products = $this->context->cart->getProducts();

Then, we loop through them, and see if any is virtual:

		$products = $this->context->cart->getProducts();

		if($products)
		{
			foreach ($products as $product) {
				if ($product['is_virtual'])
				{
					// what to do?
				}		
			}
		}

It’s dead easy, isn’t it? Now we can choose what to do, let’s try removing bankwire for virtual products!

		$products = $this->context->cart->getProducts();

		if($products)
		{
			foreach ($products as $product) {
				if ($product['is_virtual'])
				{
					return false;
				}		
			}
		}

What happens now? This will kill the bankwire payment method whenever someone has a virtual product in the cart. It means, of course that it won’t be accessible even if there are other products there. This might lead to unwanted situations, when no method is available at all.

For example, you have two methods: bankwire, and paypal. You remove bankwire with this method on virtual products, and paypal on others. What happens when a user has both a virtual and normal product in the cart? No method will be available! We therefore need to make a choice, whether to leave a warning in the cart page (shopping-cart.tpl) or explore another way.

We might want to only hide the method if all products are virtual, for example. How to?

The easiest way is to use $this->context->cart->isVirtualCart(), which will return true if all products in it are virtual. Alternatively, we can do it manually ourselves:

	if($products)
	{
		$virtuals = 0;
		foreach ($products as $product) {
			if ($product['is_virtual'])
			{
				$virtuals++;
			}		
		}
		if($virtuals == count($products))
			return false;
	}

In this case, we use a counter to check how many virtual products we have. If all of them are virtual, we disable the module! How can we revere it then?

		$products = $this->context->cart->getProducts();

		if($products)
		{
			foreach ($products as $product) {
				if (!$product['is_virtual'])
				{
					return false;
				}		
			}
		}

This will disable bankwire whenever a non-virtual product is in the cart.

	if($products)
	{
		$nonvirtuals = 0;
		foreach ($products as $product) {
			if (!$product['is_virtual'])
			{
				$nonvirtuals++;
			}		
		}
		if($nonvirtuals == count($products))
			return false;
	}

While this other will hide it when all products are physical.

Conclusion

There are many ways to utilize the restriction, depending on your needs (such as even buying a certain number of products!). Just keep in mind that you might end up not having any payment available if you mix up the wrong conditions!

You like the tuts and want to say "thank you"? Well, you can always feel free to donate:

  • aidilweb

    Thanks for your tutorial.

    With this tutorial i can hack payment method for custom prestahsop

  • daniel curbelo

    Hello, very good your site.
    Sorry for my bad translation with google translate.
    I need help with an issue of Paypal and do not know how to follow, I hope you can help me. I’m putting together a store for Uruguay in Prestashop and I can not make the block paypal ALWAYS display at the checkout (although all products are Uruguayan pesos)?
    I want to sell in Uruguayan pesos and Paypal block appears in the checkout and of course make the conversion to USD.
    I PS1.6 and I’m testing with Paypal Europe. Currently I have already verified that the conversion does not even appear in the checkout but obviously I need for customers APPEARS.
    Finally I would like to know what the most appropriate version of paypal to Uruguay.
    Thank you very much and greetings from Uruguay.

    • winnister

      I’m REPORTING YOU TO THIS SITE! you’re RUNNING AN ILLEGAL SCAM AND THE fbi WILL BE FOLLOWING YOU AND WILL PROSECUTE YOU!

Store Top Sales

You like the tuts and want to say "thank you"? Well, you can always feel free to donate: