Timeloop plugin for Craft CMS 5.x
This plugin creates repeating dates without complex inputs

Have you ever wanted to create recurring events without having the bloat of a full scale events calendar or the need to duplicate entries over and over?
Timeloop allows you to do just that. Simply set a start date (and time if you wish), configure the repetition frequency (every last Sunday of the month maybe?) and set any reminder you might like (2 days before sounds great) and Timeloop will provide you with an array of dates to work with.
Some examples
- You have a dance class that is held every Tuesday and Thursday at 6:30pm
- An employee portal wants to set a reminder for staff to update their contact details once a year.
- A church wants to display a list of all the dates for upcoming monthly worships on the last Sunday of the month.
- A training company holds the same event every 1st Wednesday of the month and doesn't want to duplicate the content for each event.
If you have any repeating dates in your entries, Timeloop is for you.
Requirements
This plugin requires Craft CMS 3.3.0 or later.
Using Timeloop
The Timeloop Model
Fetching dates (returned as DateTime objects)
Get the start date from the loop (this includes the time set in loopStartTime):
{{ entry.timeloop.loopStartDate | date('Y-m-d\\TH:i:sP') }}
Get the end date from the loop (this includes the time set in loopEndTime):
{{ entry.timeloop.loopEndDate | date('Y-m-d\\TH:i:sP') }}
Get the start time from the loop:
{{ entry.timeloop.loopStartTime | date('H:i:s') }}
Get the end time from the loop:
{{ entry.timeloop.loopEndTime | date('H:i:s') }}
Get an 'array' of dates between the chosen start and end date as (DateTime objects):
{% for date in entry.timeloop.dates %}
{{ date | date('Y-m-d\\TH:i:sP') }}
{% endfor %}
This generated set of dates takes all the field values into consideration (frequency, cycle and custom settings)
Upcoming Dates (returned as DateTime Objects)
Get the first upcoming date. If there is no upcoming date the returned value will be false:
{{ entry.timeloop.upcoming ? entry.timeloop.upcoming | date('Y-m-d\\TH:i:sP') : 'no upcoming date' }}
Get the date that is following the first upcoming date. If there is no nextUpcoming date the returned value will be false:
{{ entry.timeloop.nextUpcoming ? entry.timeloop.nextUpcoming | date('Y-m-d\\TH:i:sP') : 'no next upcoming date' }}
Period Model
Get the frequency of the period (e.g. P2D, P1W, P4M, ...) as (DateTimePeriod String):
{{ entry.timeloop.period.frequency }}
Get the set cycle for the frequency (e.g. 1, 4, 8) as (Integer):
{{ entry.timeloop.period.cycle }}
Display the selected days if the frequency is set to weekly as (Array):
{% for day in entry.timeloop.period.days %}
{{ day }}
{% endfor %}
The above will parse the names of the selected days when weekly has been chosen as frequency.
Timestring Model
Get the ordinal of a monthly set loop (e.g. first, second, ..., last)
warning: If the chosen frequency is not monthly, the returned value will be null.
warning: If the frequency is set to monthly and no timestring selection has been made, the returned value will be none as (String).
{{ entry.timeloop.timestring.ordinal ?? 'not set' }}
Reminder Model
Get a reminder before the recurring date occurs (DateTime)
{{ entry.timeloop.reminder | date('Y-m-d\\TH:i:sP') }}
GraphQL
If you want to use the plugin through GraphQL, we've added a custom GraphQL Type to provide the field data.
You can get the DateTime Types from the data directly for:
loopStartDatewill return the start date.loopStartTimewill return the start time, defaults to00:00:00when no start time has been entered orshowTimesis set to false.loopEndDatewill return the end date.loopEndTimewill return the end time, defaults to23:59:59when no end time has been entered orshowTimesis set to false.loopReminderwill return the reminder for the first upcoming date, if any.
Loop Period
You can get the loopPeriod object in the query as follows:
loopPeriod {
frequency
cycle
days
timestring {
ordinal
day
}
}
frequencywill return the chosen frequency (P1D / P1W / P1M / P1Y).cyclewill return the entered cycle value.dayswill return an array that contains the selected days of the week as string.timestringwill return an object that contains theordinal(e.g. last) andday(e.g. Saturday) values.
The Dates
To get an array of formatted dates, use dates.
Dates arguments:
limit(Integer): add a limit of dates you want to return, defaults to100.futureDates(Boolean): if you want to show future dates only, defaults totrue.
Dates directives:
formatDateTime(timezone: "Europe/London" format: "d/m/Y")
query{
entries(section: "section"){
id,
...on section_section_Entry {
dateCreated,
title,
timeloop {
loopReminder
loopStartDate
loopStartTime
loopEndDate
loopEndTime
loopPeriod {
frequency
cycle
days
}
getDates(limit: 10, futureDates: false)
getReminder
getUpcoming
getNextUpcoming
}
}
}
}
Timeloop Roadmap
Features for the future:
- Add controllers to be used for a cronjob or other automated tasks.
- Make the field translatable.
- Provide language translations.
- Add the possibility to blacklist dates (e.g. do not repeat the dates during July/August).
- Add holiday settings (Bank holidays to take into consideration when displaying upcoming dates).
- Localise holidays based on the Craft CMS timezone settings.
And many more!
Brought to you by CraftPulse
Standard
Plus $9/year after one year.
To install this plugin, copy the command above to your terminal.
This plugin doesn't have any reviews.


