Useful JS Snippets
Below are some useful JS snippets that you can add to your WordPress theme to customize ShopWP
Add a custom input above the buy button to pass to the cart​
This code does two things. It adds a custom "Special instructions" input above any product buy button. If a user adds a value to this input, the value will then get passed to the line item and eventually the Shopify order.
wp.hooks.addFilter(
	'cart.lineItemAttributes',
	'shopwp',
	function (defaultAttributes, variant, quantity, buyButtonState, buttonRef) {
		var $parentWrapper = jQuery(buttonRef).closest('.swp-item')
		var $inputElement = $parentWrapper.find(
			'.special-instructions-wrapper input'
		)
		var inputVal = $inputElement.val()
		if (!$inputElement.length) {
			return defaultAttributes
		}
		if (!inputVal) {
			return defaultAttributes
		}
		return [
			{
				key: 'Special instructions',
				value: inputVal,
			},
		]
	}
)
wp.hooks.addFilter(
	'before.productBuyButton',
	'shopwp',
	function (defaultValue, productState) {
		return `
	<style>
		.special-instructions-wrapper {
			display: flex;
			flex-direction: column;
			margin-bottom: 20px;
		}
		.special-instructions-wrapper label {
			font-weight: bold;
		}
	</style>
	<div class="special-instructions-wrapper">
		<label for="instructions">Enter special instructions:</label>
		<input type="text" id="instructions" name="instructions" placeholder="Your instructions go here" />
	</div>
	`
	}
)
Add Rich Text metafields below the buy button​
This code allows for transforming the Rich Text metafield from a complex nested object to a string of HTML to return.
function objectToHTML(obj) {
	// Helper function to process children
	function processChildren(children) {
		return children.map(child => objectToHTML(child)).join('')
	}
	// Base case for text nodes
	if (obj.type === 'text') {
		let text = obj.value
		if (obj.bold) text = `<b>${text}</b>`
		if (obj.italic) text = `<i>${text}</i>`
		return text
	}
	// Handling different types of elements
	switch (obj.type) {
		case 'root':
			return processChildren(obj.children)
		case 'paragraph':
			return `<p>${processChildren(obj.children)}</p>`
		case 'list-item':
			return `<li>${processChildren(obj.children)}</li>`
		case 'list':
			let listType = obj.listType === 'ordered' ? 'ol' : 'ul'
			return `<${listType}>${processChildren(obj.children)}</${listType}>`
		case 'link':
			return `<a href="${obj.url}">${processChildren(obj.children)}</a>`
		case 'heading':
			return `<h${obj.level}>${processChildren(obj.children)}</h${obj.level}>`
		default:
			// If there's an unknown type, just return the children wrapped in a div for safety
			return `<div>${processChildren(obj.children)}</div>`
	}
}
wp.hooks.addFilter(
	'after.productBuyButton',
	'shopwp',
	function (defaultValue, productState) {
		var metafields = productState.payload.metafields.filter(Boolean)
		if (metafields.length) {
			var finalHTML = '<div class="swp-metafields">'
			metafields.forEach(metafield => {
				var metafieldValue = JSON.parse(metafield.value)
				finalHTML += objectToHTML(metafieldValue)
			})
			return finalHTML + '</div>'
		} else {
			return null
		}
	}
)