Events Introduction

Events is a full-featured Craft CMS Plugin for event management and ticketing. Events integrates with Craft Commerce so you can easily sell tickets to your events.

Major Features

  • Manage events and add optional custom fields
  • Events live preview and sharing
  • Generate tickets via events with auto generated SKU's
  • Manage ticket types and add optional custom fields
  • PDF Ticket with QR Code
  • Event ticket check in

Requirements

Craft CMS

Events requires Craft CMS 2.6 or higher.

Craft Commerce

Events extends und uses Craft Commerce features. The minimum version of Craft Commerce needed is 1.2.

PHP

Events requires Craft PHP 5.4 or higher.

Installation & Setup

Installing Events is as simple as any other Craft plugin - just drop the events/ folder in your craft/plugins directory and install.

Installation

  • Download the latest version of events and unzip.
  • Copy the events/ directory into your craft/plugins/ directory.
  • Inside the Craft control panel, navigate to Settings → Plugins.
  • Locate the row showing the Events plugin and click Install.

Settings/License

With Events installed, you will be able to acess the plugin settings. Here you can enter the license key for using Events and get access to general settings.

In the General Settings section you can adjust the length of the generated ticket SKU. Ticket SKU's are generated automatically when you add A Ticket Type to an event and when this ticket get purchased. Per default it is set to 6 characters length.

Setup

With Events now installed, you have to setup first:

Then you can create Events for your created event type.

Updates

Refer to the Releases via our Github repository for all updates and changes.

Feature Tour

Events

Overview

Go to the main section of Events via the CP sidebar menu. Because events are handled as element types, you will be presented a list similar as the entries overview.

Before you can start creating events first you have to set up a Event Type and a Ticket Type.

The overview shows a list of all events. You can filter them via event types or status and can search via their title. Also supported is a quick edit of the event details via double click at the status icon next to the event title.

Create/Edit

Each field is fairly self-explanatory, but any additional information is provided below.

  • Title: Set up a title for your event to easily find it in the cp panel and display at the frontend.
  • Start Date: The event start date can provided here.
  • End Date: If the event is more then a daily event, you can set a end date here.
  • All day event: If you don't want to set a specific time the event is running, you can simply set it as a all day event via the light switch button.
  • Slug: The slug is the link how the event is displayed at the frontend
  • Enable: Simply enable or disable this event for user in the frontend
  • Delete: The delete button deletes the event. Already purchased tickets for this event are still remain in the database.

  • Total capacity: The total capacity are calculated automatically via the quantities of all tickets. But if you want, you can set the capacity independently of the ticket quantities. Keep in mind that if you change the quanitity of one ticket, the total capacity will be recalculated.
  • Ticket Type: You can select a ticket type from a list of previous created ticket types.
  • Quantity: Set a quantity for this ticket type.
  • Price: Specify a price for this ticket type.
  • Available From: If wished, you can set a date from when this ticket type can be purchased.
  • Available To: Also possible is to set a date after that this ticket type can not be purchased anymore.
  • Delete Ticket Type: You can remove this ticket type from the event. Already purchased tickets are still remain in the database.
  • Add ticket: You can add a new ticket row where you can select ticket type, add quantities, prices and so on.

Live Preview

Events can show a live preview of you currently editing event. This is only possible, if you marked Events of this type have their own URLs the Event Type settings and provided a Event URL Format as well as a Event Template. Read further details under the Event Type section.

The Share button allows you to share a draft version of the event. If the event is not live yet, the link contains a token which allows you to show the event detail page. Without the token the event detail page is shown as page not found. This ability allows you to share the event link internal to get an approval or similar before you publish the event.

Event Types

Overview

Here you can find a table list of all created event types. First step(s) to start is to create your first event type you can categories events for.

The Delete icon deletes already created event types. Created events for this event type will also be deleted. Already purchased tickets still remain in the database.

Create/Edit

Each field is fairly self-explanatory, but any additional information is provided below.

  • Name: What this event type will be called in the CP.
  • Handle: How you’ll refer to this event type in the templates.

