Rental Widget - Advanced Customization

Perform custom actions when a customer interacts with the Rental Widget

Because of the design of Product Rentals Pro's Rental Widget, the options are almost endless with regard to how much you can customize it with custom development.

Event Triggers

Product Rentals Pro allows a developer to hook in to events triggered by the PRP Rental Widget, so that custom behaviour can be implemented.

At the moment, the only event emitted from the widget is when an item is added to Cart, but more will be introduced soon, to support even more advanced custom behaviours.

Why would you want to do this? Well, a common example is that you may want to open a Cart Drawer (or Quick-Cart) when an item is added to Cart from the PRP Rental Widget - rather than the default behaviour of visiting the full Cart page.

This can't just be a setting in Product Rentals Pro, because every theme works differently, and can also have various custom code and logic. Some themes may not even have a Cart Drawer. Hence, the default behaviour of the Rental Widget is to visit the Cart page, as we know that exists on every Shopify store and will work reliably.

prp::cart:added

Fired when an item is added to Cart from the Rental Widget

Data provided with the event

Property
Description

detail.cart

The response from the Cart JSON API after adding the item(s) to Cart. May be more than 1 item added if the Insurance add-on in activated.

detail.whenPrevented.redirect

Defaults to false If you preventDefault() then the Rental Widget won't redirect the customer to the Cart page, however you can override this by setting this value to true.

detail.whenPrevented.dontReset

Defaults to false If you preventDefault() then the Rental Widget will return the Add to Cart button state to disabled and with "Select dates first..." as the button text. You can override this by setting this value to true, in which case the button would remain in disabled state with text "Adding..."

Code Example

Below is a code example for changing the behaviour when a customer adds an item to their Cart using the Rental Widget.

// This event fires whenever an item is added to cart via the Rental Widget
document.addEventListener('prp::cart:added', (event) => {

        // Reset the Rental Widget
        // This is the default when using event.preventDefault() anyway,
        // but showing here for the example
        event.detail.whenPrevented.dontReset = false;
        
        // Don't redirect to the full Cart page
        // This is the default when using event.preventDefault() anyway,
        // but showing here for the example
        event.detail.whenPrevented.redirect = false;

        // This stops the navigation to the full cart page
        event.preventDefault(); 

        // Code for any action you want to take goes below
        // The next 2 lines are not functions that would work your store
        // you would need to use the equivalent functions your theme/store uses
        // to trigger a quick cart refresh and open the cart drawer
        refreshQuickCart();
        openCartDrawer();
        
});

prp::variant:unavailable

Fired when an unavailable variant is selected by the customer. 'Unavailable' can mean:

  • The Variant set as having 0 units within Product Rentals Pro

  • A Variant doesn't exist in Shopify, for the combination of options selected.

  • A Variant has Inventory Tracking on in Shopify, but with an inventory count of 0 or negative, without "Continue selling when out of stock" is on (though we recommend against using Inventory Tracking for rental products)

You can use this to display a custom message, or to automatically switch the options selected, like in the example below.

Code Example

Below is a code example for switching the 'Condition' option, if a change in the 'Size' option means that there is no available Variant for the previously selection Condition option.

document.addEventListener('prp::variant:unavailable', (event) => {
  const radioButtons = document.querySelectorAll(
    'input[type="radio"][name="Condition"]'
  );
  const checkedRadio = Array.from(radioButtons).find(radio => radio.checked);
  if (checkedRadio && checkedRadio.classList.contains('disabled')) {
    const firstNonDisabled = Array.from(radioButtons).find(
      radio => !radio.classList.contains('disabled')
    );
    if (firstNonDisabled) {
      firstNonDisabled.click();
    }
  }
});

The code could be added directly to your theme, either in theme.liquid or a relevant product page liquid file. Alternatively you could add it via your Theme Customizer by going to your Product page template that has the PRP Rental Widget, and adding a 'Custom Liquid' block underneath it. In the Custom Liquid block, you can enter Javascript code, as long as you put it between a script tag (<script> at the beginning and </script> at the end).

