/** * Creates the schema.org event meta data ouput. * * This is hooked to the btb_create_event_schema_org filter. * * @param string $input The input string to which the output is appended. * @param BTB_Event $event The event for which the meta data should be generated. * @param array $times Array of BTB_Time objects for the event. * @param BTB_Venue $venue The venue the event will happen. * @return string */ public static function event_schema_org_filter($input, BTB_Event $event, array $times, $venue) { $out = $input; $description = btb_get_event_description($event, true); $eventurl = btb_get_description_page($event, true); $info_page = (int) get_option('btb_struct_data_orga_info_page', ''); if ($info_page) { $organizer = array('@type' => 'Organization', 'url' => get_permalink($info_page)); } $event_images = btb_get_event_images($event); $eligible_regions = get_option('btb_struct_data_eligible_regions', array()); if ($event->struct_data_type == 'event' && $venue && $times) { $eventLocation = array('@type' => 'Place'); $eventLocation["name"] = $venue->name; if ($venue->use_map_coords) { $geo = array('@type' => 'GeoCoordinates'); $geo["latitude"] = $venue->latitude; $geo["longitude"] = $venue->longitude; $eventLocation["geo"] = $geo; } $elAddress = array('@type' => 'PostalAddress'); if (!empty($venue->streetAndNumber())) { $elAddress["streetAddress"] = $venue->streetAndNumber(); } if (!empty($venue->postal_code)) { $elAddress["postalCode"] = $venue->postal_code; } if (!empty($venue->region)) { $elAddress["addressRegion"] = $venue->region; } if (!empty($venue->city)) { $elAddress["addressLocality"] = $venue->city; } if (!empty($venue->country)) { $elAddress["addressCountry"] = $venue->country; } if (count($elAddress) > 1) { $eventLocation["address"] = $elAddress; } foreach ($times as $key => $time) { $out .= "\n<script type='application/ld+json'>\n"; $schema = array('@context' => 'http://schema.org', '@type' => $event->event_type); $schema["name"] = $event->name; if (!empty($organizer)) { $schema["organizer"] = $organizer; } $schema["startDate"] = $time->date_only ? date('Y-m-d', $time->start) : date('c', $time->start); if ($time->end > $time->start) { $schemaEvent["endDate"] = $time->date_only ? date('Y-m-d', $time->end) : date('c', $time->end); } if ($description) { $schema['description'] = $description; } $schema["url"] = $eventurl; if (!empty($event_images)) { $full_img = $event_images['full']; $event_image = array('@type' => 'ImageObject'); $event_image['contentUrl'] = esc_url($full_img[0]); $event_image['width'] = array('@type' => 'QuantitativeValue', 'value' => $full_img[1], 'unitText' => 'px'); $event_image['height'] = array('@type' => 'QuantitativeValue', 'value' => $full_img[2], 'unitText' => 'px'); $thumb_img = $event_images['thumbnail']; $event_thumbnail = array('@type' => 'ImageObject'); $event_thumbnail['contentUrl'] = esc_url($thumb_img[0]); $event_thumbnail['width'] = array('@type' => 'QuantitativeValue', 'value' => $thumb_img[1], 'unitText' => 'px'); $event_thumbnail['height'] = array('@type' => 'QuantitativeValue', 'value' => $thumb_img[2], 'unitText' => 'px'); $event_image['thumbnail'] = $event_thumbnail; $schema['image'] = $event_image; } $eventOffer = array('@type' => 'Offer'); $eventOffer["price"] = number_format($time->price ? $time->price : $event->price, 2, '.', ''); $eventOffer["priceCurrency"] = get_option('btb_currency_code', 'EUR'); $eventOffer["url"] = get_permalink(); $eventOffer["inventoryLevel"] = $time->free_slots; $eventOffer["availability"] = $time->free_slots ? "http://schema.org/InStock" : "http://schema.org/OutOfStock"; if ($eligible_regions) { if (is_array($eligible_regions) && !empty($eligible_regions)) { $eventOffer['eligibleRegion'] = $eligible_regions; } } $schema["offers"] = $eventOffer; $schema["location"] = $eventLocation; $out .= json_encode($schema); $out .= "\n</script>\n"; } } elseif ($event->struct_data_type == 'product' || $event->struct_data_type == 'event' && !$venue || $event->struct_data_type == 'event' && !$times) { $out .= "\n<script type='application/ld+json'>\n"; $schema = array('@context' => 'http://schema.org', '@type' => 'Product'); $schema["name"] = $event->name; $schema["mainEntityOfPage"] = $eventurl; if ($description) { $schema['description'] = $description; } $schema["url"] = $eventurl; if (!empty($event_images)) { $full_img = $event_images['full']; $event_image = array('@type' => 'ImageObject'); $event_image['contentUrl'] = esc_url($full_img[0]); $event_image['width'] = array('@type' => 'QuantitativeValue', 'value' => $full_img[1], 'unitText' => 'px'); $event_image['height'] = array('@type' => 'QuantitativeValue', 'value' => $full_img[2], 'unitText' => 'px'); $thumb_img = $event_images['thumbnail']; $event_thumbnail = array('@type' => 'ImageObject'); $event_thumbnail['contentUrl'] = esc_url($thumb_img[0]); $event_thumbnail['width'] = array('@type' => 'QuantitativeValue', 'value' => $thumb_img[1], 'unitText' => 'px'); $event_thumbnail['height'] = array('@type' => 'QuantitativeValue', 'value' => $thumb_img[2], 'unitText' => 'px'); $event_image['thumbnail'] = $event_thumbnail; $schema['image'] = $event_image; } $priceHigh = 0; $priceLow = 0; if ($times) { // extract the prices for each time $prices = array(); $free_slots = 0; foreach ($times as $key => $time) { $prices[] = $time->price ? $time->price : $event->price; $free_slots = $free_slots + $time->free_slots; } // sort the prices to determine highes and lowest price, if any sort($prices, SORT_NUMERIC); $priceHigh = end($prices); $priceLow = reset($prices); } // if there are different prices, use AggregateOffer otherwise Offer if ($priceHigh != $priceLow) { $offers = array('@type' => 'AggregateOffer'); $offers['lowPrice'] = number_format($priceLow, 2, '.', ''); $offers['highPrice'] = number_format($priceHigh, 2, '.', ''); } else { $offers = array('@type' => 'Offer'); $offers['price'] = $times ? number_format($priceLow, 2, '.', '') : number_format($event->price, 2, '.', ''); } $offers['priceCurrency'] = get_option('btb_currency_code', 'EUR'); $offers['url'] = get_permalink(); if ($times) { $offers["inventoryLevel"] = $free_slots; $offers["availability"] = $free_slots ? "http://schema.org/InStock" : "http://schema.org/OutOfStock"; } if (!empty($organizer)) { $offers["offeredBy"] = $organizer; } if ($eligible_regions) { if (is_array($eligible_regions) && !empty($eligible_regions)) { $offers['eligibleRegion'] = $eligible_regions; } } $schema['offers'] = $offers; $out .= json_encode($schema); $out .= "\n</script>\n"; } return $out; }
/** * Sends e-mails to customer and wordpress owner. * * @param BTB_Booking &$booking The booking object to send mails for. * @return int 1 if successfull, 0 if mail to owner failed, -1 if mail to customer failed, -2 if both mails failed */ private static function send_mails(&$booking) { $notifyemail = get_option('btb_notify_to', ''); // email address of the site owne to notify about new bookings $fromemail = get_option('btb_confirm_from', ''); // email address used as from address when sending booking to customer if (empty($notifyemail) && empty($fromemail)) { return -2; } $tags = array('{{salutation}}', '{{title}}', '{{first_name}}', '{{last_name}}', '{{company}}', '{{address}}', '{{address2}}', '{{zip}}', '{{city}}', '{{country}}', '{{mail}}', '{{phone}}', '{{notes}}', '{{event_name}}', '{{event_url}}', '{{event_start_date}}', '{{event_end_date}}', '{{event_start_time}}', '{{event_end_time}}', '{{slots}}', '{{single_price}}', '{{total_price}}', '{{booking_code}}', '{{booking_time}}'); if (get_option('btb_instance_type', 'master') == 'master') { $event = btb_get_event($booking->booked_event); $time = btb_get_time($booking->booked_time); } else { $event = btb_get_event_from_api($booking->booked_event, OBJECT, 'display'); $time = btb_get_time_from_api($booking->booked_time, OBJECT, 'display'); } date_default_timezone_set(get_option('timezone_string', 'UTC')); $replacements = array($booking->title == "mr" ? sprintf(__('Dear Mr. %s %s', 'bt-booking'), $booking->first_name, $booking->last_name) : sprintf(__('Dear Mrs. %s %s', 'bt-booking'), $booking->first_name, $booking->last_name), $booking->title == "mr" ? __('Mr.', 'bt-booking', 'bt-booking') : __('Mrs.', 'bt-booking'), $booking->first_name, $booking->last_name, $booking->company ? $booking->company : '', $booking->address, $booking->address2, $booking->zip, $booking->city, BTBookingCountries::get_country_by_code($booking->country), $booking->email, $booking->phone, $booking->notes, $event->name, btb_get_description_page($event, true), date_i18n(_x('m/d/Y', 'Event date shown in e-mails', 'bt-booking'), $time->start), date_i18n(_x('m/d/Y', 'Event date shown in e-mails', 'bt-booking'), $time->end), $time->date_only ? '' : date_i18n(_x('h:iA', 'Event time shown in e-mails', 'bt-booking'), $time->start), $time->date_only ? '' : date_i18n(_x('h:iA', 'Event time shown in e-mails', 'bt-booking'), $time->end), $booking->booked_slots, get_option('btb_currency', '€') . ' ' . number_format_i18n($booking->price, 2), get_option('btb_currency', '€') . ' ' . number_format_i18n($booking->price * $booking->booked_slots, 2), $booking->code, date_i18n(_x('m/d/Y h:iA', 'Booking time shown in e-mails', 'bt-booking'), $booking->booking_time)); $ret = 1; if (!empty($notifyemail) && !empty($fromemail)) { if (!self::send_mail_to_owner($tags, $replacements, $notifyemail, $fromemail, $booking)) { $ret = 0; } } else { $ret = 0; } if (!empty($fromemail)) { if (!self::send_mail_to_customer($tags, $replacements, $booking, $fromemail)) { $ret = $ret - 2; } } else { $ret = $ret - 2; } return $ret; }
/** * @brief Returns the full or short description of an event. * * Tries to find a description at first in the event itself, if that is empty and * the event has a description page, it searches for a description in the description * page. * * If @a $short_desc is true, the short description (excerpt) is returned. If you the * source for the meta description is set to something else than default in the plugin * settings, this source is used for the short description. * * @param BTB_Event $event The event to request the description for. * @param bool $short_desc If true, the short description (excerpt) will be returned. * * @return string The description or an empty string. */ function btb_get_event_description(BTB_Event &$event, $short_desc = false) { if ($short_desc) { $descsrc = get_option('btb_struct_data_src_desc', 'default'); if ($descsrc == 'default') { if (!empty($event->short_desc)) { return $event->short_desc; } else { $desc_page = btb_get_description_page($event); if ($desc_page != $event->ID) { $dp = get_post($desc_page); return $dp->post_excerpt; } else { return ''; } } } elseif ($descsrc == 'yoastseo') { $desc = get_post_meta($event->ID, '_yoast_wpseo_metadesc', true); if ($desc) { return $desc; } else { $desc_page = btb_get_description_page($event); if ($desc_page) { $desc = get_post_meta($desc_page, '_yoast_wpseo_metadesc', true); if ($desc) { return $desc; } else { return ''; } } else { return ''; } } } } else { if (!empty($event->description)) { return $event->description; } else { $desc_page = btb_get_description_page($event); if ($desc_page != $event->ID) { $dp = get_post($desc_page); return $dp->post_content; } else { return ''; } } } }