Conditional Output in Bricks based on Visitor Selection

Updated on 16 Aug 2024

A user asked:

How to dynamically show menu based on ‘user type’ selected

Hi, starting out on a project moving a clients site from hubspot to wordpress.

On their homepage, users select what type they are, eg. homeowner, architect etc. The site recognises the option chosen and shows a different menu option for each one.

Any ideas how I can change the ‘user type’ to whatever they have chosen so it shows the right menu – the menus will output conditionally, ie ‘ if the field = homeowner, only show x and y

Hope that makes sense.

Home to select option: https://cemfloor.co.uk

…when they navigate to other pages after choosing user type, the same menu button with the user type stays present based on their choice. Any ideas – I was trying to create a header that displays the button and menu conditionally based on their user type choice – trying to set a cookie on session storage using bricks interactions on the homepage and then output conditionally based on that.

Also the logo goes to the chosen user type ‘home’ page too once they have selected one.

This Pro tutorial shows how

  • localStorage can be used to store/persist the user type on the client-side and
  • cookies can be used to make the user type accessible to PHP on the server-side and
  • AJAX can be used to sync the user type with server

to transfer data between server and browser for effectively using dynamic conditions in Bricks to conditionally output elements depending on which button the visitor has clicked.

This is quite a powerful technique to have in your toolbox after you understand how it is put together and you should be able to extend it to build various solutions like age gate and custom cookie banners.

In this example we shall set up three buttons on the homepage each linking to corresponding pages:

and add three corresponding buttons (can be any other element) in the Header template:

Each button in the header has a dynamic data condition set on it.

These header buttons will not be visible on the homepage when a visitor visits the site for the first time or has not clicked on any of the homepage buttons yet.

When a visitor clicks the Homeowner button on the homepage for example, our custom JavaScript sets localStorage and a cookie (user_type = homeowner), then navigates to the corresponding /homeowners/ page.

In the dynamic condition on the Homeowner header button, we call a custom function that checks if the user_type cookie’s value is homeowner and since that is true when the Homeowner homepage button is clicked, the header button will be shown.

The cookie’s value will remain the same until another homepage button is clicked thus enabling us to output different elements based on which button the visitor clicked.

Update 1

Added instructions on how to add a select dropdown in addition to the buttons for the visitors to select their user type.

Step 1

Edit your site’s homepage with Bricks and inside a Section’s Container, paste this Block.

The three buttons (anchor tags to be precise) have user-type-link class.

They are each linked to /home-owners/, /contractors/, and /channel-partners/ respectively. While it does not matter, you may want to create these 3 Pages just so you don’t keep coming across 404 Not Found pages during your testing after you implement the steps.

The buttons have IDs set at STYLE → CSS → CSS ID to homeowner, contractor and channel-partner respectively. The value of user_type cookie will be set to the ID of whichever button is clicked.

Step 2

Install and activate the Bricks child theme if it is not already active. You can download the Bricks child theme directly from your Bricks account.

This can be done at any stage, even if your site is already built with the parent Bricks theme, and will not have any negative impact.

Create a directory called assets in the child theme.

Create a directory called js inside assets.

Create a file named say, localstorage.js in the above js directory having:

// Wait for the DOM to be fully loaded before executing the script
document.addEventListener('DOMContentLoaded', () => {
  // Select all elements with the class 'user-type-link'
  const links = document.querySelectorAll('.user-type-link');

  // Add click event listeners to each user type link
  links.forEach(link => {
    link.addEventListener('click', event => {
      // Prevent the default link behavior
      event.preventDefault();

      // Get the user type from the link's id attribute
      const userType = link.id;
      // Get the target URL from the link's href attribute
      const targetUrl = link.href;

      // Store the user type in localStorage for client-side persistence
      localStorage.setItem('user_type', userType);

      // Set a cookie with the user type for server-side access
      // The cookie expires in 1 hour and is available for the entire site
      document.cookie = `user_type=${userType}; path=/; max-age=3600`;

      // Immediately navigate to the target URL
      window.location.href = targetUrl;

      // Send an AJAX request to the server to update the user type
      // This happens after navigation starts, thanks to the keepalive option
      // bl_ajax_object is the object that contains the AJAX URL sent from the PHP
      fetch(bl_ajax_object.ajax_url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded',
        },
        body: `action=set_user_type&user_type=${encodeURIComponent(userType)}`,
        keepalive: true, // Ensures the request completes even if the page unloads
      });
    });
  });

  // Check if we need to sync the user type on page load
  const userType = localStorage.getItem('user_type');
  if (
    userType && // If a user type is stored in localStorage
    (!document.cookie.includes('user_type=') || // And either the cookie doesn't exist
      document.cookie.split('user_type=')[1].split(';')[0] !== userType) // Or the cookie value doesn't match localStorage
  ) {
    // Update the cookie to match localStorage
    document.cookie = `user_type=${userType}; path=/; max-age=3600`; // 1 hour expiry
    // Send an AJAX request to update the server
    fetch(bl_ajax_object.ajax_url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: `action=set_user_type&user_type=${encodeURIComponent(userType)}`,
    });
  }
});