If you ticked Events of this type have their own URLs, the following fields appear:

  • Event URL Format: What the event URLs should look like. You can include tags that output event properties, such as such as slug} or {publishDatedate("Y").
  • Event Template: The template to use when a event’s URL is requested.

If you ticked it up, you should create a template file and insert the path. You can find a template example in the Templating section.

Event Fields

Event Fields are provided to use custom fields for events. You can find more details under the Event Custom Fields section.

Ticket Types

Overview

Here you can find a table list of all created ticket types. First step(s) to start is to create your first ticket type you can create tickets for.

The Delete icon deletes already created ticket types. Created tickets for this ticket type will also be deleted. Already purchased tickets still remain in the database.

Create/Edit

Each field is fairly self-explanatory, but any additional information is provided below.

  • Name: What this event type will be called in the CP.
  • Handle: How you’ll refer to this event type in the templates.
  • Tax Category: Tickets created and purchased for this ticket type will be categorised in the tax categorie you select here.

If you ticked Tickets of this type have their own URLs, the following fields appear:

  • Ticket URL Format: What the ticket URLs should look like. You can include tags that output event properties, such as such as slug} or {publishDatedate("Y").
  • Ticket Template: The template to use when a ticket’s URL is requested.

If you ticked it up, you should create a template file and insert the path. You can find a template example in the Templating section.

Ticket Fields

Ticket Fields are provided to use custom fields for tickets. You can find more details under the Ticket Custom Fields section.

PDF Ticket

Events supports a PDF version of purchased tickets. They can be printed by the customer to use them at the entrance. This PDF feature is using the Craft CMS integated Dompdf() function.

Template File

The printed ticket appearance is handled by a html template. You need to create a new template file somewhere in you template directory. A template example is provided in the Templating section under PDF Ticket.

Dynamic Route

Add a new dynamic route in Settings -> Routes:

  • URL: As example shop/events/ticket/<tag>/<number>
    • <tag>: This is the order id where the ticket was purchased.
    • <number>: This is the line item id of the ticket type which was purchased.
  • Template: Put in the path of the previous created template file. As example: shop/events/_ticket. You can leave off the html ending.

Last but not least you have to provide a download button oder link. You can put it in your costumer/order.html file for instance. Don't forget to use the link you pasted in your dynamic route.

<a target="_blank" href="/shop/events/ticket/{{ order.id }}">Download PDF Tickets</a>

The link has to point to the route you just created.

You can also display the download link for every single line item within you line item loop:

{% if item.purchasable.elementType == 'Events_Ticket' %}
    <a target="_blank" href="/shop/events/ticket/{{ order.id }}/{{ item.id }}">Download PDF Tickets</a>
{% endif %}

QR Code

Events provides a QR code generation feature. Because URL's are most times super long and not very beautiful to print we decided to use a QR code instead. The generated QR code contains a link to the Ticket Check In controller with the the ticket SKU.

Ticket Check In

Events is providing an easy ticket check in. The check in controller validates the ticket sku and checks if the ticket was already checked in to avoid multiple usage.

Route

The route to the check in controller is following:

actions/events/ticket/checkin?sku=<sku>

Parameter

  • <sku>: This is the ticket SKU which gets generated automatically at the purchase of the ticket. This SKU is unique.

Return

The controller returns a json response. On an error the response contains a simple error message. On success the response contains following:

  • success: Contains the string "Ticket checked in.".
  • checkedInDate: The check in date in the DATE_ATOM format.

Templating

Event list

You can display a list of all events via the following template snippet:

{% for event in craft.events.events.find() %}

Events are element types. Hence they are selectable via the Craft Element Criteria Model. For instance you can set a limit vouchers via limit().

{% for event in craft.events.events.limit(5).find() %}

Another way to adjust your list is to specify a event type via type().

{% for event in craft.events.events.type('festival').find() %}

And of course, you can combine multiple criterias.

{% for event in craft.events.events.type('festival').limit(5).find() %}

Ticket list

Tickets are also handled as ticket types. Hence you can select them similar as events via criterias. To get all tickets for a specified event you need to add the event id.

{% for ticket in craft.events.tickets.eventId(event.id) %}

Available Tickets

Because tickets can have a Available From and Available To parameter you need to be aware of this. Events provides a simple helper function to get all available tickets. The event id also needed here again.

{% for ticket in craft.events.availableTickets(event.id) %}

Purchased Tickets

Purchased tickets are stored in a extra table called purchased tickets. You can get this tickets via craft.events.purchasedTickets(). You can give this function up to 2 parameters:

  • array $attributes: list of attribute values (indexed by attribute names) that the active records should match.
  • array $options: query condition or criteria.

Event Capacity

Events have a maximum capacity. The capacity are calculated by the summary of the quanitites of all created event tickets. To check for the maximum event capacity you can paste in a event id as an argument.

{% set purchasedEventTickets = craft.events.purchasedTickets({ eventId: event.id }) | length %}
{% if purchasedEventTickets < event.capacity %}
    // Your ticket list here...
{% endif %}

Ticket Quantity

Every ticket has a maximum quantity. To check for the maximum quantity you can paste in a ticket id as an argument, similar as events.

{% set purchasedTickets = craft.events.purchasedTickets({ ticketId: ticket.id }) | length %}
{% if purchasedTickets < ticket.quantity %}
    //...
{% endif %}

Simple Ticket selection

A simple ticket selection list can look like following snippet:

{# check for event limit #}
{% set purchasedEventTickets = craft.events.purchasedTickets({ eventId: event.id }) | length %}
{% if purchasedEventTickets < event.capacity %}
    <form method="POST">
        <input type="hidden" name="action" value="commerce/cart/updateCart">
        <input type="hidden" name="redirect" value="shop/cart">
        <input type="hidden" name="qty" value="1">
        {{ getCsrfInput() }}

        <select name="purchasableId" class="purchasableId">
            {%- for ticket in craft.events.availableTickets(event.id) -%}

                {# check for ticket limits #}
                {% set purchasedTickets = craft.events.purchasedTickets({ ticketId: ticket.id }) | length %}
                {% if purchasedTickets < ticket.quantity %}
                    <option value="{{ ticket.purchasableId }}">
                        {{ ticket.getTicketTypeName() }} - {{ ticket.price|commerceCurrency(cart.currency) }}
                    </option>
                {%- endif -%}
            {%- endfor -%}
        </select>

        <button type="submit">{{ "Add to cart"|t }}</button>
    </form>
{% else %}
    <strong>Sold out</strong>
{% endif %}

Multiple Ticket Selection

Events is providing a multi ticket selection list. To use it you need to call the custom frontend controller events/cart/add.

A complete integration can look like following snippet:

<form method="POST">
    {# custom frontend controller #}
    <input type="hidden" name="action" value="events/cart/add">
    <input type="hidden" name="redirect" value="shop/cart">
    {{ getCsrfInput() }}

    <table width="100%" border="0" cellpadding="0" cellspacing="0">
        {% for ticket in craft.events.availableTickets(event.id) %}

            <tr>
                <td>{{ ticket.getTicketTypeName() }}</td>
                <td>{{ ticket.price | commerceCurrency(cart.currency) }}</td>

                <td align="right" nowrap="nowrap">
                    <input type="hidden" name="event" value="{{ event.id }}">

                    {# check for ticket limits #}
                    {% set purchasedTickets = craft.events.purchasedTickets({ ticketId: ticket.id }) | length %}
                    {% set availableTickets = ticket.quantity - purchasedTickets %}

                    {% if availableTickets > 0 %}
                        <div class="field dropdown">
                            <div class="input">
                                <select name="item[{{ ticket.id }}][qty]" class="ticket_table_select">
                                    {% set maxDropdown = (availableTickets > 10) ? 10 : availableTickets %}

                                    {% for i in 0..maxDropdown %}
                                        <option value="{{ i }}">{{ i }}</option>
                                    {% endfor %}
                                </select>
                            </div>
                        </div>
                    {% else %}
                        <strong>Sold out</strong>
                    {% endif %}
                </td>
            </tr>

        {% endfor %}
    </table>

    <input type="submit" value="{{ "Add to cart"|t }}" class="button"/>
</form>

Displaying Tickets After The Purchase

Purchased tickets can be displayed after the purchase in the costumer/order.html or _pdf/order.html file within the line item loop. Use following template snippet:

{% if item.purchasable.elementType == 'Events_Ticket' %}
    {% set purchasedTickets = craft.events.purchasedTickets({ lineItemId: item.id }) %}
    {% if purchasedTickets %}
        {% for purchasedTicket in purchasedTickets %}
            SKU: {{ purchasedTicket.ticketSku }}<br />
        {% endfor %}
    {% endif %}
{% endif %}

PDF Ticket

To generate a pdf ticket you need to create a extra template view. You can use simple html tags, css styling and even twig tags.

Display Tickets

Displaying a list of all purchased tickets for an order just use:

craft.events.purchasedTickets({ orderId: tag)

<tag> is used as order id, which we defined previously in our route setup.

If you did add <number> into your route setup, you can add number as lineItemId:

craft.events.purchasedTickets({ orderId: tag, lineItemId: number })

PDF Settings

  • compress: Compress the pdf file. Default is false
    • true
    • false
  • orientation: The orientation of the pdf
    • 'portrait'
    • 'landscape'
  • size: The size of the pdf
    • 'letter'
  • cacheDirectory: The directory to cache the pdf file.
  • filename: The filename for the chached pdf file.

QR Code

To replace a ugly URL with a beautiful QR Code, simply use:

<img src="{{ ticket.getQR() }}" />

Example File

Following template snippet can help you creating a appropiated template file:

{% set html %}
    <html>
    <head>
        <meta http-equiv="content-type" content="text/html; charset=utf-8" />
        <style>
            html {
                margin-top:0.2in !important;
                margin-left:0.2in !important;
            }

            body {
                font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
                font-size: 13px;
                line-height:1.4em;
                font-weight:bold;
            }

            .ticket {
                width:8in;
                height:2.7in;
                background-size:cover;
                background-repeat:no-repeat;
                position:relative;
                margin-bottom: 0.2in;
            }

            #event-info {
                display:inline-block;
                position:absolute;
                left:0.9in;
                top:0.12in;
                width:4.7in;
            }

            .label {
                color:#768690;
                display:block;
                text-transform:uppercase;
            }

            .value {
                display:block;
                color:#121212;
                text-transform:uppercase;
                overflow:hidden;
                font-size:16px;
            }

            #title {
                height:0.4in;
            }

            #stub-info {
                display:block;
                position:absolute;
                top:0.06in;
                left:6in;
                width:1.9in;
                text-align:center;
            }

            #purchased-on {
                display:inline-block;
                color:#fff;
                text-transform:uppercase;
                font-size:9px;
                text-align:center;
                width:100%;
                position:relative;
            }

            #qrcode {
                position:relative;
                width: 70%;
                height: auto;
                margin-top: 0.3in;
                margin-left: -1.9in;
            }

            #ticket-num {
                display:block;
                text-transform:uppercase;
                text-align:center;
                width:100%;
                position:relative;
                top: 0;
                left: 0;
                font-weight:bold;
                font-size: 12px;
            }

            #attendee-info {
                text-align:left;
                font-size:10px;
                position:relative;
                top:0.18in;
                line-height: 1.6em;
            }

            #attendee-info .value {
                font-size:10px;
            }
        </style>
    </head>

    <body>
    {% set orderId = tag %}
    {% for ticket in craft.events.purchasedTickets({ orderId: orderId, lineItemId: number }) %}
        <div class="ticket">

            <div id="event-info">
                <span class="label">EVENT</span>
                <span id="title" class="value">{{ ticket.getEvent().title }}</span>

                <span class="label">DATE AND TIME</span>
                <span class="value">{{ ticket.getEvent().startDate | date("M j, Y \\a\\t g:i A") }}</span>
                <span class="label">to</span>
                <span class="value">{{ ticket.getEvent().endDate | date("M j, Y \\a\\t g:i A") }}</span>
            </div>

            <div id="stub-info">
                <span id="purchased-on">Purchased on {{ ticket.getOrder().dateOrdered | date("M j, Y \\a\\t g:i A") }}</span>
                <img id="qrcode" src="{{ ticket.getQR() }}" />
                <span id="ticket-num" class="value">#{{ ticket.ticketSku }}</span>

                <div id="attendee-info">
                    <span class="label">1 {{ ticket.getTicketTypeName() }} Pass</span>
                    {% if ticket.getOrder().customer.user %}
                        <span id="name" class="value">{{ ticket.getOrder().customer.user.name }}</span>
                    {% else %}
                        {% set address = ticket.getOrder().customer.addresses[0] %}
                        <span id="name" class="value">{{ address.firstName }} {{ address.lastName }}</span>
                    {% endif %}
                    <span id="email" class="value">{{ ticket.getOrder().customer.email }}</span>
                </div>
            </div>
        </div>
    {% endfor %}
    </body>
    </html>
{% endset %}

