Creating a custom layout template for the plugin

Why a Custom Layout?

It is difficult to predict all the use cases, so to enable flexibility, with this plugin developers can create a custom layout template. This may be to change the position of images, add conditional text to buttons like ‘SOLD OUT’ and many more.
This tutorial covers adding venues and price data in the event meta section of the grid layout, but covers all the basics you need to add whatever Eventbrite data you need.

The Quick Guide

  1. Create a folder called widget-for-eventbrite-api in your child theme
    ( if you don’t have a child theme, you can place this folder in wp-content )
  2. Copy a template from the plugin template folder and rename your file keeping the name structure   shortcode_layout_{yourtemplatename}__premium_only.php 
  3. Identify the items you need e.g. $data->events->post->venue>address->localized_address_display see here for example structure
  4. And add the appropriate code and markup to your new template file
  5. Apply CSS to style as desired
  6. Use the new template in your shortcode e.g. [wfea layout=’mytemplate’]

The Long Version

The Eventbrite API feed contains lots of data, too much really to make it all as selection items in the shortcode parameters. So the plugin has a templating system that lets customise your own display. You don’t need to a hard core developer but you will need to be able to customise PHP, know the basis of HTML and CSS, but if you have got this far I’m fairly confident you will be able to create your own custom templates.

The first thing you will need is a place to store your custom template, and this will be in your child theme ( or wp-content ) . You never want to edit the templates in the plugin directory as any updates will overwrite your work. 

  •  create a directory  inside your child theme ( or wp-content ) called widget-for-eventbrite-api
  •  copy a template of your choice  from the plugin’s template directory /wp-content/plugins/widget-for-eventbrite-api/templates I have chosen the grid template
  •  rename the template – note the name format  must follow this structure  shortcode_layout_{yourname}__premium_only.php    note that is a double underscore infront of premium, the file I have renamed as shortcode_layout_mycustom1__premium_only.php
  •  test your shortcode [wfea layout=’mycustom1′]   should work and produce a grid layout as that is what we copied

OK we can now get down to coding!

The first thing we need to understand is the data structure that is passed to the template.

The event data is logically held in this object $data->events  and the best thing now is to inspect the data object structure and contents, if you have an IDE with debugging and breakpoints then use that to take a look at the data content, but if you have not don’t worry add this code to the top of your template just after the <?php line, and it will dump the structure and content to your browser console log ( remember to remove it before you go live )

function mydebug ($data) { 
    echo "<script>\r\n//<![CDATA[\r\nif(!console){var console={log:function(){}}}"; 
    $output    =    explode("\n", print_r($data, true)); 
    foreach ($output as $line) { 
        if (trim($line)) { 
            $line    =    addslashes($line); 
            echo "console.log(\"{$line}\");"; 
        } 
    } 
    echo "\r\n//]]>\r\n</script>"; 
} 
mydebug($data->events);

Using my sample Eventbrite data this is the content I get – I have put it in a separate page here for reference.

We really are not that far off now, next we want to find the data we want, in this case we want location and price.

We can see most of the useful data is down the structure at $data->events->posts->   but as the template is a WordPress loop using $data->events->have_posts()   we will user the structure $data->events->post->

If you carefully inspect  the structure you can find elements of  location within address. We can see several values but for this we will use
$data->events->post->venue->address->localized_address_display

For price we need to look at tickets – with EventBrite you can have multiple ticket prices, but for this example we will assume just one, and arrays count from 0 up, so the first ticket type is 0, namely
$data->events->post->tickets[0]->cost->display

If you have multiple ticket prices – you will have to write a little loop and decide how you will handle the display.

If you look at the structure there are other useful ticket fields with status like sold out etc.

Now we know the data elements – it is just a matter of adding that to the template in the appropriate place.

So for this example we will extend the entry-meta section and the code we will write is

                    <div class="venue">
                        <?php
                           printf('<span>%1$s</span>',$data->events->post->venue->address->localized_address_display);
                        ?>
                    </div>
                    <div class="price">
                        <?php
                           if ( $data->events->post->tickets[0]->free ) {
                               printf('<span>%1$s</span>',__('Free'));
                           } else {
                           printf('<span>%1$s</span>',$data->events->post->tickets[0]->cost->display);
                               }
                        ?>
                    </div>
  

Note for the ticket I’m just using ticket zero  – if you have multiple tickets you would code a loop to step through each ticket.
Also note, that I’m checking for ‘free’  as my events are mixed free and paid, and free events don’t have a cost, so trying to display a price when there isn’t one would create a not found error.

