Advanced Layout (Expert: Custom Code with action…)

This functionality is designed for proficient and advanced users with a strong command of PHP, Javascript, and HTML programming. If the provided guide doesn’t assist you in implementing custom actions, this feature may not be suitable for your expertise level.
Given that this feature caters to expert users, I’m unable to offer complimentary support for it.

Donation Platform for WooCommerce was developed to be easy to use, at the same time there should be no limits for advanced users. When editing a product, you can enable custom code for the sections of the donation selection form:

After you have saved, the action will now be carried out instead of the standard layout options. Now add the action in the functions.php file of your theme. Tip: You can of course also use the free Code Snippets plugin instead.

 * A custom section
 * use the action given on the product edit page
add_action( 'wcdp_custom_html_pa_donation-frequency_12345', function(){
	echo 'your custom html code';
} );

When you inspect the donation form in the frontend you can see that the normal selection html is still delivered, but without it being rendered to the user. You have to ensure that your custom code copies all inputs to these hidden fields, otherwise it will not add the correct product to the cart.

Example 1

Your custom html code could look like this:

<!-- Display a checkbox "make it monthly" -->
<input type="checkbox" id="recurrent" name="recurrent" value="1">
<label for="recurrent">make it monthly</label>

<!-- make sure that the value of the checkbox is recognized correctly -->
(function($) {
	$(window).bind("load", function() {

	$("#recurrent").on("change", function(){

	function changeRecurrent(){
		if ($("#recurrent").prop("checked")) {
		} else {


Custom code is not recommended if you do not understand how variable products work.

Example 2

This is the code for the following example:

add_action('wcdp_custom_html_donation-frequency_4301', function() {
	echo '
<!-- Two input fields -->
<label class="card">
<!-- Use class wcdp_options so WCDP observes changes to this input. It also copies the attributes from the button layout -->
	<input class="card__input wcdp_options" type="radio" name="donation-frequency" value="monthly" id="wcdp_value_monthly" wcdp-name="donation-frequency">
	<div class="card__body">
		<div class="card__body-header">
			<p><strong>Yes, I want to multiply my impact and donate monthly!</strong></p>
			<p style="font-weight:100;">As a thank you, we will send you a free gift.</p>
		<div class="card__body-cover">
			<img class="card__body-cover-image" src="">
			<span class="card__body-cover-checkbox">
			  <svg class="card__body-cover-checkbox--svg" viewBox="0 0 12 10">
				<polyline points="1.5 6 4.5 9 10.5 1"></polyline>
<div style="height:1em;"></div>
<label class="card">
	<input class="card__input wcdp_options" type="radio" name="donation-frequency" value="one-time" id="wcdp_value_one-time" wcdp-name="donation-frequency" checked="checked">
	<div class="card__body">
		<div class="card__body-header">
			<p>I don\'t want a gift.</p>
			<p style="font-weight:100;">Only donate once.</p>
		<span class="card__body-cover-checkbox">
		  <svg class="card__body-cover-checkbox--svg" viewBox="0 0 12 10">
			<polyline points="1.5 6 4.5 9 10.5 1"></polyline>

.card {
	--background: #fff;
	--background-checkbox: #0c4a0d;
	--background-image: #fff, rgba(0, 107, 175, 0.2);
	--text-color: #666;
	--text-headline: #000;
	--card-shadow: #0c4a0d;
	--card-radius: 5px;
	--blend-mode: overlay;
	--transition: 0.15s;
	user-select: none;

.card__body {
	display: grid;
	grid-template-columns: 60% 40%;
	align-items: center;
	background: var(--background);
	border-radius: var(--card-radius);
	overflow: hidden;
	position: relative;
	cursor: pointer;
	box-shadow: var(--shadow, 0 4px 4px 0 white);
	transition: transform var(--transition), box-shadow var(--transition);
	xtransform: scale(var(--scale, 1)) translateZ(0);
	margin: 0 4px 0 4px;
	opacity: 0.5;
	transition: opacity 0.15s linear 0s;
.card__body:hover {
	opacity: 1;
	transition: opacity 0.15s linear 0s;
.card__body-cover {
width: 100%;
.card__input {
	position: absolute;
	opacity: 0;
	outline: none;
	border: none;
	background: none;
	padding: 0;
	margin: 0;
	-webkit-appearance: none;
.card__input:checked ~ .card__body {
	--shadow: 0 0 0 3px var(--card-shadow);
	opacity: 1;

.card__input:checked ~ .card__body .card__body-cover-checkbox {
	--check-bg: var(--background-checkbox);
	--check-border: #fff;
	--check-scale: 1;
	--check-opacity: 1;

.card__input:checked ~ .card__body .card__body-cover-checkbox--svg {
	--stroke-color: #fff;
	--stroke-dashoffset: 0;

.card__input:checked ~ .card__body .card__body-cover:after {
	--opacity-bg: 0;

.card__input:checked ~ .card__body .card__body-cover-image {
	--filter-bg: grayscale(0);

.card__body:active {
	--scale: 0.96;

.card__body-cover:after {
	content: "";
	position: absolute;
	left: 0;
	top: 0;
	width: var(--c-width);
	height: var(--c-height);
	border-radius: var(--c-border);
	background: linear-gradient(to bottom right, var(--background-image));
	mix-blend-mode: var(--blend-mode);
	opacity: var(--opacity-bg, 1);
	transition: opacity var(--transition) linear;

.card__body-cover-image {
	height: 100%;
	object-fit: cover;
	filter: var(--filter-bg, grayscale(1));

.card__body-cover-checkbox {
	background: var(--check-bg, var(--background-checkbox));
	border: 2px solid var(--check-border, #fff);
	position: absolute;
	right: 10px;
	top: 10px;
	z-index: 1;
	width: 28px;
	height: 28px;
	border-radius: 50%;
	opacity: var(--check-opacity, 0);
	transition: transform var(--transition), opacity calc(var(--transition) * 1.2) linear, -webkit-transform var(--transition) ease;
	xtransform: scale(var(--check-scale, 0));

.card__body-cover-checkbox--svg {
	width: 13px;
	height: 11px;
	display: inline-block;
	vertical-align: top;
	fill: none;
	margin: 7px 0 0 5px;
	stroke: var(--stroke-color, #fff);
	stroke-width: 2;
	stroke-linecap: round;
	stroke-linejoin: round;
	stroke-dasharray: 16px;
	stroke-dashoffset: var(--stroke-dashoffset, 16px);
	transition: stroke-dashoffset 0.4s ease var(--transition);

.card__body-header {
	padding: 0 10px;
jQuery( function( $ ) {
//select default value
    $(document).ready(function() {