How to Code a Custom Loop Template for Divi in PHP and CSS: A Step-by-Step Tutorial

Preview of the Divi Loop Layout

While the Divi theme provides a flexible visual builder for designing pages, its loop modules come with some limitations. The blog and post grid modules rely on Divi’s own loop code, which can be restrictive when you want full control over the loop output.

That’s where custom loop templates come in handy. The Divi Machine, Divi BodyCommerce, and Divi Ajax Filter plugins allow you to code your own templates to customize the markup and styling of archive loops.

Here are some key benefits of using a custom loop template:

  • Complete design freedom – Craft a unique layout tailored to your site’s needs, rather than working within Divi’s constraints.
  • Control over HTML markup – Structure the loop markup however you want, adding custom elements and classes.
  • Custom fields support – Display fields from ACF or other plugins in your loop items.
  • Faster load times – Hard-coded templates load quicker than generating loop output dynamically.
  • Reusability – Create templates once and reuse them across different archive modules.

In this comprehensive tutorial, we’ll walk through the steps for building a custom events template from start to finish using Divi Machine.

Let’s get started!

Step 1 – Set up the Post Type

As we’re using Divi Machine in this tutorial we will add our post type using this, if you’re using Divi Ajax Filters or Divi BodyCommerce then you could use ACF to add your Post Type.

We’ll use the Events post type for this example. To add it in Divi Machine, go to Divi Engine > Add/Edit Post Types and click “Add Post Type”.

Name it “Events” and leave the default settings, then click “Publish”.

Add a custom post type in Divi Machine

Now we’re ready to setup our ACF Fields!

Step 2 – Add Custom Fields with ACF

To display custom data in our loop, we need to set up Advanced Custom Fields. Go to ACF > Field Groups > Add New and create a group called “Event Info”.

Add the following fields:

  • Event Address – WYSIWYG Field
  • Event Date – Date Picker Field
  • Event Start Time – Time Picker Field
  • Event End Time – Time Picker Field
  • Ticket Link – URL Field

Event Address

Add an Event Address field using the WYSIWYG Field type. Set the Field Name to event_address.

Event Address field in ACF

Event Date

Add an Event Date field with the Date Picker Field type. Set Field Name to event_date.

Under Return Format, choose how you want the date displayed. We’ve gone with [Month] [Day], [Year] for our example.

Event Date field in ACF

Event Start Time

Use a Time Picker Field for Event Start Time. Set Field Name to event_start_time and add a custom Return Format like H:i to show just hours and minutes.

Event Start Time field in ACF

Event End Time

Add an Event End Time field the same way, with Field Name event_end_time. Again, we have used the Return Format of H:i to show just hours and minutes.

Event End Time field in ACF

Ticket Link

Create a Ticket Link field using the URL Field type. Set Field Label to “Ticket Link” and Field Name to ticket_link.

Ticket URL field in ACF

Assigning our Field Group to Our Post Type

Below our Fields, there is a section called Settings with a tab called Location Rules. For these fields to be associated with our Post Type, we configure this as follows:

Once done, assign the group to the Events post type under Location Rules.

Assign field group to Events post type

Step 3 – Create the Template File

To utilize Custom Loop Templates you need to have a Divi child theme. If you don’t already have one set up, take a peek at our post and free Divi child theme download here.

If you are already all set with your Divi child theme, follow these steps:

  • Copy our Sample Loop Template from our plugin to your child theme in this structure: /wp-content/themes/[YOUR-CHILD-THEME]/divi-ajax-filter/loop-templates/
  • The file location will be slightly different depending on the plugin you’re using, you can see the variations below:

Divi Ajax Filter
/wp-content/plugins/divi-ajax-filter/lib/loop-templates

Divi Machine
/wp-content/plugins/divi-machine/includes/modules/divi-ajax-filter/lib/loop-templates

Divi BodyCommerce
/wp-content/plugins/divi-bodycommerce/includes/modules/divi-ajax-filter/lib/loop-templates

Your file can be named custom-template.php and it will be automatically loaded or you can name this file anything you like and it will show in the Custom Loop Template dropdown in the module settings allowing you to create multiple templates. 

Custom Template in Divi Machine

The code in that file should look something like this:

<?php


if ( ! defined( 'ABSPATH' ) ) exit;


// get the post ID
$post_id = get_the_ID();