If you do have multiple tickets with different prices, then lets display a list of tickets with their names and prices separated by / and also lets check if the tickets are SOLD out or no longer on sale.  The code now becomes a loops building up a string and then outputting it.
Note I changed the text ‘Free’ to ‘£0’  – that is because my free tickets have a name ‘free’  so leaving as ‘free free’ looks weird. Of course different solutions or if statements could solve that issue differently.
The code for the new ‘price’ div could look like this

                   <div class="price">
                        <?php
                        $output = "";
                        foreach ($data->events->post->tickets as $ticket) {
                            $output .= $ticket->name . ' ';                // start with the name and a space
                            if ('AVAILABLE' !== $ticket->on_sale_status) {  // we only want proces for AVAILABLE tickets
                               $output .= sprintf('<span class="warn">%1$s</span>',str_replace('_',' ',$ticket->on_sale_status));  // unavailable tickets show the status instead of price removing undersccores
                                                                                                                                   // wrap in a span with class so you can style
                            } else {
                                if ($ticket->free) {
                                    $output .= esc_html__('£0', 'my-text-domain');   // esc_html__ will translate if the text domain has a translations
                                } else {
                                    $output .= $ticket->cost->display;
                                }
                            }
                            if (next($data->events->post->tickets)) {
                                $output .= ' / '; // only append a separator when there are more tickets  to come
                            }
                        }
                        printf('<span>%1$s</span>', $output);
                        ?>
                    </div>

Finally we need to add some styling, you can add css to your child theme style.css ( or in customizer additional css if you are so inclined )
I’m just going to add

.wfea-group .entry-meta div.venue {
   float: left;
}
.wfea-group .entry-meta div.price {
   float: right;
}
.wfea-group .warn {
   font-weight: bold;
}

You may want to do other things, like padding. fonts, colors, that is up to you.
And we also need to tweak the entry-meta div to ‘clear’ the floats – most themes should have a clearfix class so I’ll use that
so the full entry-meta section looks like

                <div class="entry-meta clearfix">
                    <?php
                    if ($data->args['date']) :
                        $date = eventbrite_event_time();
                        printf('<time class="eaw-time published" datetime="%1$s">%2$s</time>', esc_html(get_the_date('c')), esc_html($date));
                    endif;
                    ?>
                    <div class="venue">
                        <?php
                           printf('<span>%1$s</span>',$data->events->post->venue->address->localized_address_display);
                        ?>
                    </div>
                    <div class="price">
                        <?php
                        $output = "";
                        foreach ($data->events->post->tickets as $ticket) {
                            $output .= $ticket->name . ' ';                // start with the name and a space
                            if ('AVAILABLE' !== $ticket->on_sale_status) {  // we only want proces for AVAILABLE tickets
                                 $output .= sprintf('<span class="warn">%1$s</span>',str_replace('_',' ',$ticket->on_sale_status)); // unavailable tickets show the status instead of price removing undersccores
                                                                                                                                    // wrap in a span with class so you can style
                            } else {
                                if ($ticket->free) {
                                    $output .= esc_html__('£0', 'my-text-domain');   // esc_html__ will translate if the text domain has a translations
                                } else {
                                    $output .= $ticket->cost->display;
                                }
                            }
                            if (next($data->events->post->tickets)) {
                                $output .= ' / '; // only append a separator when there are more tickets  to come
                            }
                        }
                        printf('<span>%1$s</span>', $output);
                        ?>
                    </div>
                </div>

The final result.

The full code for the template. Please note the templates have been developed over time, so the example below is not current code as new features have been added since, so don’t just cut and paste.

<?php
/**
 * Front end display of shortcode loop
 * can be overridden in child themes / themes
 *
 * To customise create a folder in your theme directory called widget-for-eventbrite-api and a modified version of this file called shortcode_layout_1__premium_only.php
 * If you need a second layout  create a file e.g. shortcode_layout_2__premium_only.php  and call with [wfea layout=2]
 *
 * @var mixed $data Custom data for the template.
 */

