- 
                Posts721
- 
                Joined
- 
                Last visited
- 
                Days Won3
Everything posted by froot
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development I have another question concerning fieldgroups. The installation now seems to work flawlessly, the module installs fields and fieldgroups and template with these fieldgroups. When editing the template in the GUI, I get a different interface to what I am used to when the template was created in the GUI, see screenshot attached. Does that raise any red flags? Why can't I add other fields to the template? Is that a security measure of some sort? What are other limitations apart from the obvious one?
- 
	thanks for the input, I'm a step further now. Is there a way to catch a PHP Notice? I'd like to stop the code and handle appropriately or at least create a log or get an email if anything goes wrong so I can debug. Because it's quite a work load to anticipate everything that could go wrong and throw exceptions manually… Right now I can only catch \Exception, \Throwable and WireException I believe.
- 
	OK I it looks like I need to catch the exceptions manually, thus evaluate the return values. Anyways, It's easy to throw an error/exception if you know what can go wrong but I cannot anticipate everything that could go wrong so how to catch any type of error? Can I catch internal server errors?
- 
	I'm having troubles understanding some basic php… How can I catch errors of nested methods… Do I need to check for the 'error' key in the the $result variable manually? Or like make subMethods1 return true/false and check for that in the topMethod's try block? I still want to return what the error was in the subMethod… class myClass extends WireData {s public function topMethod($item) { $result = []; $result['title'] = $item['title']; try { if ($item['title'] == 'subMethod1') { $array = $this->subMethod1($item); $result = $this->mergeArrays($array, $result); } if ($item['title'] == 'subMethod2') { $array = $this->subMethod2($item); $result = $this->mergeArrays($array, $result); } } catch (WireException $e) { $result['errors'] = $e; } return $result; } protected function subMethod1($item) { try { $result['foo'] = 'bar'; $result['foobar'] = 'foobar'; $result['yada'] = 'blah'; echo $unKnownVariable; // throws error return $result; } catch ($e) { $result['error'] = $e; return $result; } } protected function subMethod2($item) { try { // ... } catch ($e) { // ... } } protected function mergeArrays($array, $result) { foreach ($array as $key => $value) { $result[$key] = $value; } return $result; } }
- 
	  KIOSK, One-Page Checkout Module for ProcessWirefroot replied to froot's topic in Module/Plugin Development there's a new version on github now that also installs a stack_prices repeater field and a ready-to-use product template. Hope that helps. I'm trying to give users with guest role permission to view (at least) the kiosk dashboard page on kiosk.datajungle.xyz, but don't know how yet. Any help is welcome. If you installed the first version and want to use the new one, uninstall while still on the first version because I renamed the templates and fields and whatnot to keep it more consistent. Sorry about the inconvenience, if there's a better way to do it? Still learning how to use the "update" functionality of modules.
- 
	always struggling with this. How to get the only or first image what ever the images field type (array or single or automatic)? // check if there is one if(count($item->images)){ echo $item->images->first->width(200)->url; } Doesn't work in all scenarios though… what if the field is NOT an array and only has one image? what if the field is NOT an array and empty? what if the field IS an array but only has one image? what if the field IS an array but empty? what if the field IS an array and there are multiple images? (probably the only scenario where the above works). Can someone who's been there before provide a code that covers all and never throws an error, just stays empty if there is no image?
- 
	  KIOSK, One-Page Checkout Module for ProcessWirefroot replied to froot's topic in Module/Plugin Development That happens when a new $_SESSION is started. It stores two empty arrays in that variable, one with key 'kiosk' and one with key 'PayPalSession'. These arrays get filled later. When you refresh it's gone. Not a big problem, will fix it in the next update.
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development I think the issue is, like I mentioned before, that many devs don't want their module to rely on yet another third party module to function (install/uninstall) correctly. What if the module is discontinued some day or outdated? What you could do, just an idea, is make the migrate module serve the same purposes it does already, but instead of offering methods, generate the code that would work with pure PW that developers can put in their module. Also, not sure if that's possible or this or another module offers that already, allow for fields and template export. So what happens a lot to me at least is, I work on a site, create some fields and templates via GUI and when I'm happy I want these fields in another installation or better yet (from now on at least) included in a module. Then I would need to re-overthink what I did via GUI to accomplish the same thing via API. If you could just use RockMigrations, navigate to the field(s), template(s) or even page(s)? in question and click click bing bang boom it shows you the API-code you need for PW to install it in anywhere else.
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development so… public static function getModuleinfo() { return [ 'installs' => 'RockMigrations', ]; } I'm sure this module rocks, pun intended. When will it be a core module?
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development that seems to work just fine, thanks!
- 
	  KIOSK, One-Page Checkout Module for ProcessWirefroot replied to froot's topic in Module/Plugin Development You can create a field stack_prices as a repeater field with three subfields: repeater_product_quantity (integer), repeater_product_stackprice (float) and repeater_product_shipping (float) Add this field to your product-template. Then, on your product page, before you render the add-to-cart button with ___renderBuyButton() you can format these values like so: if ($page->stack_prices != '') : $product->stack_prices = array(); $i = 0; foreach ($page->stack_prices as $sp) : $pricing = array( 'qu' => $sp->repeater_product_quantity, 'sp' => $sp->repeater_product_stackprice, 'sh' => $sp->repeater_product_shipping ); $product->stack_prices[$i] = $pricing; $i++; endforeach; endif; and then send it to the function: echo $kiosk->___renderBuyButton($product); I want to include this field in the module to be created upon installation soon.
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development https://github.com/dtjngl/kiosk/blob/master/Kiosk/Kiosk.module#L237 @teppo @bernhard can you help me find the bug? It won't delete the page in line 237 and 239 if it has children, because it has children, but I delete those children in lines 232–235
- 
	  KIOSK, One-Page Checkout Module for ProcessWirefroot replied to froot's topic in Module/Plugin Development this installation's paypal function is not working currently though, had to re-install it, there's a bug I'm trying to fix.
- 
	  KIOSK, One-Page Checkout Module for ProcessWirefroot replied to froot's topic in Module/Plugin Development Here's a test installation for you to get a look and feel http://kiosk.datajungle.xyz/shop/ I will provide access to the admin soon so you can view the kiosk settings page, kiosk dashboard and some of the page tree.
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development I posted the fruits of my labour and your contributions in the post below, thanks to y'all, looking forward to your feedback!
- 
	  KIOSK, One-Page Checkout Module for ProcessWirefroot replied to froot's topic in Module/Plugin Development Hi @wbmnfktr thanks for your message, I thought "checkout" is a term that speaks for itself. It's meant to be a shopping cart checkout and it doesn't use any third party software except for PayPal (for now). I edited my initial post, which is pretty much the readme.md file on github.
- 
	I'm working on a one-page, vanilla javascript and php (PW API) shopping checkout module that integrates PayPal server side. Here's version 1.0 https://github.com/dtjngl/kiosk Looking forward to your feedback! DISCLAIMER this is a BETA version at best, it's my first "real" module I'm writing for ProcessWire (and first module I'm writing at all) so please don't eat me alive. I'm aware that it needs a lot of work, but at this point, but it's functional. I'm also aware that it is not very customisable at this point (it's mostly customised for one specific use case), but I promise I will work on that. My main objective is to get more seasoned developers' mentoring, feedback, advice, warnings – and and of course, if you want to look into or help develop it further – pull requests. Please point out any potential dangers you see or anything that raises a red flag for you. I'm learning so much from that. Though the module is held in german, you can translate almost all strings that are in the php files via PW's translate functionality. I cannot help with the strings in the javascript yet, but will do so soon (using a json file that lives on the file system probably). I started working on this module because many checkout systems out there are either overkill and too complicated, didn't fulfil my needs or come with a premium fee that is not worth it. Also, austrian law (and other countries' jurisdiction) demand a different flow than what PayPal's Express checkout offers. So this version makes calls to PayPal on the server. WHAT IT CONTAINS - OnePage checkout system with 4 steps: cart, address(es) form, payment method (paypal and deferred), order overview - "minicart" (the cart-summary in the page's header) - buy button (to add items to the cart) - a dashboard (with admin template) for an overview of all placed orders uses server session storage and browser localstorage REQUIRED WireMail SMTP UIKIT (for best behaviour, will be optional soon) vanilla Javascript (no jQuery required) PHP (DUHDOY!) ProcessWire Version (not sure, but works with version 3.0.200) if you want it in english you need a multi-language installation PayPal Business Account (Live or Sandbox to test with) HOW TO INSTALL 1. Put the folder "Kiosk" in your ProcessWire site's modules folder 2. Install the module Kiosk, this will… - create fields for the order template - create a template for the orders placed - create a template for the orders' parent page - create a parent page "Custom Orders" for all orders under /admin/page/ (you can rename the page, not the template) - create a template "kiosk_checkout" for the checkout page - create a page "Checkout" for the checkout, child to "Home" (you can move the page, you can rename the page, not the template) - install module ProcessKiosk along with it - ProcessKiosk create a page under /admin/ (visible in the module upon creation). Here you will see a table with all the orders placed. 3. check the Kiosk module's settings page (navigate via the module's overview page) and enter details to your best knowledge. Some are not "required" but they actually are. 4. Put the below code (in essence) on "kiosk_checkout.php": if ($config->ajax) { $kiosk->handleAJAX($input); return $this->halt(); } else { $kiosk->handleStaticContent($input); echo $kiosk->renderCheckoutSteps(); } 5. put this line on a page that loads everywhere, preferably on init.php: $kiosk = $modules->get('Kiosk') 6. put this line where you want the "minicart" and toggling cart preview (provided the site runs UIKIT) to be, probably in a header that renders on each page: echo $kiosk->renderMiniCart(); 7. put this line just above you closing tag: echo $kiosk->addScripts(); HOW DOES THIS THE ORDERING WORK? 1. Add items to the cart or update quantity when viewing the cart, continue with "weiter". 2. Enter your address, if your billing address differs, uncheck the "gleiche Rechnungsadresse" and enter the billing address, checked or unchecked, both forms will be sent to the server but handled accordingly, continue with "weiter" 3. Select a payment method, continue with "weiter" 4. formdata object (containing cart items, address(es), payment method) will be sent via AJAX to the server and stored in the server session variable 5.1. if payment method is deferred - AJAX response contains the order summary markup that will render in step4 - don't forget to check " ich habe die Datenschutzerklärung sowie die AGB zur Kenntnis genommen und akzeptiere diese." (privacy policy and terms and conditions) - click on "Zahlungspflichtig bestellen" will send another AJAX request to the server thus submitting the order (continue to WHAT HAPPENS WHEN AN ORDER IS PLACED?) 5.2. if it's paypal, a bit more is happening - server sends a cURL request to paypal containing client ID and secret - response will send a token - server sends that token along with the purchase unit (created from our placed order) in another cURL request to paypal - response will send an "approve"-URL - AJAX response contains that URL - user is redirected to paypal to approve the order - user is redirected to the "checkout" page along with a token and PayerID as GET parameters - token (not needed actually) and PayerID are stored in the server session - with the PayerID in the session variable and the "status" of the paypal approved order in the localstorage the checkout process will head on to step 4: order summary - don't forget to check " ich habe die Datenschutzerklärung sowie die AGB zur Kenntnis genommen und akzeptiere diese." (privacy policy and terms and conditions) - clicking on "Zahlungspflichtig bestellen" will send another AJAX request to the server - second AJAX request will send PayPalAccessToken, PayPalPayerId and PayPalRequestId in another cURL to PayPal which will trigger the payment - response will… continue to WHAT HAPPENS WHEN AN ORDER IS PLACED? WHAT HAPPENS WHEN AN ORDER IS PLACED? an order-page with all the order's details (plus order number from the kiosk's number circle) is created under /admin/page/custom_orders/ (you can find it in the Kiosk Dashboard) number circle is iterated email markup is created using the module's default email template, you can add a path to a custom template in the module's settings email is sent to the site master and the user (check the module's settings for email addresses etc.) order in server session is reset to an empty array paypal session in server session is reset to an empty array localstorage of the browser is deleted user is redirected to a custom url (defined in the module's settings) HOW ARE PRICES HANDLED? prices allow for a stack price functionality. This means that prices and shipping depend on the quantity of items purchased. You can enter different prices and shipping costs for different quantities. If a user's amount of a selected item reaches the specified stack price, the item price and the shipping costs change. HOW ARE PRODUCTS ADDED TO THE CART? a product should be a page object to keep things simple. That page needs an "images" array field (that very name). Below you can see what a product would need. These values are added to the button's data attributes. // This is how you make a product… $product = new WireArray(); $product->id = $page->id; $product->title = $page->title; $product->source = $page->parent->name; $product->url = $page->url; $product->images = $page->images; $product->product_width = 150 // for proportional item image calculation in the cart $product->taxrate = 10 // or what ever the tax rate $product->stack_prices = array( array( "qu" => 1, "sp" => 19.99, "sh" => 5 ), array( "qu" => 10, "sp" => 14.99, "sh" => 0 ), ); $product->stack_prices = htmlspecialchars(json_encode($product->stack_prices)); // then render the "add to cart" button $kiosk->renderBuyButton($product); UPDATE version 1.1: installing kiosk.module will also create a repeater field "kiosk_product_stack_prices" (including 3 subfields as described above) that handles the stack_prices array of arrays (as described above) so you can use the GUI. create a field "kiosk_product_tax_rate" create a field "kiosk_product_width " create a field "images" if there is none in your system. create a template "kiosk_product" with all these mentioned fields use this template for your products (or the fields thereon at least and add to your template of choice) and you should be good to go. CAUTION! If you uninstall kiosk.module it will delete all pages with template "kiosk_product", that's because I'm still figuring out how to detach the fields and fieldgroups without deleting the template. Also, if you're coming from version 1.0 and want to upgrade, please uninstall it in 1.0 first and only then get the new repo (v1.1) to install again. Class kiosk now provides the following hookable methods: ___renderBuyButton(Page $product, (string) 'add to cart') pass a product (preferably with template kiosk_product) and it returns a buybutton with the price for 1 item. This method now accepts the button's label (string) as a second argument. Method is hookable. ___getSpecificStackPrice(Page $product, (int) 5) // 5 is just an example pass a product (preferably with template kiosk_product) and an amount, it returns the price for that amount of items. Method is hookable. ___getSinglePrice(Page $product) pass a product (preferably with template kiosk_product) and it returns the price for 1 item. Method is hookable. So, use template "kiosk_product" for your products, edit the product page to add details, and then do echo $kiosk->renderBuyButton($product, (string) 'add to cart'); to render an "add to cart" button.
- 15 replies
- 
	- 14
- 
					
						
					
							  
 
 
- 
	  How to insert scripts and stylesheets from your module?froot replied to hdesigns's topic in Module/Plugin Development if I add bd('site/ready.php'); to my ready.php file and bd('site/init.php'); to my init.php file It seems to load: site/ready module init site/init is the order legit? I fire some of the module's methods on the _main.php and like I said, I use markup regions, I guess that makes all the difference(?) And I need to load some of the module's methods when the page renders because these methods generate the markup… So if I change the module to autoload => true, do the module's ready() and init() functions fire exactly after the site's ready.php and init.php files load accordingly? Anyways, autoloading it doesn't help.
- 
	  How to insert scripts and stylesheets from your module?froot replied to hdesigns's topic in Module/Plugin Development I initialise the module manually. Yes I read this doc and many others.. I guess it gets intialised 3 times here because I call upon the module 3 times with wire('modules')->get('asdf'); instead of doing it just once in a php file that loads on each page, which I will change, some methods need to be called everywhere anyway. The hook fires perfectly fine inside my site/ready.php file and everything works as intended, but not inside the ready() function inside my module it doesn't. // ready.php $wire->addHookAfter('Page::render', $modules->get('asdf'), 'addScripts'); // works // asdf.module ready() { $wire->addHookAfter('Page::render', $this, 'addScripts'); // doesn't work } // asdf.module public function addScripts($event) { $page = $event->object; bd("inside hook"); $additionalScripts = '<!-- :D THIS IS THE SCRIPTS HOOK -->'; $additionalScripts .= '<script type="text/javascript" src="'.wire('urls')->httpSiteModules.'asdf/scripts/script1.js"></script>'; $additionalScripts .= '<script type="text/javascript" src="'.wire('urls')->httpSiteModules.'asdf/scripts/script2.js"></script>'; $additionalScripts .= '<script type="text/javascript" src="'.wire('urls')->httpSiteModules.'asdf/scripts/script3.js"></script>'; $additionalScripts .= '<!-- THIS IS THE SCRIPTS HOOK :D -->'; $event->return = str_replace("</body>", $additionalScripts.'</body>', $event->return); } I'm using markup regions BTW. Also curious about how Tracy Debugger handles scripts, because they are also included at the end of the body tag, don't know when and where that it renders. I'm wondering if that interferes with my hooking, but like I said it works when the hook fires in the actual ready.php file.
- 
	you mean like \stdClass() that's it? It's probably a very basic question so you're probably not missing anything.
- 
	I have to use the php standard class stdClass for my function to work. But that doesn't work in the Processwire namespace. What's the equivalent in Processwire? I think it's the best bet to find an equivalent API instead of going in and out of different namespaces.
- 
	  How to insert scripts and stylesheets from your module?froot replied to hdesigns's topic in Module/Plugin Development thanks @bernhard, I did all that you suggested. #1 – #5 seem to work fine, I can see 'ready' in Tracy and 3 times 'module init' (why 3 times, no idea). But no success at #6, the hook seems not to fire, no 'inside hook' or what ever in Tracy, so the hook doesn't fire properly. I tried putting the hook in the init() and in the ready() function of my module (of course not simultaneously). So any more suggestions? Not sure what to look for in the browser dev tools though, I can just say that the markup doesn't get altered at all. Also, I would actually need to include three scripts in different places of the site, not sure if that's the best practice but some scripts cannot run everywhere as they depend on what's in the DOM and it's just too complicated to bail out in the code when DOM-elements are not present.
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development EDIT: I should of course add the page where I'm actually trying to delete the parent page ? That one actually throws the error(s). It's very weird, otherwise installing/uninstalling works fine - so far… This doesn't work at all BTW. I end up with an empty dashboard page and it has "no process".
- 
	  How to insert scripts and stylesheets from your module?froot replied to hdesigns's topic in Module/Plugin Development there's of course a typo, it should say $additionalScripts in the last line… Anyways, hello everybody. I tried the following (same as above)… public function init() { $this->addHookAfter('Page::render', $this, 'addScripts'); // ... } public function addScripts($event) { $page = $event->object; $additionalScripts = '<script type="text/javascript" src="/site/modules/MyModule/scripts/mymodulescript.js"></script>'; $additionalScripts .= '<script type="text/javascript" src="/site/modules/MyModule/scripts/myotherscript.js"></script>'; $event->return = str_replace("</body>", $additionalScripts.'</body>', $event->return); } Pretty simple, doesn't work though. Even if the path might be wrong (what's the right path to the module's folder anyway?) it should at least include the wrong path where the body tag closes, but nothing happens. Thoughts?
- 
	  some questions… first: checking if field exists doesn't workfroot replied to froot's topic in Module/Plugin Development thanks @teppo Currently this is not an issue, but it seems to often come back when there's an other issue… What still is an acute issue though is the following code bit: $suckers = wire('pages')->find('template=template_custom_orders'); foreach ($suckers as $s) : $s->delete(); endforeach; It first throws an error like Can't delete Page 1234 because it has one or more children But it deletes the children pages, NOT the parent page. When I uninstall it a second time, I get no error and it uninstalls the parent page. That's odd. My guess would be I need to save the parent page in between delete the children and deleting the parent? Seems wrong though…
 
         
                 
                    