?>
<article id="<?php echo $post_id; ?>" <?php post_class( 'et_pb_post clearfix grid-item'); ?>>
<div class="grid-item-cont">
<p>
    Here you can create your own custom template for each post in the loop. To do this you will need to create a child theme if you do not have one.
    <br><br>
    Create the folder /divi-ajax-filter/loop-templates/custom-template.php
    <br><br>
    Add the content you want for each post there.
</p>
</div>
</article>
<?php

This file is where we’ll add the loop markup that shows all the elements we’d like to see show up on the front end.

Step 4 – Set Up the Main Markup

The contents of your Custom Loop Template sit within the Post Object which means that it is almost like being on the single post page from a code standpoint. This means that functions like the_title() work without the need to specify an ID as the code works as if you’re on that page itself. This simplifies the process for you and opens up a lot of functionality. 

Let’s start cleaning things up a little first and add some simple code that will house our Custom Divi Loop:

The Article Element

We’re going to delete everything that is within the <article> tags so it looks like this:

<?php


if ( ! defined( 'ABSPATH' ) ) exit;


// get the post ID
$post_id = get_the_ID();


?>
<article id="<?php echo $post_id; ?>" <?php post_class( 'et_pb_post clearfix grid-item'); ?>>

Our code will go here...

</article>
<?php

The Card Container

Inside <article>, add a <div> with class card to contain the loop:

<?php


if ( ! defined( 'ABSPATH' ) ) exit;


// get the post ID
$post_id = get_the_ID();


?>
<article id="<?php echo $post_id; ?>" <?php post_class( 'et_pb_post clearfix grid-item'); ?>>
<div class="card">

Our code will go here...

</div>
</article>
<?php

Step 5 – Add the Loop Contents

Now, before we start building and adding all the elements we want in out custom loop, let’s remind ourselves of the template we’re building.

Preview of the Custom Loop we are building for Divi
The template can be broken down into the following components:

  • Featured Image
  • Date & Times
  • Event Details
  • Icons
  • Call to Actions

We’ll work through each of these components and gradually build our Custom Divi Loop template out.

Featured Image

The first component we’re going to add is our thumbnail of the featured image, to do this we we will add a <div> with the class card-image inside of main card <div>. We also need to sprinkle some PHP in there to call our image, so add the code below:

<div class="card-image">
  <?php echo get_the_post_thumbnail( $post_id, 'large', array( 'class' => 'img-responsive' ) ); ?>
</div>

This PHP code is using the get_the_post_thumbnail() function to display the featured image (post thumbnail) of a specific post.

The function takes three parameters:

  • $post_id (required): The ID of the post for which you want to display the featured image.
  • 'large' (optional): The size of the thumbnail you want to display. ‘thumbnail’ is a predefined size in WordPress, but you can also use other predefined sizes like ‘medium’, ‘large’, or custom sizes.
  • array( 'class' => 'img-responsive' ) (optional): An array of additional attributes to pass to the HTML img tag that will be rendered for the featured image. In this example, 'class' => 'img-responsive' is added to set the CSS class of the img tag to 'img-responsive'. This is often used to make the image responsive or to apply styling.

The echo statement is used to print the HTML code generated by the get_the_post_thumbnail() function to the webpage or output it to the browser. The HTML code will be an img tag with the desired image and attributes.

Date and Time

Now that we have our image in place, we need to add our date and times. To do this we will add another div after our featured image, we’ll give it a class of event-schedule and inside it we will create two more, one with the class event-date and the other with the class event-time.

<div class="event-schedule">
  <div class="event-date">
    Our code will go here...
  </div>
  
  <div class="event-time">
    Our code will go here...     
  </div>
</div>

Now we have our containers, we need to actually get the the ACF fields, but how? We’ll start with the Event Date. When you just need to output the ACF field there is a handy function called the_field(). We can then pass the ACF Field Name to this so it would be the_field(‘event_date’).

<div class="event-schedule">
  <div class="event-date">
    <?php the_field( 'event_date' ); ?>
  </div>
  
  <div class="event-time">
    Our code will go here...     
  </div>
</div>

Using the same logic we used on our Event Date, we’ll repeat a similar process with our times, so we can put them in using the_field(‘event_start_time’) and the_field(‘event_end_time’).