Other Custom Development

The PRP Rental Widget loads directly on your website (unlike some other rental apps) so your website has the ability to manipulate any part of it with code and/or CSS.

With custom code, you can do things like include extra content into an area of the Rental Widget, show/hide certain parts of the Rental Widget when different selections are made by the customer, or include custom form fields.

Code Example - Custom Field for Pickup Time

Whilst Custom Form Fields are planned as a future feature of Product Rentals Pro, you can get most of the way there now by adding some custom code to your website.

Below is an example of adding a "Pickup Time" field to the Rental Widget. When adding to cart, the Pickup Time selection becomes a line item property of the product in the cart and will then display on the Order in Shopify after it's placed by the customer.

The code below will achieve this. In this example, the field is only visible/active when a customer selects a Delivery Method named "Pickup". It injects CSS as part of a new <style> tag, but this could also easily be included in a CSS file or in the custom CSS field of the PRP Rental Widget settings accessible from your theme editor.

// Inject the CSS dynamically into the page
const style = document.createElement('style');
style.textContent = `
  .rw-custom-fields {
    display: none; /* Hide by default */
  }

  /* Show when the .rw-date-selected class is present and .rw-show is applied */
  .rw-date-selected .rw-custom-fields.rw-show {
    display: block;
  }
`;

// Append the CSS to the document head
document.head.appendChild(style);

const container = document.querySelector('.rw-app-fields-container'); // Replace with the actual selector

if (container) {
	const wrapperDiv = document.createElement('div'); // Create a div to wrap the elements
	wrapperDiv.className = "rw-recap-date-group rw-custom-fields"; // rw-recap-date-group only there to match Date label styling
	wrapperDiv.style.marginBottom = "15px";
	wrapperDiv.style.marginTop = "-25px";

	// Set up the label
	const labelSpan = document.createElement('span');
	labelSpan.textContent = "Pickup Time";

	// Set up the Select box
	const select = document.createElement('select');
	select.className = 'rw-extra-input'; // Required to prevent the calendar selection from resetting on change
	select.name = "properties[Pickup time]";
	select.required = true;
	select.style.display = 'block';
	select.style.padding = '10px';
	select.style.appearance = 'auto';
	select.style.width = '100%';

	const option1 = document.createElement('option');
	option1.value = "9-10am";
	option1.textContent = "9-10am";

	const option2 = document.createElement('option');
	option2.value = "4-5pm";
	option2.textContent = "4-5pm";

	select.appendChild(option1);
	select.appendChild(option2);

	// Add label/select to containers
	wrapperDiv.appendChild(labelSpan);  // Append label span to the div
	wrapperDiv.appendChild(select);     // Append select box to the div
	container.appendChild(wrapperDiv);   // Append the div to the container
}

const deliveryMethods = document.querySelectorAll('input[name="properties[Delivery Method]"]');

// Function to toggle the visibility based on Delivery Method
function togglePickupTime() {
	const selectedMethod = document.querySelector('input[name="properties[Delivery Method]"]:checked');
	const wrapperDiv = document.querySelector('.rw-custom-fields');

	if (selectedMethod && selectedMethod.value === "Pickup") { // Match merchant's naming
		wrapperDiv.classList.add('rw-show'); // Show the element by adding the class
	} else {
		wrapperDiv.classList.remove('rw-show'); // Hide the element by removing the class
	}
}

// Run once on page load if deliveryMethods exist
if (deliveryMethods) {
	togglePickupTime();

	// Listen for changes in the Delivery Method radio buttons
	deliveryMethods.forEach(method => {
		method.addEventListener('change', togglePickupTime);
	});
}

Code Example: Add a simple Terms & Conditions checkbox before the Rent Now button

The code below will add a simple checkbox that must be ticked before the PRP Rental Widget will allow a rental item to be added to cart. This can be added into a Custom Liquid block, placed into your product page template, right after the PRP Rental Widget.

