Jump to content

Shop-for-ProcessWire (@Apeisa)


Nico Knoll

Recommended Posts

While creating my own payment module I made an interesting discovery:

It is not possible to add a page render hook to the payment module because it will result in an internal server error (500).

Checking the error log:

Error:  Call to a member function getModuleConfigData() on a non-object (line 14 of [...]\site\modules\Shop-for-ProcessWire-master\PaymentAbstract.php)

[edit:]

The problem is if you want the page render hook to work you have to set autoload to true. This results loading the module with every page requests. As soon as PW loads the custom payment module it also loads PaymentAbstract because the custom payment module inherits from
PaymentAbstract. So the PaymentAbstract constructor gets called but because it is in the wrong context (because maybe the user is request a page from the backend or so) some objects are missing...

[edit-end]

So I altered the PaymentAbstract.php constructor checking first if $this->modules exists:

if($this->modules) {
         $data = $this->modules->getModuleConfigData('ShoppingCheckout');
         if (!isset($data['completedUrlSegment'])) {
            $module = $this->modules->get('ShoppingCheckout');
            $data = $module::getDefaultData();
         }
         $page = $this->page;
         $this->currentUrl = $page->url . $data['paymentUrlSegment'] . '/';
         $this->completedUrl = $page->url . $data['completedUrlSegment'] . '/';
      }

I'm not sure if this is the best solution but it works for me.

@apeisa: If you think this is a good solution it might be a good idea to fix it in the github as well...

  • Like 1
Link to comment
Share on other sites

Thanks hdesigns, but I think this could be solved differently.

First off I'm not sure why you need a Page::render hook in the payment module, since as you said you'll need to make it autoload. So it will get loaded on every request, so it doesn't really make sense to add the hook in the payment module, since it could also be added through a simple WireData module.

$this->modules isn't there yet defined in the __construct, so to solve this we could move the config stuff into the init() method in the abstract class, as in the init all those API vars are ready.

Only thing what I found when quickly testing this, is that the title text

$this->title = $this->_("Payment Example");

needs then to be moved to the __construct of the payment module, so checkout module will get it.

Link to comment
Share on other sites

Hi Soma

Here's the deal: In my payment module I need to include some js and css in the head of the html.

I'm totally new to PW so maybe there is a simpler approach (beside just editing the template because I don't want everyone to edit his/her template only to make my module running). If there is one I'm happy to hear.

As far as I understand you I could just create another module only for the script inclution. While this works for sure I'm not happy with the idea. For me it just doesn't make sense to create another module because the payment module could not run without the "render hook module"...

btw: I don't think this problem occurs only in my payment module. Many credit card gateways demands you to include some kind of js in your page to make their process work.

Link to comment
Share on other sites

But the autoload feature makes it load on every request. If you're happy with that :) So you'd have to restrict it to the particular page, parse and add the html to the page.

Here's a better approach:

Load the script to  $config->scripts->add("url/to/script.js");

    public function init() {
        $this->config->scripts->add($this->config->urls->PaymentExample . "script.js");
    }

and adding this to where the scripts should be loaded in the template file:

<?php foreach($config->scripts->unique() as $file) echo "\n\t<script type='text/javascript' src='$file'></script>"; ?>

 after the checkout module render call of course. This is also used by the admin to add and load scripts and css from modules.

Link to comment
Share on other sites

I've read a lot about this approach but I don't like because -as you mentioned- you have to integrate that code line in the template header.

Here's what I've done:

public function addScripts($event) {
		$page = $event->object; 

		// don't add this to the admin pages
		if($page->template == 'admin') return;
      
      //only add it if we are in the payment section of the shoppingCheckout module
      if(!$this->modules) return;
      $checkoutModule = $this->modules->get('ShoppingCheckout');
      if(!$checkoutModule) return;
      if($this->input->urlSegment1 != $checkoutModule->paymentUrlSegment) return;
      
      $additionalHeadScripts = '[myScripts...]';

		$event->return = str_replace("</head>", $additionalHeadScripts.'</head>', $event->return); 
	}
Link to comment
Share on other sites

What you mean by "you have to integrate that code line in the template header" ? Why is this bad?

If you want to distribute a module the admin that wants to integrate this module should just hit the install button and do some configuration. It's called usability...

In my opinion it is not user/admin friendly if you have to pack a readme file to the module that says "but first you have to alter your template file to make that module work"...

I understand you, my approach definitely has it's weaknesses:

- If everyone would do it the way I did PW would risk to get (much) slower

- It needs some (minor) adjustments on the main shop module. So if apeisa decides to keep the code as it is I can't distribute the module either.

Maybe we're a bit off-topic now because this is a whole different problem and has not necesserily to do with apeisas shopping module.

Maybe we should open a new thread to discuss what is the best approach for inserting scripts from a module...

[Edit:]

I've created a new topic for that: http://processwire.com/talk/topic/4472-how-to-insert-scripts-and-stylesheets-from-your-module/

Link to comment
Share on other sites

Yeah I understand your point and I provided the best/correct solution, so you could make your payment module autoload and add hooks. So should be no big deal.

This isn't the official shop module thread btw. :)

Users/admins don't have access to install modules only superusers. So this is usually the site builder that is concerned about installing modules. Adding a line to the templates and be done with it when setting it up makes it a lot more modular at the end.

With doing this to add script via a render hook as you said it's a "hack" that has several drawbacks.

- render hook might get called 2 times, if one decided to use a $page->render() mvc approach to render pages, so the scripts will get added 2 times

- as you said, scalability, it may not important with 1 module on 1 page but you get it

- if you have multiple payment modules doing what you do, they will all add scripts, so you also have to check for what payment module is selected.

I agree it's a little different topic, but the best way is what I showed using $config->scripts, $config->styles. Ultimately it's also what PW admin is doing. Through a render hook might be ok in cases but I wouldn't settle on that as a best practice.

  • Like 1
Link to comment
Share on other sites

Since it wouldn't be autoload, It will only get loaded after when you call checkout render in your template. So as I mentioned it would have to be after the echo $modules->ShoppingCheckout->renderCheckout();. If you have the script output before it won't work.

It depends how you use templates, and the order is important.

Link to comment
Share on other sites

.. had to run ..

so if we go from the default PW site setup with head.inc and foot.inc in your sc-checkout.php you would do it like this:

$checkout = $modules->ShoppingCheckout->renderCheckout();

include("./head.inc");
echo $checkout;
include("./foot.inc");
 

If you want to add the scripts getting loaded in header in head.inc

If you have your scripts before </body> in foot.inc you can also do 

include("./head.inc");
echo $modules->ShoppingCheckout->renderCheckout();
include("./foot.inc");
  • Like 1
Link to comment
Share on other sites

Here's the deal: In my payment module I need to include some js and css in the head of the html.

Are you sure about that? I think it is very rare for any js to actually be required in head (and css definitely not required). So I would probably inject that JS just in processPayment() method of your module. Something like this:

$out = "<script>alert("hello there, this js need to be before the actual payment form")</script>";
$out .= "<form name='processOrSomething'>...</form>";
  • Like 2
Link to comment
Share on other sites

Yeah of course you could just output scripts along with the "form" output. :) Thanks apeisa for throwing that in.

That being said, there's not many modules that generate markup apart from this module and the case where a module needs to output code in the template is rare but of course possible (using render hook). I think if you use this shop module you anyway need to create templates and template code to make it work and adding a line or more to account for scripts is not that bad at all. PW gives you flexibility here as it doesn't dictate how you need to use it. In case of the shop module it is also possible to create you own markup for all the cart, checkout etc and only use the low level functions provided by the modules. 

  • Like 1
Link to comment
Share on other sites

  • 2 weeks later...
  • 2 months later...

For those interested. 

Requires the shop module installed, code not well documented and from the my first steps in PW time. So be honest with me ;)

Hi Luis,

thx for your effort to the development of a lightweight shoping solution! Iam from germany too,

and need something like this for a project Iam working on.

I tryed your template with the module apeisa created. Is there a chance, we are getting a shop profile, with some basic shop functionality and example products in it? Would be super awesome, as Iam struggling to get it to work with just the template files

Link to comment
Share on other sites

A real good processwire shop should have been there already. Come on, we all have seen business growing on the internet year after year and it is growing ever since. The money is on the internet, you know that and I know that. How many of us have to use prestashop or ecommerce or another webshop package because there is no shop module for processwire with the same level. Right now I found a client who wants me to set up a webshop and I feel strange that I can not use processwire for it. I know that Apeisa made a shop module but it is not the same level as prestashop or ecommerce. This is not criticism but this is what is needed these days. I am sure nobody

will mind paying for a good pw shop as every year it is wanted more and more to make money on the internet.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...