Jump to content

kongondo

PW-Moderators
  • Posts

    7,379
  • Joined

  • Last visited

  • Days Won

    139

Posts posted by kongondo

  1. Hi @thibaultvdb,

    Thanks for your interest in Padloper 2. 

    I have moved your question to its own topic. 

    Yes, it should be possible to do this with Padloper 2, although the feature is not available out of the box. There are at least two approaches I can think off. Let me sleep on it. I'll give you a better response tomorrow. 

    Thanks.

    • Thanks 1
  2. Hi @ank,

    Apologies for the late response.

    Below are examples of 'add to cart' buttons without page reload. Ajax is used to submit the request and handle the response from the server. There are two examples: 

    1. jQuery ajax
    2. Vanilla JavaScript ajax

    In both cases, the server (Padloper) returns a JSON response. This is unlike in htmx in which case the server will return markup as the response. Hence, in the examples below, we need to handle the response ourselves. I have given some examples but you can choose to handle the response however you wish. The most important thing is the submission aspect of the code, i.e. what form inputs you send to the server. I'll explain these below before I get to the examples. In future, I will add the examples below to the demos repository. I will also be adding the explanations below to the docs.

    Add to Cart Endpoint

    You need to send a POST request to the address /padloper/add/. Padloper listens to requests sent there using URL Hooks.

    INPUTS

    Required

    Product ID (integer)

    Your request must contain the ID of the product you want to add to the cart. Please note that this applies to both a product without variants or a variant. I.e., in case of a variant, you only need to send its ID. Its ID will be its product ID. 

    The input name must be: product_id

    Optional

    Quantity (integer)

    This tells Padloper how many of the given product/product variant to add to the cart. If this is not specified, it defaults to 1 item.

    The input name must be: padloper_cart_add_product_quantity

    Redirect Page (string | integer)

    This is only applicable for non-ajax requests! This tells Padloper where to redirect the user to after they add an item to the cart. It is useful in cases such as 'add to cart and checkout'. The value can be a string representing the URL to redirect to or a page ID whose URL to redirect to.

    The input name must be: padloper_cart_redirect

    EXAMPLES

    Notes

    1. These examples assume you are using a delayed output template strategy. Otherwise, if using a direct output you just need to echo $content. 
    2. Please also note that form markup can be added to any page. You don't need a special page to add an item to the cart.
    3. Padloper products pages live under the admin hence cannot be accessed directly from the frontend. One way to show a product in the frontend is to access it via a URL Segment, e.g. /products/my-nice-product/ OR /products/1234/ where 1234 is the ID of the product. You can then use $padloper->get("id=1234") OR $padloper->get("name=my-nice-product, template=product").
    4. We are using Tailwind CSS in our examples.
    5. For the jQuery example, you will need to link to jQuery script somewhere in your <head> or <body>.
    6. In this examples, we don't show how to use the values in the JSON in the server response. They are self-explanatory though. If not, let me know.
    7. The JavaScript handlers code was not thoroughly tested. They are intended as a quick illustration.

    jQuery Example

    Template File (PHP)

    Spoiler
    <?php
    
    namespace ProcessWire;
    
    
    // ++++++++++++++
    # FOR DEMO/TESTING jQUERY AJAX 'ADD TO CART', i.e. non-htmx demos
    # @NOTE: YOU NEED TO ADD SOME CHECKS TO YOUR CODE; e.g. ensure the product exists, etc
    // ++++++++++++++
    
    // @NOTE: hardcoded PRODUCT ID for testing only! Get programmatically in real case
    $testProductID = 1895;
    // fetch the product page
    $testProduct = $padloper->get("id={$testProductID}");
    
    // get the first image for this product
    $testProductImage = $testProduct->padloper_images->first();
    // create a thumb for the image
    $testProductThumb = $testProductImage->height(130);
    
    // get the stock info for this product
    $stock = $testProduct->padloper_product_stock;
    // get the price of the product formatted as a currency
    $price = $padloper->getValueFormattedAsCurrencyForShop($stock->price);
    
    // FOR TESTING NON-AJAX ONLY! FOR REDIRECT BACK HERE
    // $testProductName = $sanitizer->pageNameTranslate($testProduct->getUnformatted('title'));
    // $testProductURL = "/products/{$testProductName}/";
    
    ##################
    
    // Primary content is the page's body copy
    $content = $page->body;
    
    // FOR TESTING JQUERY AJAX ADD TO CART
    $content .= "<div>" .
    	"<h3>TEST JQUERY AJAX ADD TO CART</h3>" .
    	"<hr class='my-3'>" .
    
    	"<div id='padloper_add_single_product' class='my-8'>" .
    	"<div class='container mx-auto px-6'>" .
    	"<div>" .
    	"<div>" .
    	"<h2 class='text-gray-900 text-3xl title-font font-medium mb-1'>{$testProduct->title}</h2>" .
    	"<img class='rounded'" .
    	"src='{$testProductThumb->url}' alt='{$testProduct->title}'>" .
    	"<div class='lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0'>" .
    
    	// 					<!-- DESCRIPTION -->
    	"<p class='leading-relaxed'></p>" .
    	$testProduct->padloper_description .
    
    	//					<!-- PRICE -->
    	"<div id='padloper_2_demo_product_add_to_cart_wrapper' class='flex mt-4'>" .
    	// price
    	"<span class='title-font font-medium text-xl text-gray-900'>{$price}</span>" .
    	// *** jQUERY AJAX FORM ***
    	"<form method='post' action='{$config->urls->root}padloper/add/' id='padloper-cart-add-product-other-ajax-jquery' class='padloper-cart-add-product flex ml-auto'>" .
    	// product id hidden input
    	"<input type='hidden' name='product_id' value='{$testProduct->id}'>" .
    	// csrf hidden input
    	$session->CSRF->renderInput() .
    	# ++++++++++++
    	// FOR TESTING NON-AJAX ONLY! FOR REDIRECT BACK HERE
    	// "<input type='hidden' name='padloper_cart_redirect' value='{$testProductURL}'>" .	
    	// "<input type='hidden' name='padloper_cart_redirect' value='{$page->id}'>" .
      	# ++++++++++++
    	// add to cart button
    	"<button class='text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded'>Add to Cart (jQuery)</button>" .
    	"</form>" .
    	"</div>" .
    	"</div>" .
    	"" .
    	"</div>" .
    	"</div>" .
    	// success/error message	
    	// JQUERY
    	"<span id='other-ajax-add-to-cart-success-jquery' class='font-medium text-lg bg-gray-700 text-white'></span>" .
    	"<span id='other-ajax-add-to-cart-error-jquery'class='font-medium text-lg bg-white-700 text-red-300'></span>" .
    	//		<!-- div.container -->
    	"</div>" .
    	//	<!-- div#padloper_add_single_product -->
    	"</div>";

     

    JavaScript

    Spoiler
    /**
     * DOM ready
     *
     */
    document.addEventListener("DOMContentLoaded", function (event) {
    	console.log("TEST/DEMO: OTHER AJAX ADD TO CART DEMO")
    	jqueryAddToCart()
    })
    
    // ------------------
    function jqueryAddToCart() {
    	// jQuery example of how to make add to cart buttons ajaxified
    	$("#padloper-cart-add-product-other-ajax-jquery").submit(function (event) {
    		// console.log(event)
    		event.preventDefault()
    		const $form = $(this)
    		const url = $form.attr("action")
    
    		// Send the data using post
    		const posting = $.post(url, $form.serialize())
    
    		posting.done(function (data) {
    			if (data.errors) {
    				let str = ""
    				$.each(data.errors, function (i, val) {
    					str = str + val
    				})
    				$("#other-ajax-add-to-cart-success-jquery").text(str)
    				$("#other-ajax-add-to-cart-success-jquery").fadeOut(6000)
    			} else {
    				// $("#totalQty").html(data.totalQty)
    				// $("#numberOfTitles").html(data.numberOfTitles)
    				// $("#totalAmount").html(data.totalAmount)
    				$("#other-ajax-add-to-cart-success-jquery").text(
    					"Product successfully added to basket"
    				)
    				// $("#other-ajax-add-to-cart-success").addClass("py-3 px-2")
    				$("#other-ajax-add-to-cart-success-jquery").fadeOut(6000)
    			}
    		})
    	})
    }
    
    

     

    Vanilla JavaScript Example

    Template File (PHP)

    Spoiler
    <?php
    
    namespace ProcessWire;
    
    
    // ++++++++++++++
    # FOR DEMO/TESTING VANILLA JAVASCRIPT AJAX 'ADD TO CART', i.e. non-htmx demos
    # @NOTE: YOU NEED TO ADD SOME CHECKS TO YOUR CODE; e.g. ensure the product exists, etc
    // ++++++++++++++
    
    // @NOTE: hardcoded PRODUCT ID for testing only! Get programmatically in real case
    $testProductID = 1895;
    // fetch the product page
    $testProduct = $padloper->get("id={$testProductID}");
    
    // get the first image for this product
    $testProductImage = $testProduct->padloper_images->first();
    // create a thumb for the image
    $testProductThumb = $testProductImage->height(130);
    
    // get the stock info for this product
    $stock = $testProduct->padloper_product_stock;
    // get the price of the product formatted as a currency
    $price = $padloper->getValueFormattedAsCurrencyForShop($stock->price);
    
    // FOR TESTING NON-AJAX ONLY! FOR REDIRECT BACK HERE
    // $testProductName = $sanitizer->pageNameTranslate($testProduct->getUnformatted('title'));
    // $testProductURL = "/products/{$testProductName}/";
    
    
    ##################
    
    // Primary content is the page's body copy
    $content = $page->body;
    
    // FOR TESTING VANILLA JAVASCRIPT AJAX ADD TO CART
    $content .= "<div>" .
    	"<h3>TEST VANILLA JAVASCRIPT AJAX ADD TO CART</h3>" .
    	"<hr class='my-3'>" .
    
    	"<div id='padloper_add_single_product' class='my-8'>" .
    	"<div class='container mx-auto px-6'>" .
    	"<div>" .
    	"<div>" .
    	"<h2 class='text-gray-900 text-3xl title-font font-medium mb-1'>{$testProduct->title}</h2>" .
    	"<img class='rounded'" .
    	"src='{$testProductThumb->url}' alt='{$testProduct->title}'>" .
    	"<div class='lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0'>" .
    
    	// 					<!-- DESCRIPTION -->
    	"<p class='leading-relaxed'></p>" .
    	$testProduct->padloper_description .
    
    	//					<!-- PRICE -->
    	"<div id='padloper_2_demo_product_add_to_cart_wrapper' class='flex mt-4'>" .
    	// price
    	"<span class='title-font font-medium text-xl text-gray-900'>{$price}</span>" .
    	// *** VANILLA JAVASCRIPT AJAX BUTTON ***
    	"<form method='post' action='{$config->urls->root}padloper/add/' id='padloper-cart-add-product-other-ajax-vanilla' class='padloper-cart-add-product flex ml-auto'>" .
    	// product id hidden input
    	"<input type='hidden' name='product_id' value='{$testProduct->id}'>" .
    	// csrf hidden input
    	$session->CSRF->renderInput() .
    	# ++++++++++++
    	// FOR TESTING NON-AJAX ONLY! FOR REDIRECT BACK HERE
    	// "<input type='hidden' name='padloper_cart_redirect' value='{$testProductURL}'>" .	
    	// "<input type='hidden' name='padloper_cart_redirect' value='{$page->id}'>" .
    	# ++++++++++++
    	// add to cart button
    	"<button id='padloper-cart-add-product-other-ajax-vanilla-button' class='text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded' type='button'>Add to Cart (Vanilla JS)</button>" .
    	"</form>" .
    	"</div>" .
    	"</div>" .
    	"" .
    	"</div>" .
    	"</div>" .
    	// success/error message
    	// VANILLA JS
    	"<span id='other-ajax-add-to-cart-success-vanilla' class='font-medium text-lg bg-gray-700 text-white'></span>" .
    	"<span id='other-ajax-add-to-cart-error-vanilla'class='font-medium text-lg bg-white-700 text-red-300'></span>" .
    	//		<!-- div.container -->
    	"</div>" .
    	//	<!-- div#padloper_add_single_product -->
    	"</div>";

     

    JavaScript

    Spoiler
    /**
     * DOM ready
     *
     */
    document.addEventListener("DOMContentLoaded", function (event) {
    	console.log("TEST/DEMO: OTHER AJAX ADD TO CART DEMO")
    	handleVanillaJavaScriptAddToCart()
    })
    
    // ------------------
    
    
    function handleVanillaJavaScriptAddToCart() {
    	const vanillaJavaScriptAddToCartButtonElement = document.getElementById(
    		"padloper-cart-add-product-other-ajax-vanilla-button"
    	)
    	if (vanillaJavaScriptAddToCartButtonElement) {
    		// add event listener to autocomplete shipping country
    		vanillaJavaScriptAddToCartButtonElement.addEventListener(
    			"click",
    			vanillaJavaScriptAddToCart,
    			false
    		)
    	}
    }
    
    async function vanillaJavaScriptAddToCart() {
    	const vanillaJavaScriptAddToCartFormElement = document.getElementById(
    		"padloper-cart-add-product-other-ajax-vanilla"
    	)
    	// -----
    	if (!vanillaJavaScriptAddToCartFormElement) {
    		return
    	}
    
    	// GOOD TO GO
    	const addToCartURL = vanillaJavaScriptAddToCartFormElement.action
    	const data = new FormData(vanillaJavaScriptAddToCartFormElement)
    
    	try {
    		const response = await fetch(addToCartURL, {
    			method: "POST",
    			// Set the headers
    			headers: {
    				Accept: "application/json",
    				"X-Requested-With": "XMLHttpRequest",
    			},
    			// Set the post data
    			body: data,
    		})
    		if (!response.ok) {
    			throw new Error("Network response was not OK")
    		}
    
    		const json = await response.json()
    		console.log(
    			"TEST/DEMO: OTHER AJAX ADD TO CART DEMO vanillaJavaScriptAddToCart - json",
    			json
    		)
    		const successElement = document.getElementById(
    			"other-ajax-add-to-cart-success-vanilla"
    		)
    
    		successElement.innerHTML = "Product successfully added to basket"
    		toggleFade(successElement)
    	} catch (error) {
    		console.error("There has been a problem with your fetch operation:", error)
    		const errorElement = document.getElementById("other-ajax-add-to-cart-error")
    
    		errorElement.innerHTML =
    			"There was an error: Could not add product to basket"
    		toggleFade(errorElement)
    	}
    }
    
    function toggleFade(element, duration = 600) {
    	element.style.display = ""
    	element.style.opacity = 0
    	let last = +new Date()
    	const tick = function () {
    		element.style.opacity =
    			+element.style.opacity + (new Date() - last) / duration
    		last = +new Date()
    		if (+element.style.opacity < 1) {
    			;(window.requestAnimationFrame && requestAnimationFrame(tick)) ||
    				setTimeout(tick, 16)
    		} else {
    			setTimeout(() => {
    				fadeOut(element)
    			}, 2500)
    		}
    	}
    	tick()
    }
    
    function fadeOut(el) {
    	setInterval(function () {
    		var opacity = el.style.opacity
    		if (opacity > 0) {
    			opacity -= 0.1
    			el.style.opacity = opacity
    		}
    	}, 50)
    }

     

    Server Response

    {
        "productId": 1895,
        "variationId": 0,
        "productTitle": "Printed Ghanain Skirt",
        "quantity": 1,
        "totalQty": 85,
        "numberOfTitles": 5,
        "totalAmount": "\u00a313,425.45"
    }

    Please note that the variationId is a legacy response value that is no longer needed in Padloper. It will be removed in the next release.

    Screenshots

    Please note that in my testing, I combined the code for jQuery and Vanilla JavaScript into one template file.

    Demo Product Page

    jquery_vanilla_js_add_to_cart_ajax_demo.thumb.png.eaacf8bad447d24d752688129c3b8353.png

    Dev Console: Ajax Request

    jquery_vanilla_js_add_to_cart_ajax_demo_ajax_request.thumb.png.71be1f54fe1afb5a43e1697b8d1fb35b.png

    Dev Console: Ajax Response

    Hope this helps. Otherwise, give us a shout.

    Cheers

    jquery_vanilla_js_add_to_cart_ajax_demo_ajax_response.png

  3. Hi @Stefanowitsch,

    I totally agree with your sentiments. The state of Padloper documentation is not good at all. I don't want to make excuses.  Written documentation was at the top of my list but other things came up. I then decided to instead create video documentation. I started on those but again was sidetracked. 

    4 hours ago, Stefanowitsch said:

    After using Padloper 1 for a project I want to look at Version 2 for a new project.

    Great! Happy to help you with this. This doesn't mean I won't be working on the video documentation; I'll still work on that.

     

    4 hours ago, Stefanowitsch said:

    I know that Padloper 2 is entirely re-written and despite the name has nothing to to with the original version, am I right?

    Technically, this is incorrect. Although there are a lot of new features and a new API, some aspects of Padloper 1 remain, e.g. 'padloper templates' to customise markup, e.g. summary of order line items in the basket, etc.

    4 hours ago, Stefanowitsch said:

    So I can't really build upon my experience with the original Padloper 1. 

    Actually, you can. For instance, stuff like 'add to cart', 'checkout form', etc. are near identical.

    4 hours ago, Stefanowitsch said:

    I am a bit confused on how to get started with Padloper 2.

    I am entirely to blame for this. As stated, the docs are not nearly good enough. They are actually still in an interim location. The plan has been to move them to the padloper domain.

    4 hours ago, Stefanowitsch said:

    This Docs go through the installation process but then it kind of stops. 

    True. Again, I am to blame for this state.

    4 hours ago, Stefanowitsch said:

    I would like to have further - basic - information like:

    - How to create Categories and Products in the backend

    I will be covering this in the video docs. It is quite easy to create categories and products. Meanwhile, I can grant you backend access to the demo site to visualise how things work.

    5 hours ago, Stefanowitsch said:

    - How to handle product field data (like custom attributes, variatons, etc.)
    - What fields are required for the product templates (price, amount, etc.) ?

    Zero fields are required 😀. Padloper ships with its own custom fields in many cases. It also utilises a few in-built ProcessWire fields such as title and rich text area (for product descriptions).

    5 hours ago, Stefanowitsch said:

    - Does Padloper create these fields in the installation process for me or do I have to do it manually?

    Padloper creates all fields for you during installation. At installation, you choose the features you want. For instance, if you don't want the feature 'category', Padloper will not install its related template(s) and fields. If you installed the feature 'tags' and later changed your mind, Padloper will remove this cleanly for you. Most features are optional. The core features include order and product.

    5 hours ago, Stefanowitsch said:

    Basically what I love to read would be a "how to set up a simple shop with categories and products step by step".

    This is how I have planned the video docs. I.e., several short videos covering installation, setting up the backend, creating your first product, displaying products in the frontend, checkout, extending Padloper, etc.

     

    5 hours ago, Stefanowitsch said:

    As far as I see there you have to install these demos manually and search through the templates and source code by yourself to see "how things are done". I find this a bit irritating, isn't the Documentation supposed to support this kind of information? 

    I understand your frustration. I agree, the docs need to provide this information. The video docs will do this. Meanwhile, I need to update the demo repos to indicate their incompleteness.

    5 hours ago, Stefanowitsch said:

    It would be great if a database-dump would be included which supports the demo with an already existing page tree with the demo categories and demo product pages to see how things are configured in the backend.

    This is a great suggestion, thanks! Somebody else mentioned this recently. My plan now is to include an option during installation to install a demo shop. This would match the features that you have selected for install. I also plan (not sure about the timeline for this) an integrated JavaScript driven backend demo of how things work in the backend, basically a click-through thing.

    5 hours ago, Stefanowitsch said:

    The Padloper2Starter Readme says that these template files have to be created manually:

    You need to create a products and a categories page under your root page (home). They should use the similarly named templates respectively.
    
    The template files for above pages are:
    
    /templates/products.php -> for all or single product.
    
    /templates/categories.php -> for all or single category.

    Then again I am wondering what fields to I have to add to those templates in the first place to make the Demo work?

    Apologies the docs are not clear. Now that you point this out I see how they can be misleading and how they are incomplete. The above instructions are only for the demos. You don't need those templates for Padloper to work. You don't need to create any fields. For frontend use, the only thing that is required is a checkout page. Using the Padloper API ($padloper),  you can access and display any Padloper items in the frontend wherever you like. You don't need a products page or a categories page, etc. For instance, you could display all your products on the homepage, etc. You could add items to your cart in a modal, or in a dedicated page, or however you want. At the end of the day, things are just ProcessWire pages. Technically, you can access things using ProcessWire API but $padloper saves you a few steps. 

    I hope I have addressed all your queries. The above responses are not a substitute for good, quality documentation. Video documentation and better demo repos are still a high priority for me. Thanks for honestly pointing out the current shortcomings and your frustrations. Whether or not you decide to use Padloper, I genuinely value your opinion 🙂. Thanks!

    • Like 1
    • Thanks 1
  4. Hi @csaggo.com,

    9 hours ago, csaggo.com said:

    as the first we started is still on hold on customer side...

    I was looking forward to a showcase 😄 .

    9 hours ago, csaggo.com said:

    i am in the process of going live with another padloper shop

    Excellent! Congrats!

    9 hours ago, csaggo.com said:

    two things did not work as expected:

    Thanks for reporting. Yes, I noticed these a few weeks ago and fixed the code. The fixes will be available in the next release.

    9 hours ago, csaggo.com said:

    in the __construct method i had to put 
     

    (array $klarnaConfigs = null)

    I have something similar in the code fix, i.e. $configs=[].

    9 hours ago, csaggo.com said:

    the second issue is more important:
    in PadloperUtilites the methods getNonCorePaymentProvidersIDs, getNonCorePaymentProvidersNames, getNonPaymentCustomAddonsIDs, getNonPaymentCustomAddonsNames will not work if i am not logged in as a superuser (so being able to access all pages). I had to add check_access=0 to the processwire-selectors there.

    True. All already have the fix per your description.

    Thanks!

  5. I see. I'll have a think about how devs can pass configs to the Stripe payment element. I think you should also confirm with Stripe/authorities that removing those fields will not go against the regulations for your country (including your customers' countries).

    • Like 1
  6. Hi @Spinbox,

    5 hours ago, Spinbox said:

    I've made a change to the js file of the stripe payment module, removing the name input from payment methods.

    This seems to be something injected by Stripe based on your settings in your Stripe dashboard. I don't see name inputs in my tests. Below is a screenshot of my Stripe payment fields:

    padloper_stripe_fields.png.32f7a966d75b81cc8c43d028c4bb9e7f.png

    Could you check your dashboard settings please and let me know? Thanks.

     

  7. Hi @nabo,

    Many thanks for the purchase!

    1 minute ago, nabo said:

    since I switched to php 8.
    Now I've got 4 deprecated messages and the backend doesn't work anymore.

    I'll work on these; the fixes seem straightforward enough. I'll send you the updated files for testing and look to make an official release for later in the year. I hope this is OK. Thanks!

    • Like 1
  8. Hi @alexm,

    21 hours ago, alexm said:

    if this is used to retrieve them?

    Exactly. An example:

    <?php
    
    namespace ProcessWire;
    
    
    public function setAddonPage(Page $page, string $addonSettingsFieldName) {
      // here we assign these variables to class properties for convenience
      // you don't have to do that
      // you can use $page directly to get your settings using 'addonSettingsFieldName' 
      $this->addonPage = $page;
      $this->addonSettingsFieldName = $addonSettingsFieldName;
    
      // --------
      // EXAMPLE
      $addonSettingsJSON = $page->get($addonSettingsFieldName);
      bd($addonSettingsJSON, __METHOD__ . ': $addonSettingsJSON at line #' . __LINE__);
      if(!empty($addonSettingsJSON)){
        $addonSettingsArray = json_decode($addonSettingsJSON,true);
        // do something with $addonSettingsArray
      }
    }

    I thought I had a hello world addon example in the demo projects. Looks like I don't. I'll add that to my TODO.

     

    • Like 1
  9. 7 hours ago, alexm said:

    If I do a bar dump on $sent = $mail->send(); I get 1 as the response. I don't know whether this would be the expected response

    1 means that $mail sent 1 message. So, we know that that succeeded. Hmm. I am at a loss about this one. Given that the hook is called an an email is sent, I have no reason to suspect that the hook is perhaps being called late.

    1. Do you know if the customer is getting the email being sent by Padloper for this same order?
    2. Secondly, just for testing could you please test with Hooking before?
    3. Are you able to please test the exact same Hook function but by hooking to another method, e.g. ___saveOrder()?

    Thanks.

    • Like 1
  10. 5 hours ago, alexm said:

    say I want to make, for the sake of argument, a discount code addon - what would I set the returned value of getType() to?

    Hey @alexm, the value of that would have to be 'custom'. All non-payment addons must be of type 'custom'.

    4 hours ago, alexm said:

    Got it! Needs to be public property

    Yes. Sorry about that. I need to state that in the docs. Does this mean your question above about 'getType()' is now sorted? Thanks.

    • Like 1
  11. Morning @alexm,

    Apologies for the confusing docs (and perhaps naming issues). All non-payment addons must return 'custom' for getType(). Payment addons, even custom ones, are not defined as 'custom' addons. They are defined as payment addons and must return 'payment' for getType().

    So, the idea of 'custom' does not mean 'third-party' or 'non-core'. Instead, it means the addon does something that is not necessarily a feature of Padloper, i.e. it does something custom. Since 'payment' is something that is a feature of Padloper, even third-party payment modules are not considered 'custom' since their function/role is to do something that is part of the core function of Padloper, i.e. payments.

    Hope this makes sense. Will revise docs.

    • Like 1
  12. 54 minutes ago, alexm said:

    I think there might be some confusion, unless I'm having a bit of a moment.

    @alexm. Sorry, my bad! I get you now. I'll add this to the settings together with your other idea about a 'from email address'. I'll make a variable, $storeDetails or something like that available to invoice-content-html.php. This will give you access to the bank details saved in the store config. Do you need more than these three pieces of info?

    Quote

    Bank Name, Sort Code and Account Number

    Cheers.

    • Thanks 1
  13. 9 hours ago, Spinbox said:

    I got it working like I wanted. Thank you for your detailed reply. I hope I sanitized everything correctly.

    @Spinbox. Glad you got it sorted! Things look sanitized correctly.

    9 hours ago, Spinbox said:

    edit: I'm not sure how to validate a password, found some topics about checking isValidPassword($pass) but not sure how to implement it here

    Did you see this topic as well?

    The docs state that InputfieldPassword::isValidPassword() (https://processwire.com/api/ref/inputfield-password/is-valid-password/:

    Quote

    Return whether or not the given password is valid according to configured requirements.

    This means that it will use the password requirements set in the backend for ProcessWire users. If that suits your needs, then you could use the method as described in the post I have linked to above. If not, i.e. if you have a different set of requirements, you might have to roll out your own validation. An example is shown in the post I have linked to above. I think you should be fine with matching the requirements sent in the backend (i.e., use InputfieldPassword::isValidPassword() as is). You would need to handle cases where the password is found to be invalid (per your requirements).

    Hope this helps. 

    • Like 1
×
×
  • Create New...