* @copyright 2016 Kaleb Heitzman * @license https://opensource.org/licenses/MIT MIT * @version 1.1.0 * @link https://github.com/kalebheitzman/grav-plugin-events * @since 1.0.0 Initial Release */ class EventsPlugin extends Plugin { /** * Current Carbon DateTime * * @since 1.0.0 Initial Release * @var object Carbon DateTime */ protected $now; /** * Events/Events Class * * Processes pages for `event:` frontmatter and then inserts repeating and * reoccuring events into Grav Pages with updated dates, route, and path. * * @since 1.0.0 Initial Release * @var object Events */ protected $events; /** * Events/Calendar Class * * Provides data to be used in the `calendar.html.twig` template. * * @since 1.0.0 Initial Release * @var object Calendar */ protected $calendar; /** * Get Subscribed Events * * @since 1.0.0 Initial Release * @return array */ public static function getSubscribedEvents() { return [ 'onPluginsInitialized' => ['onPluginsInitialized', 0], 'onGetPageTemplates' => ['onGetPageTemplates', 0], 'onTwigExtensions' => ['onTwigExtensions', 0], ]; } /** * Initialize plugin configuration * * Determine if the plugin should run and set the custom * taxonomies to store event information in. We also initialize the Events * and Calendar class that this plugin utilizes and then we start * intercepting Grav hooks to build our events list and insert any vars * we need into the system. * * @since 1.0.0 Initial Release * @return void */ public function onPluginsInitialized() { // Nothing else is needed for admin so close it out if ( $this->isAdmin() ) { $this->enable([ 'onAdminSave' => ['onAdminSave', 0], ]); return; } // Add these to taxonomy for events management $event_taxonomies = array('type', 'event_freq', 'event_repeat', 'event_location'); $taxonomy_config = array_merge((array)$this->config->get('site.taxonomies'), $event_taxonomies); $this->config->set('site.taxonomies', $taxonomy_config); // get the current datetime with c $this->now = Carbon::now(); // set the calendar accessor $this->calendar = new \Events\CalendarProcessor(); // set the events accessor $this->events = new \Events\EventsProcessor(); // enable the following hooks $this->enable([ 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], 'onPagesInitialized' => ['onPagesInitialized', 0], 'onTwigSiteVariables' => ['onTwigSiteVariables', 0], ]); } /** * Add current directory to twig lookup paths. * * Add the templates directory to the twig directory look up path so we * can load our page templates. These are overridable by the theme and * are only meant as a starting point. * * @since 1.0.0 Initial Release * @return void */ public function onTwigTemplatePaths() { // add templates to twig path $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; } /** * Add repeating and reoccuring events as Grav pages * * Repeating Events: events the tile horizontally in a week `MTWRFSU` * Reoccuring Events: events that tile vertically through `daily, weekly, * monthly, yearly` * * The Events/Events class searches for pages with `event:` frontmatter and * processes these into new Grav pages as needed. This is a dynamic operation * and does not add new physical pages to the filesystem. * * @since 1.0.0 Initial Release * @return void */ public function onPagesInitialized() { // get instances of all events $this->events->all(); } /** * Association with page templates * * @param Event $event * @since 1.0.15 Major Refactor * @return void */ public function onGetPageTemplates(Event $event) { $types = $event->types; /* @var Locator $locator */ $locator = Grav::instance()['locator']; // Set blueprints & templates. $types->scanBlueprints($locator->findResource('plugin://events/blueprints')); $types->scanTemplates($locator->findResource('plugin://events/templates')); // reverse the FUBARd order of blueprints $event = array_reverse($types['event']); $types['event'] = $event; } /** * Set needed variables to display events * * For the calendar page, we load the appropriate js and css to make the * calendar work smoothly as well as add the appropriate calendar twig * variables. * * @since 1.0.0 Initial Release * @return void */ public function onTwigSiteVariables() { // setup $page = $this->grav['page']; $pages = $this->grav['pages']; $collection = $pages->all()->ofType('event'); $twig = $this->grav['twig']; $assets = $this->grav['assets']; /** @var Uri $uri */ $uri = $this->grav['uri']; $type = $uri->extension(); // only load the vars if calendar page if ($page->template() == 'calendar') { $yearParam = $this->grav['uri']->param('year'); $monthParam = $this->grav['uri']->param('month'); $twigVars = $this->calendar->twigVars($yearParam, $monthParam); $calVars = $this->calendar->calendarVars($collection); // add calendar to twig as calendar $twigVars['calendar']['events'] = $calVars; $twig->twig_vars['calendar'] = array_shift($twigVars); if ( $type == 'json' ) { $twig->twig_vars['calendarJson'] = $this->calendar->calendarVars($collection); } } // output on events if ( $page->template() == 'events' && $type == 'json' ) { $events = []; foreach($collection as $page) { $events[]['id'] = $page->id(); $events[]['title'] = $page->title(); $events[]['date'] = $page->date(); $events[]['header'] = $page->header(); $events[]['content'] = $page->content(); $events[]['summary'] = $page->summary(); $events[]['lang'] = $page->language(); $events[]['meta'] = $page->contentMeta(); $events[]['slug'] = $page->slug(); $events[]['permalink'] = $page->permalink(); } $twig->twig_vars['eventsJson'] = $events; } $twig->twig_vars['eventCategories'] = $this->events->getEventCategories(); // scripts $js = 'plugin://events/assets/events.min.js'; $assets->add('jquery'); $assets->addJs($js, 1); // styles $css = 'plugin://events/assets/events.min.css'; $assets->addCss($css); } /** * Process Event Information * * This hook fires a reverse geocoding hook for the location field * on single events. * * @param Event $event * @since 1.0.15 Location Field Update * @return void */ public function onAdminSave(Event $event) { $config = (array) $this->config->get('plugins.events'); // get the object being saved $obj = $event['object']; // check to see if the object is a `Page` with template `event` if ( $obj instanceof Page && $obj->template() == 'event' ) { // get the header $header = $obj->header(); // check for location information if ( isset( $header->event['location'] ) && ! isset( $header->event['coordinates'] ) ) { // leave if geocoding is disabled if ( ! $config['enable_geocoding'] ) { return; } $location = $header->event['location']; // build a url $url = "https://maps.googleapis.com/maps/api/geocode/json?address=" . urlencode($location) . "&key=" . $config['api_key']; // fetch the results $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $geoloc = json_decode(curl_exec($ch), true); foreach ( $geoloc['results'][0]['address_components'] as $address_component ) { if($address_component['types'][0] === 'country' && $address_component['types'][1] === 'political') { $header->event['country'] = $address_component['long_name']; } if($address_component['types'][0] === 'locality' && $address_component['types'][1] === 'political') { $header->event['city'] = $address_component['long_name']; } if($address_component['types'][0] === 'postal_code') { $header->event['zip'] = $address_component['long_name']; } } // build the coord string $lat = $geoloc['results'][0]['geometry']['location']['lat']; $lng = $geoloc['results'][0]['geometry']['location']['lng']; $coords = $lat . ", " . $lng; // set the header info $header->event['coordinates'] = $coords; $obj->header($header); } } else // the saved object was not a page, so it was likely the plugin settings { $update_mode = $event['object']["icalendar_update"]; if($update_mode != 0) { // process iCalendar file(s) $icalendar = new \Events\iCalendarProcessor(); $icalendar->process($update_mode-1); // reset flag $event['object']["icalendar_update"] = 0; } } } /** * Association with twig extensions * * @since 1.1 * @return void */ public function onTwigExtensions() { require_once(__DIR__ . '/twig/DateTranslationExtension.php'); $this->grav['twig']->twig->addExtension(new DateTranslationExtension($this->grav)); } }