<div class="event-schedule">
  <div class="event-date">
    <?php the_field( 'event_date' ); ?>
  </div>
  
  <div class="event-time">
    <?php the_field( 'event_start_time' ); ?> - <?php the_field( 'event_end_time' );?>
  </div>
</div>

The problem with this is that only our Event Start Time is a required field so if no end time was defined we would end up with an output like this: 13:00 -

That doesn’t look great does it? So, we’re going to use an if statement to only show our separator if an end time has been defined.

<div class="event-schedule">
  <div class="event-date">
    <?php the_field( 'event_date' ); ?>
  </div>
  
  <div class="event-time">
    <?php the_field( 'event_start_time' ); ?><?php if(get_field('event_end_time')) { echo ' - '; the_field( 'event_end_time' ); } ?>
  </div>
</div>

Event Title

With our Date and Times locked in, let’s move on to the Title. Under your event-schedule div, add a new one with the class event-details. To add our title, we will use the the_title() function which we’ll also wrap in a h2 tag.

<div class="event-details">
  <h2><?php the_title(); ?></h2>
</div>

Address

Next is the address, which is another ACF field, so you probably know the drill by now. We can use the_field() to get this so we’ll add a div under our h2 tags with the class event-address and in this add some PHP to show the ACF field.

<div class="event-details">
  <h2><?php the_title(); ?></h2>
  <div class="event-address">
    <?php the_field( 'event_address' ); ?>
  </div>
</div>

CTA Buttons

We are trucking along liek crazy, feel like a Divi code ninja yet? Almost there.

So, to add our buttons we’re going to add…you guessed it… another div under the address we just added. We’ll give this div a class of event-cta-row.

<div class="event-cta-row">
   Our code will go here...
</div>

We’re going to have two buttons in our loop, one will go to the event page which will always be visible, and the other will go to an external URL to purchase a ticket if a link is provided.

We’ll start with the button going to the event page.

To do this, we will add an a tag with the class event-details-cta and a href value which will be dynamically added using the the_permalink() function.

<div class="event-cta-row">
  <a href="<?php the_permalink(); ?>" class="event-details-cta">Details</a>
</div>

You can of course change the link text from to anything you’d like, but details seems to make the most sense here.

Now comes the final step in our template file, adding the external link for ticket purchases.

We only want this to show if there is a link was provided, so we’re going to add an if statement to check if our ACF Field ticket_link has a value. If it does, we will add our a tag with the field value as the href value and the class event-tickets-cta. This will go right below our “Details” button.

<div class="event-cta-row">
  <a href="<?php the_permalink(); ?>" class="event-details-cta">Details</a>

  <?php if(get_field( 'ticket_link' )) : ?>
    <a href="<?php the_field( 'ticket_link' ); ?>" class="event-tickets-cta">Buy Tickets</a>
  <?php endif; ?>
</div>

And that’s it! For our template anyway, as you can see, it doesn’t look very good right now. In the next step, we’re going to cover styling the template.

Unstyled coded Divi loop template

Step 6 – Style the Template

Time to make it all look purrdy! We’ll be placing all of our CSS in the style.css file of our child theme for this step. You can of course adjust the values to match your design as we go, this is just to serve as a guide on how one might do this.

The first thing we need to do is to add a little bit of CSS to ensure our containers are the same height so we get a nice uniform appearance.

Either head over to Appearance > Theme File Editor > style.css and add the CSS below.

.grid-col,
.grid-col > div,
.grid-col > div > article {
  height:100%;
  margin-bottom: 0;;
}

The next step is to give our ‘card’ some styling. Each line is commented below.

.card {
  width:100%; /* Ensure the card is 100% width of the column */
  box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; /* Add a shadow to make it stand out */
  border-radius:10px; /* Subtle rounding on the corners */
  overflow:hidden; /* Hide the content that overflows the card */
  height: 100%; /* Ensure the card is 100% height of the column */
  display:flex; /* Flexbox makes the container flexible */
  flex-direction:column; /* Flex direction column makes the children stack vertically */
  justify-content:flex-start; /* Align the children to the top of the container */
}

Now let’s style our Dates and Times.

/* Target the date and time */
.event-schedule > div {
  font-family: sans-serif;
  width: auto;
  text-align: center;
}
/* Target the date */
.event-date {
  border-right: 1px solid #dedede; /* Add a seperator between the date and time */
  padding-right: 10px;
}
/* Target the time */
.event-time {
  padding-left: 10px;
}