<script>
  const container = document.querySelector('.rw-app-fields-container');
  if (container) {
    const wrapperDiv = document.createElement('div'); // Create a div to wrap the elements
    wrapperDiv.className = "rw-recap-date-group rw-custom-fields"; // Styling to match Date label styling
    wrapperDiv.style.marginBottom = "15px";
    wrapperDiv.style.marginTop = "-25px";

    // Set up the checkbox input
    const checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.className = 'rw-extra-input'; // Important so that dates don't reset when checkbox is clicked
    checkbox.id = 'rental-terms';
    checkbox.name = 'properties[Terms accepted]';
    checkbox.required = true; // Make it required
    checkbox.value = 'Yes';

    // Set up the label
    const label = document.createElement('label');
    label.htmlFor = 'rental-terms';
    label.innerHTML = `I accept the rental <a href="/terms" target="_blank">terms & conditions</a>`; // Update href to your terms page URL

    // Add checkbox and label to the container
    wrapperDiv.appendChild(checkbox);
    wrapperDiv.appendChild(label);
    container.appendChild(wrapperDiv);
}
</script>

Code Example - Add extra information about 'Buy Now' items

Some PRP customers use the Exclusions feature within Product Rentals Pro to offer customers of purchasing rather than renting an item, all from the one product page.

In this example, we're going to add in some extra information about the Buy Now option above the Add To Cart button, to help customers understand how it works. The information will only appear once the 'Buy Now' option is selected, and will hide if the customer goes back to selecting one of the rental durations (e.g. 4 Days or 8 Days).

This can be achieved with the following code. Please note this is set up for specific naming of this example site. You'll need to adjust it to work on your site with your specific configuration and naming of fields. It is recommended this is done by a web developer. Like the previous Code Example, it injects CSS as part of a new <style> tag, but this could also easily be included in a CSS file or in the custom CSS field of the PRP Rental Widget settings accessible from your theme editor.

// Inject the CSS dynamically into the page
const prpCustomStyle = document.createElement('style');
prpCustomStyle.textContent = `
  .rw-custom-fields {
    display: block; /* Hide by default */
  }

  /* Show when the .rw-date-selected class is present and .rw-show is applied */
  .rw-date-selected .rw-custom-fields.rw-show {
    display: block;
  }

  .buy-now-info {
	background-color: #dff4fb;
	padding: 15px;
  }
`;

// Append the CSS to the document head
document.head.appendChild(prpCustomStyle);

const container = document.querySelector('.rw-exclusions-info'); // Replace with the actual selector

if (container) {
	const wrapperDiv = document.createElement('div'); // Create a div to wrap the elements
	wrapperDiv.className = "rw-recap-date-group rw-custom-fields"; // rw-recap-date-group only there to match Date label styling
	wrapperDiv.style.margin = "15px 0";
	wrapperDiv.innerHTML = `<div class="buy-now-info">
		Please note that there may be a delay with delivery if there are existing rentals in place for the item. You'll be notified of the expected delivery date within 24 hours of your 'Buy Now' order being placed, and you'll be given the option of a refund if the delay in dispatch will be more than 1 week.
		</div>`;
	container.appendChild(wrapperDiv);   // Append the div to the container
}

const days = document.querySelectorAll('input[name="Days"]');

// Function to toggle the visibility based on Days option selected
function toggleBuyNowMsg() {
	const selectedMethod = document.querySelector('input[name="Days"]:checked');
	console.log('selectedMethod', selectedMethod.value);
	const wrapperDiv = document.querySelector('.rw-custom-fields');

	if (selectedMethod && selectedMethod.value === "Buy Now") { // Match merchant's naming
		wrapperDiv.classList.add('rw-show'); // Show the element by adding the class
	} else {
		wrapperDiv.classList.remove('rw-show'); // Hide the element by removing the class
	}
}

// Run once on page load if Days fields exist
if (days) {
	toggleBuyNowMsg();

	// Listen for changes in the 'Days' radio buttons
	days.forEach(method => {
		method.addEventListener('change', toggleBuyNowMsg);
	});
}

Last updated