{% set settings = {
    compress: true,
    orientation: 'portrait',
    size: 'letter',
    cacheDirectory: 'cache/tickets',
    filename: 'JAF2015-' ~ orderId ~ '.pdf'
} %}

{% set pdf = craft.events.pdfFromHtml(html, settings) %}
{{ pdf.output }}

Custom fields

Events provides custom fields. You can assign them for Events and Tickets.

You can access this custom fields easily as every other custom field in Craft. For instance, an assigned image asset field to an event can be displayed by following template code:

<img src="{{ voucher.customFieldImage.first().getUrl() }}" />

In this case customFieldImage is the handle of the custom field you did assign.

Events

You can assign custom fields to events via Event Types.

Once you assigned custom fields to a event type, they appear on the Event edit page and can filled with content. Every single tab you assigned in the field layout appears as it own tab with the associated fields.

Tickets

You can assign custom fields to tickets via Ticket Types.

Once you assigned custom fields to a ticket type, they appear on the Event edit page in the ticket tab under the ticket settings. To display the ticket settings simply click on the gearwheel icon. All assigned custom fields appear under the Available From/To fields.

Because tab handling is not supported here, just assign all custom fields into the same tab in the ticket type field layout editor.

Notice

After you selected a ticket type, assigned custom fields won't appear. First save the event and reopen the ticket settings, then custom fields will be displayed.

Support

Slack

Get in touch via the Craft Community Slack and be sure to post in the #help channel and mention our handle (@crawf). This is the most preferred method.

GitHub

If you've found a bug, or would like to make a feature request, head to the GitHub Repo and file an issue. Pull requests are also most welcome!

Twitter

Get our attention on Twitter by using the #craftcms hashtag and mentioning @verbb

Stack Exchange

Ask a question via the Craft Stack Exchange and tag your question with plugin-events.

Email

Any feedback, comments, questions or suggestions please email us at support at verbb.io.