The next step is the event details which is our Title and Address.

/* Target the container of the title and address */
.event-details {
  width: 90%;
  margin: 0 auto 0 auto;
  color: #273c75;
  flex-grow: 1;
}
.event-details h2 {
  font-family:sans-serif;
}
.event-address {
  font-family:sans-serif;
}

Lastly, we have to style our buttons.

/* Style the CTA buttons */
.event-cta-row > a {
  transition: opacity 0.3s ease-in-out; /* Add a transition to the opacity */
  flex-grow: 1; /* Allow the buttons to grow to fill the container */
}
.event-cta-row > a:hover {
  opacity: 0.8; /* Fade the button on hover */
}
.event-details-cta {
  width:50%; /* Make the button 50% of the container - It will still grow if there is only 1 button */
  background: #8360c3;  /* fallback for old browsers */
  background: -webkit-linear-gradient(to right, #2ebf91, #8360c3);  /* Chrome 10-25, Safari 5.1-6 */
  background: linear-gradient(to right, #2ebf91, #8360c3); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
  padding:10px; /* Add some padding */
  color:white; /* White text */
  text-align:center; /* Center the text */
  font-family:sans-serif; /* Sans-serif font */
  text-decoration:none; /* Remove the underline */
  font-weight:bold; /* Bold font weight */
}
.event-tickets-cta {
  width:50%; /* Make the button 50% of the container - It will still grow if there is only 1 button */
  background: #ad5389;  /* fallback for old browsers */
  background: -webkit-linear-gradient(to right, #3c1053, #ad5389);  /* Chrome 10-25, Safari 5.1-6 */
  background: linear-gradient(to right, #3c1053, #ad5389); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
  padding:10px; /* Add some padding */
  color:white; /* White text */
  text-align:center; /* Center the text */
  font-family:sans-serif; /* Sans-serif font */
  text-decoration:none; /* Remove the underline */
  font-weight:bold; /* Bold font weight */
}

And that folks, is all there is to it! Now when you refresh your Divi page, you will see this shiny and gorgeous custom coded loop layout. Go, you!

Bonus: Adding a Repeater Field

Many of our users have asked about adding a repeater field to the custom Divi loop layouts, so here is our take on that and guide on how you can do it yourself!

Just note that you will need ACF Pro to follow along.

Add the Repeater Field

First we need to add a “Title Field” which will house our repeater, so let’s get cracking.

Icon List Title


This will let you set the title that appears above the icon list. We have defined a default value which then ensures a title will always be visible but allows you to modify it should you require a different one on any specific posts.

Icon List/Tooltip


For our icons we’re going to use a repeater which allows you to set an icon/image and a tooltip value. What we need to do now, is configure the Repeater Field.

Repeater Sub-Fields

Then we have our sub fields, we’ll be using an image and a text field.

The Icon is configured like below, the field label is Icon, Field Name is icon and the type is Image. We’ve also got the Return Format set to Image URL to make it easy to work with.

Next is our Text Field for the tooltip text. The Field Type is Text, Field Label is Tooltip and the Field Name is tooltip


Now we have our repeater field in place, we can focus on the code which will display it in our custom coded Divi loop layout.

Output the Repeater to the Loop

As Biggie smalls said, we’re going going, back back, to Cali Cali…or in this case, our custom template PHP file.

The Icon Title and Icons will be above our buttons so we will be adding the code between the Event Details div and the CTA Row div.

The title will work the same as the previous ACF Fields however the icons and tooltip works slightly differently as we have them within a repeater field.

We don’t want the title or icons to show up if we don’t have any icons to show so we will start off by adding the following two lines after our event-details div.

<?php if ( have_rows( 'icon_list_tooltip' ) ) : ?>

  Our code will go here...

<?php endif; ?>

This code checks to see if we have any rows in our repeater, if we do, it will show the content between the two PHP lines.

Ok, so let’s add our title. To do this, let’s add a div with the class event-icons-title and put the ACF Field inside with the code below.

<?php if ( have_rows( 'icon_list_tooltip' ) ) : ?>

  <div class="event-icons-title">
    <?php the_field( 'icon_list_title' );?>
  </div>

<?php endif; ?>

Now that our title is in place, let’s add a div to contain our icons with the class event-icons.

<?php if ( have_rows( 'icon_list_tooltip' ) ) : ?>

  <div class="event-icons-title">
    <?php the_field( 'icon_list_title' ); ?>
  </div>
  
  <div class="event-icons"> 
    Our code will go here...
  </div>

<?php endif; ?>

Now we can add a statement. This will loop through each row in our repeater. Note, we have referenced the full name of our repeater.

<?php if ( have_rows( 'icon_list_tooltip' ) ) : ?>

  <div class="event-icons-title">
    <?php the_field( 'icon_list_title' ); ?>
  </div>
  
  <div class="event-icons">    
    <?php while ( have_rows( 'icon_list_tooltip' ) ) : the_row(); ?>
      Our code will go here...
    <?php endwhile; ?> 
  </div>

<?php endif; ?>

Now we can add our icon container and tooltip text. To do this we’ll have a div with the class event-icon and also a data attribute called data-tooltip which has the ACF Field tooltip as a value.

<?php if ( have_rows( 'icon_list_tooltip' ) ) : ?>

  <div class="event-icons-title">
    <?php the_field( 'icon_list_title' ); ?>
  </div>
  
  <div class="event-icons">    
    <?php while ( have_rows( 'icon_list_tooltip' ) ) : the_row(); ?>
      <div class="event-icon" data-tooltip="<?php the_sub_field( 'tooltip' ); ?>">
      </div>
    <?php endwhile; ?> 
  </div>

<?php endif; ?>

Lastly, we add the icon itself with a simple image tag with the src set to the ACF Icon value.

<?php if ( have_rows( 'icon_list_tooltip' ) ) : ?>

  <div class="event-icons-title">
    <?php the_field( 'icon_list_title' ); ?>
  </div>
  
  <div class="event-icons">    
    <?php while ( have_rows( 'icon_list_tooltip' ) ) : the_row(); ?>
      <div class="event-icon" data-tooltip="<?php the_sub_field( 'tooltip' ); ?>">
        <img src="<?php the_sub_field( 'icon' ); ?>" />
      </div>
    <?php endwhile; ?> 
  </div>

<?php endif; ?>

That is it for the PHP! Yewwwwwwww!!

Styling

Now let’s style the title above the icons, the icons, and the tooltips then call it a day!

Just add the CSS code below to the style.css in your Divi child theme.

/* Style the Title above the icons */
.event-icons-title {
  text-align: center; /* Center the title */
  font-weight: bold; /* Bold font weight */
  margin-top: 20px; /* Add some top margin */
}
/* Style the icon container */
.event-icons {
  display:flex; /* Flexbox makes the container flexible */
  flex-direction:row; /* Flex direction row makes the children stack horizontally */
  justify-content:center; /* Center the icons */
  gap:10px; /* Add some space between the icons */
  margin-top:10px; /* Add some top margin */
}
.event-icon {
  position: relative; /* Position relative allows us to position the tooltip */
}
/* Style the tooltip */
.event-icon:before {
  content:attr(data-tooltip); /* Add the tooltip text */
  position: absolute; /* Position absolute allows us to position the tooltip */
  background:rgb(39 60 117 / 100%); /* Add a background color */
  top:-35px; /* Position the tooltip above the icon */
  left:50%; /* Position the tooltip in the center of the icon */
  transform:translateX(-50%); /* Translate the tooltip to the left by 50% of its own width */
  width:auto; /* Make the tooltip width auto so it can grow with the text */
  white-space: nowrap; /* Prevent the tooltip from wrapping */
  color:white; /* White text */
  padding:5px; /* Add some padding */
  border-radius: 10px; /* Add some rounding to the corners */
  transition: all 0.3s ease-in-out; /* Add a transition to the opacity */
  opacity: 0; /* Hide the tooltip by default */
}
.event-icon:hover:before {
  opacity:1; /* Show the tooltip on hover */
}
/* Set the width and height of the icon */
.event-icon > img {
  width:20px;
  height:20px;
}

There we go folks, much better, isn’t it?

Final Thoughts

That was intense, I know, but to achieve great custom Divi loop layouts you need to get into the nitty gritty of it all. And again, this is just how we felt was the best way to show you guys How to Code a Custom Loop Template for Divi in PHP and CSS, so use this as a stepping stone to build pretty much any layout you like.

Thanks for following along, and catch you in the next Divi tutorial!

See the completed code below:
Full PHP code
Full CSS Code

0 Comments

Submit a Comment

Explore more from Divi Engine