#DailyBloggingChallenge (322/365)
The nice thing about #hugo is how quickly one can get a site up and running.
The tricky part of it is understanding its directory architecture. This can become more difficult if using a user predefined theme, especially if one wants to one's custom spin on nonexistent parameters.
#DailyBloggingChallenge (323/365)
One will learn that one will need to copy (usually) the whole file from the themes directory and mirror its directory structure onto the root level.
This can be quite a nuisance if one wants to change just one #CSS value.
#DailyBloggingChallenge (324/365)
Learning about the directory architecture opened the gates of writing custom partials.
I previous knew of their existence depending on the specific theme and usually could avoid them by injecting custom #HTML.
Now that I have been hired to work on a professional site, especially after propagating why to use #hugo over #Wordpress, I shall use the framework to its standards and fullest capabilities.
#DailyBloggingChallenge (327/365)
To inject custom #HTML in #hugo, one will either need to activate it in the config
```
[markup.goldmark.renderer]
unsafe = true
```
or pipe the string with `safeHTML`.
#DailyBloggingChallenge (328/365)
The initial partial that is created is a button for #paypal.
This is done by saving a `paypal` param in the meta data of the article and then injected as an anchor tag onto the button.
The styling of the button is saved in a custom header partial that the theme provides.
#DailyBloggingChallenge (329/365)
This approach sounds quite good on paper, but #paypal carts don't work so simplistically.
Although this might sound like a headache initially, in the long run it is quite beneficial.
The paypal cart or form has a couple values which are important.
The main one is the form id. This exists in either case of purchasing an item from a single button or from a dropdown.
In the case of a dropdown selection, then the keys and values of the table cells are important.
#DailyBloggingChallenge (330/365)
Now that these factors are known, one gets start building the params' structure. The easiest is to have a param for the form id and an array of items for the store catalogue.
Each item of the array has a key, a value, and a image.
Further one can setup special params for the other table variables, though from brief comparison over three separate forms, they seem to stay constant.
#DailyBloggingChallenge (338/365)
The #HTML code from #PayPal looks like the image with these variables:
- `<PAYPAL_TOKEN>` is the main PayPal hook, so it knows how to update the store relative to all further actions taken within the form
- `<PAYPAL_INIT_REFERENCE>` usually as `on0`
- `<PAYPAL_INIT_VALUE>` is usually equivalent to `<PAYPAL_ITEM_1_VALUE>`
- `<PAYPAL_INIT_NAME>` is usually equivalent to `<PAYPAL_ITEM_1_NAME>`
- `<PAYPAL_ITEM_1_NAME>` is usually equal to `<PAYPAL_ITEM_1_VALUE>`
- `<PAYPAL_ITEM_2_NAME>` is usually equal to `<PAYPAL_ITEM_2_VALUE>`
#DailyBloggingChallenge (339/365)
Through the abstraction of these variables and using the power of an array in the meta of #Hugo as #toml, one can create an item like in the image.
The array in this example is called `paypalItems` and each element has the properties: `name, value, image`. Further properties of the meta are `paypal` as the `<PAYPAL_TOKEN>`, `price` should align with the price within the #paypal cart, `paypalHeadName` as `<PAYPAL_INIT_REFERENCE>`
paypalHeadValue as `<PAYPAL_INIT_VALUE>`.
Of course one could optimize the code somewhat by removing the variables that have `INIT_(VALUE|NAME)` within them and replacing them by the first item `1_(VALUE|NAME)`. And replacing `<PAYPAL_INIT_REFERENCE>` with `on0`.
#DailyBloggingChallenge (340/365)
Now we will create a partial called `paypal-button.html` within the `layouts/partials/` directory. We want to call this partial like
`{{ partial "paypal-button" (dict "paypal" .Params.paypal "items" .Params.paypalItems "headName" .Params.paypalHeadName "headValue" .Params.paypalHeadValue) }}`
within a list template (either the default or another partial).
#DailyBloggingChallenge (341/365)
The question now is how to build the partial. Since #Hugo is a static site generator that focuses on using static elements like raw #HTML and #CSS, one quickly realizes the options to continue further are not many.
One could try to use the CSS `option:checked` property and other pseudo classes within the `<option>` HTML tag to turn on and off the various choices within the array. Though this becomes quite difficult to reference items outside of the `<option>` tag and can make the whole thing an UX nightmare.
#DailyBloggingChallenge (342/365)
First we want to resolve the UX nightmare issue by designing the UI usable.
Let's go with this arrangement of items:
- title of item
- image of item
- drop-down to choose the item
This means we want to create some kind of callback that updates the prior two components that are dependent on the selection within the drop-down. Thus, we will need to extend #Hugo with #JavaScript while using #golang.
#DailyBloggingChallenge (343/365)
Time to make an overview of what we have so far:
(image Initial)
Since we are already using the callback approach, it would be better to move out everything that is not viable to the #paypal form. Thus making the overview more like
(image Reformed)
#DailyBloggingChallenge (344/365)
Let's say we would implement this pseudo code for the subdirectory `content/post/store`. It would work fine for one product in the subdirectory `store`.
Now let's add a second product that also has the same form (339) with different values.
If one would change either drop-down, both would update. The reason is that the #JavaScript callback is only checking for the #CSS class change and not for an unique class.
References
#DailyBloggingChallenge (348/365)
In 342 the first mention of using a callback function is used without any concrete description of how it shall be built. From the last image one needs to change the partial reference to be saved as a variable which is then piped with `safeHTML`, so
`{{ $itemsOutput := partial "paypal-button" (dict "paypal" .Params.paypal "items" .Params.paypalItems "headName" .Params.paypalHeadName "headValue" .Params.paypalHeadValue "uniqueID" $uniqueID) }}`
and the rendering is done via
`{{ $itemsOutput | safeHTML }}`
#DailyBloggingChallenge (350/365)
Now wrap the #HTML code (338) with a `<div>` and a #CSS class that extends the `uniqueID` (345) in its name. The pseudo code looks like the image.
- 338: https://qoto.org/@barefootstache/112786449265511946
- 345: https://qoto.org/@barefootstache/112786991862960301
#DailyBloggingChallenge (351/365)
Now that the #PseudoCode exists, it shall be converted into #Hugo syntax as described in 349. As in the image, some #GoLang functions are used like `printf` and other Hugo functions to loop over the variables that are saved as an array type.
#DailyBloggingChallenge (352/365)
This code will generate dynamically based off of the length of the `paypalItem` or `.items` variable and use the first element of it as the default value (line 9).
Next one will extend the code with more CSS classes to ease the referencing of the JavaScript actions.
#DailyBloggingChallenge (353/365)
Looking at the #JavaScript code in the image that will be parsed over #GoLang using the `printf` function.
First one creates a `change` event listener function that is bound to the id of `item-select-$uniqueID`. The `<select>`-tag shall be added the `id` attribute in line 13 (351).
Additionally a custom attribute `data-image` shall be created and placed on the `<option>`-tag in line 15 (351). This holds the path to the image value within the `paypalItems` element.
Outside of the partial the #CSS classes `selected-value` and `selected-image` need to be defined. They present the respective values from `paypalItems` element.
In the initial case, lines 10-11 will be called that take the value from the first element in the `paypalItems` array. Defined from `{{ $selectedValue := index .items 0 }}` which shall be prepended before the JavaScript code.
#DailyBloggingChallenge (354/365)
The whole code of the partial looks like in the image.
A lot of this code can be squashed to save space for the cost of readability.
#DailyBloggingChallenge (355/365)
Now that the partial is complete, look back at its parent. Combining the code from 345 and 348 one gets this image.
The problem of this code so far is that it doesn't check if the `$itemsOutput` exists. Further there are no checks that the array `.Params.paypalItems` has any items and there is no default case.
- 345: https://qoto.org/@barefootstache/112786991862960301
- 348: https://qoto.org/@barefootstache/112915551078887830
#DailyBloggingChallenge (356/365)
Now one shall add the missing checks and default cases. Further one shall add the CSS classes mentioned in 353.
The result is seen in the image.
#DailyBloggingChallenge (357/365)
This concludes the explanation behind the process of creating a #Paypal partial for #Hugo using #GoLang tricks combined with #HTML, #CSS, and #JavaScript
The #TLDR can be read at https://bf5.eu/post/guide/hugo-how-to-create-paypal-partial/
#DailyBloggingChallenge (349/365)
Further within the partial, since `safeHTML` will be used one can parse string using #HTML and #JavaScript syntax within #GoLang. As an example
`{{ $output := "" }}`
`{{ $output = print $output "<span>Example</span>" }}`
`{{ return $output }}`
This creates a `<span>`-tag with the text `Example` after `safeHTML` pipe is applied.