Step 3

Add this in child theme’s functions.php near the end:

<?php 

// Enqueue the localstorage.js script and localize (fancy way of saying pass to the .js file) AJAX URL
add_action( 'wp_enqueue_scripts', function() {
	// Check if we're not in the Bricks builder interface
	if ( ! bricks_is_builder_main() ) {
		// Only enqueue the script on the front page (site's homepage set at Settings → Reading)
		if ( is_front_page() ) {
			// Enqueue (fancy way of saying load) the localstorage.js script
			wp_enqueue_script( 
				'localstorage', 
				get_stylesheet_directory_uri() . '/assets/js/localstorage.js', 
				[], // No dependencies
				'1.0.0', // Version number
				[ 'in_footer' => true, 'strategy' => 'defer' ] // Load in footer and defer execution.
			);

			// Localize the script with new data
			wp_localize_script( 'localstorage', 'bl_ajax_object', [
				'ajax_url' => admin_url( 'admin-ajax.php' ), // Provide the AJAX URL to the script
			] );
		}
	}
} );

// AJAX handler function for setting user type
function bl_set_user_type() {
	// Check if the 'user_type' parameter is present in the POST request
	if ( isset( $_POST['user_type'] ) ) {
		// Sanitize the user type from POST data. Sanitization removes or encodes potentially harmful characters, making it safe to use.
		$user_type = sanitize_text_field( $_POST['user_type'] );

		// Echo back the sanitized user type. This line sends the sanitized user type back to the client-side JavaScript that made the AJAX request. It serves as a confirmation that the server has received, processed, and accepted the user type.
		echo $user_type;
		// In AJAX, whatever is echoed in the PHP function becomes the response body that the client-side JavaScript receives. In this case, the user type is echoed back to the client-side JavaScript. The JavaScript can then use this response to confirm that the user type was set correctly.
	}
	wp_die(); // Terminate AJAX request properly
}
// Hook the AJAX handler for both logged-in and non-logged-in users
add_action( 'wp_ajax_set_user_type', 'bl_set_user_type' );
add_action( 'wp_ajax_nopriv_set_user_type', 'bl_set_user_type' );

// Function to check if the current user type matches the given type
function bl_is_user_type( string $type ): bool {
	// Check if the user_type cookie is set and matches the given type
	return isset( $_COOKIE["user_type"] ) && $_COOKIE["user_type"] === $type;
}

// Add the bl_is_user_type function to the list of functions that can be echoed in Bricks
add_filter( 'bricks/code/echo_function_names', function() {
	return [
		'bl_is_user_type',
	];
} );

Step 4

Edit your Header template and add three buttons (or heading or text elements) for testing.

Set the text to Homeowners, Contractors and Channel Partners.

Apply this dynamic condition on the Homeowners element:

{echo:bl_is_user_type(homeowner)}

Apply similar conditions on the other two elements.

The value being passed to the bl_is_user_type function should match the ID of the homepage buttons.

Ex.:

That’s it! Check on the front end.

Now that you have it working (hopefully, if not post a comment or send a support ticket), go through the fairly well-commented code to see how it is all working together.

Update 1: How to add a select dropdown in addition to the buttons

Remove the is_front_page() check in the wp_enqueue_scripts handler by changing

// Enqueue the localstorage.js script and localize (fancy way of saying pass to the .js file) AJAX URL
add_action( 'wp_enqueue_scripts', function() {
	// Check if we're not in the Bricks builder interface
	if ( ! bricks_is_builder_main() ) {
		// Only enqueue the script on the front page (site's homepage set at Settings → Reading)
		if ( is_front_page() ) {
			// Enqueue (fancy way of saying load) the localstorage.js script
			wp_enqueue_script( 
				'localstorage', 
				get_stylesheet_directory_uri() . '/assets/js/localstorage.js', 
				[], // No dependencies
				'1.0.0', // Version number
				[ 'in_footer' => true, 'strategy' => 'defer' ] // Load in footer and defer execution.
			);

			// Localize the script with new data
			wp_localize_script( 'localstorage', 'bl_ajax_object', [
				'ajax_url' => admin_url( 'admin-ajax.php' ), // Provide the AJAX URL to the script
			] );
		}
	}
} );