if (false !== $data->events && $data->events->have_posts()) :

    // Recent posts wrapper.
    printf('<section %1$s class="wfea %2$s %3$s grid">',
        (!empty($data->args['cssID']) ? 'id="' . sanitize_html_class($data->args['cssID']) . '"' : ''),
        (!empty($data->args['css_class']) ? '' . sanitize_html_class($data->args['css_class']) . '' : ''),
        (!empty($data->template) ? '' . sanitize_html_class($data->template) . '' : '')
    );
    ?>
    <?php
    while ($data->events->have_posts()): $data->events->the_post();
        ?>
        <article class="post">
            <div class="wfea-group">
                <div class="wfea-banner">
                    <?php
                    if ($data->args['thumb']) :
                        ?>
                        <figure>
                            <?php

                            // Check if post has post thumbnail.
                            if (!empty($data->events->post->logo_url)) :
                                // Thumbnails.
                                printf('<a  href="%1$s" rel="bookmark"><img class="wp-post-image" src="%2$s" alt="%3$s"></a>',
                                    esc_url(eventbrite_event_eb_url()),
                                    esc_url($data->events->post->logo_url),
                                    esc_attr(get_the_title())
                                );

                            // Display default image.
                            elseif (!empty($data->args['thumb_default'])) :
                                printf('<a  href="%1$s" rel="bookmark"><img class="wp-post-image" src="%2$s" alt="%3$s"></a>',
                                    esc_url(eventbrite_event_eb_url()),
                                    esc_url($data->args['thumb_default']),
                                    esc_attr(get_the_title())
                                );
                            endif;
                            ?>
                        </figure>
                    <?php
                    endif;
                    ?>
                    <header class="entry-header">
                        <?php
                        if ($data->args['date']) :
                            ?>
                            <time>
                                <p>
                                    <?php
                                    the_date('M jS');
                                    ?>
                                </p>
                            </time>
                        <?php
                        endif;
                        ?>
                        <h4 class="entry-title">
                            <?php
                            printf('<a href="%1$s" title="%2$s" rel="bookmark">%3$s</a>',
                                esc_url(eventbrite_event_eb_url()),
                                sprintf(esc_attr__('Eventbrite link to %1$s', 'widget-for-eventbrite-api'), the_title_attribute('echo=0')),
                                the_title_attribute('echo=0')
                            );
                            ?>
                        </h4>

                    </header>
                </div>


                <div class="entry-meta clearfix">
                    <?php
                    if ($data->args['date']) :
                        $date = eventbrite_event_time();
                        printf('<time class="eaw-time published" datetime="%1$s">%2$s</time>', esc_html(get_the_date('c')), esc_html($date));
                    endif;
                    ?>
                    <div class="venue">
                        <?php
                           printf('<span>%1$s</span>',$data->events->post->venue->address->localized_address_display);
                        ?>
                    </div>
                    <div class="price">
                        <?php
                        $output = "";
                        foreach ($data->events->post->tickets as $ticket) {
                            $output .= $ticket->name . ' ';                // start with the name and a space
                            if ('AVAILABLE' !== $ticket->on_sale_status) {  // we only want proces for AVAILABLE tickets
                                 $output .= sprintf('<span class="warn">%1$s</span>',str_replace('_',' ',$ticket->on_sale_status)); // unavailable tickets show the status instead of price removing undersccores
                                                                                                                                    // wrap in a span with class so you can style
                            } else {
                                if ($ticket->free) {
                                    $output .= esc_html__('£0', 'my-text-domain');   // esc_html__ will translate if the text domain has a translations
                                } else {
                                    $output .= $ticket->cost->display;
                                }
                            }
                            if (next($data->events->post->tickets)) {
                                $output .= ' / '; // only append a separator when there are more tickets  to come
                            }
                        }
                        printf('<span>%1$s</span>', $output);
                        ?>
                    </div>
                </div>

                <div class=entry-content">
                    <?php
                    if ($data->args['excerpt']) :
                        ?>
                        <div class="excerpt">
                            <?php
                            printf(wp_trim_words(apply_filters('eawp_excerpt', get_the_excerpt()), $data->args['length'], ' &hellip;'));
                            if ($data->args['readmore']) :
                                printf('<a href="%1$s" target="_blank" class="more-link">%2$s</a>', esc_url(eventbrite_event_eb_url()), $data->args['readmore_text']);
                            endif;
                            ?>
                        </div>
                    <?php
                    endif;
                    ?>
                </div>
            </div>
            <?php
            if ($data->args['booknow']) :
                ?>
                <div class="booknow"> <?php
                    printf('<a href="%1$s" target ="_blank" ><button>%2$s</button></a>', esc_url(eventbrite_event_eb_url()), $data->args['booknow_text']);
                    ?>
                </div>
            <?php
            endif;
            ?>
        </article>
    <?php
    endwhile;
    ?>
    </section><!-- Generated by http://wordpress.org/plugins/widget-for-eventbrite-api/ -->
<?php

endif;

Was this helpful?