to

// Enqueue the localstorage.js script and localize (fancy way of saying pass to the .js file) AJAX URL
add_action( 'wp_enqueue_scripts', function() {
	// Check if we're not in the Bricks builder interface
	if ( ! bricks_is_builder_main() ) {
		// Enqueue (fancy way of saying load) the localstorage.js script
		wp_enqueue_script( 
			'localstorage', 
			get_stylesheet_directory_uri() . '/assets/js/localstorage.js', 
			[], // No dependencies
			'1.0.0', // Version number
			[ 'in_footer' => true, 'strategy' => 'defer' ] // Load in footer and defer execution.
		);

		// Localize the script with new data
		wp_localize_script( 'localstorage', 'bl_ajax_object', [
			'ajax_url' => admin_url( 'admin-ajax.php' ), // Provide the AJAX URL to the script
		] );
	}
} );

Replace all the code in localstorage.js with:

// Wait for the DOM to be fully loaded before executing the script
document.addEventListener('DOMContentLoaded', () => {
  // Select all elements with the class 'user-type-link'
  const links = document.querySelectorAll('.user-type-link');

  // Add click event listeners to each user type link
  links.forEach(link => {
    link.addEventListener('click', event => {
      // Prevent the default link behavior
      event.preventDefault();

      // Get the user type from the link's id attribute
      const userType = link.id;
      // Get the target URL from the link's href attribute
      const targetUrl = link.href;

      // Set user type and navigate
      setUserTypeAndNavigate(userType, targetUrl);
    });
  });

  // Select the user type dropdown menu
  const userTypeSelect = document.getElementById('user-type-select');

  // Add change event listener to the dropdown menu if it exists
  if (userTypeSelect) {
    userTypeSelect.addEventListener('change', event => {
      const userType = event.target.value;
      if (userType) {
        // Get the target URL based on the selected user type
        const targetUrl = getTargetUrl(userType);
        // Set user type and navigate
        setUserTypeAndNavigate(userType, targetUrl);
      }
    });

    // Set initial value of dropdown if user type is already selected
    const currentUserType = localStorage.getItem('user_type');
    if (currentUserType) {
      userTypeSelect.value = currentUserType;
    }
  }

  // Function to set user type and navigate
  function setUserTypeAndNavigate(userType, targetUrl) {
    // Store the user type in localStorage for client-side persistence
    localStorage.setItem('user_type', userType);

    // Set a cookie with the user type for server-side access
    // The cookie expires in 1 hour and is available for the entire site
    document.cookie = `user_type=${userType}; path=/; max-age=3600`;

    // Immediately navigate to the target URL
    window.location.href = targetUrl;

    // Send an AJAX request to the server to update the user type
    // This happens after navigation starts, thanks to the keepalive option
    fetch(bl_ajax_object.ajax_url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: `action=set_user_type&user_type=${encodeURIComponent(userType)}`,
      keepalive: true, // Ensures the request completes even if the page unloads
    });
  }

  // Function to get the target URL based on user type
  function getTargetUrl(userType) {
    // Define your URL mapping here
    const urlMap = {
      homeowner: '/home-owners/',
      contractor: '/contractors/',
      'channel-partner': '/channel-partners/',
    };
    return urlMap[userType] || '/'; // Return homepage if no match
  }

  // Check if we need to sync the user type on page load
  const userType = localStorage.getItem('user_type');
  if (
    userType && // If a user type is stored in localStorage
    (!document.cookie.includes('user_type=') || // And either the cookie doesn't exist
      document.cookie.split('user_type=')[1].split(';')[0] !== userType) // Or the cookie value doesn't match localStorage
  ) {
    // Update the cookie to match localStorage
    document.cookie = `user_type=${userType}; path=/; max-age=3600`; // 1 hour expiry
    // Send an AJAX request to update the server
    fetch(bl_ajax_object.ajax_url, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: `action=set_user_type&user_type=${encodeURIComponent(userType)}`,
    });
  }
});

In your Bricks Header template, add this Code Block for the select menu:

<select id="user-type-select" class="user-type-select">
    <option value="">Select User Type</option>
    <option value="homeowner">Homeowner</option>
    <option value="contractor">Contractor</option>
    <option value="channel-partner">Channel Partner</option>
</select>

In the CSS area:

%root% select {
  padding-left: 22px;
  padding-right: 30px;
}

Reference

https://make.wordpress.org/core/2023/07/14/registering-scripts-with-async-and-defer-attributes-in-wordpress-6-3/