From 67014d04e9de3bd917ce1b7a9f4649aa7f01fe40 Mon Sep 17 00:00:00 2001 From: Sergey Kotlov Date: Wed, 6 May 2020 14:28:24 +0100 Subject: [PATCH] * Improves the output of event dates * Adds `only_featured` parameter to `wsb_schedule` to show only featured workshops * Fixes an issue with incorrect workshop dates in some border cases * Adds two new shortcodes for `wsb_schedule`: `wsb_schedule_date` and `wsb_schedule_time` * Improves the output for timezone abbreviations which have no abbreviations (adds GMT before them) * Adds failed request logging with the ability to switch it off --- .../admin/includes/class-sidebar-field.php | 4 +- .../admin/includes/class-wsb-settings.php | 7 ++ workshop-butler/composer.json | 3 +- .../class-wsb-integration-upgrade.php | 14 +++- .../includes/class-wsb-options.php | 50 ++++++------- .../public/class-wsb-integration-public.php | 2 + .../public/includes/class-sidebar-widget.php | 46 ++++++------ .../public/includes/class-wsb-requests.php | 25 ++++++- .../public/includes/models/class-event.php | 9 +++ .../public/includes/models/class-schedule.php | 6 ++ .../shortcodes/class-wsb-event-page.php | 3 + .../class-wsb-registration-page.php | 3 + .../shortcodes/class-wsb-schedule-page.php | 20 +++-- .../class-wsb-trainer-list-page.php | 2 +- .../public/includes/utils/log-error.php | 43 +++++++++++ .../includes/view/class-date-formatter.php | 73 ++++++++++++++++--- .../view/class-schedule-formatter.php | 63 ++++++++++++---- workshop-butler/readme.txt | 10 ++- workshop-butler/views/schedule/date.twig | 4 + workshop-butler/views/schedule/time.twig | 13 ++++ workshop-butler/workshop-butler.php | 4 +- 21 files changed, 316 insertions(+), 88 deletions(-) create mode 100644 workshop-butler/public/includes/utils/log-error.php create mode 100644 workshop-butler/views/schedule/date.twig create mode 100644 workshop-butler/views/schedule/time.twig diff --git a/workshop-butler/admin/includes/class-sidebar-field.php b/workshop-butler/admin/includes/class-sidebar-field.php index 4c4f11a..68a86fb 100644 --- a/workshop-butler/admin/includes/class-sidebar-field.php +++ b/workshop-butler/admin/includes/class-sidebar-field.php @@ -47,8 +47,8 @@ class Sidebar_Field { /** * Sidebar_Field constructor * - * @param string $type Type of the field. - * @param string $description Description of the field. + * @param string $type Type of the field. + * @param string $description Description of the field. * @param string|boolean|int|null $default_value Default value of the field. */ public function __construct( $type, $description, $default_value = null ) { diff --git a/workshop-butler/admin/includes/class-wsb-settings.php b/workshop-butler/admin/includes/class-wsb-settings.php index 4f08321..c4c0909 100644 --- a/workshop-butler/admin/includes/class-wsb-settings.php +++ b/workshop-butler/admin/includes/class-wsb-settings.php @@ -288,6 +288,13 @@ protected function get_general_settings() { 'desc' => __( 'Log in to Google Analytics to get your API key', 'wsbintegration' ), 'validation' => 'not_empty', ), + array( + 'id' => WSB_Options::REPORT_ERRORS, + 'type' => 'switch', + 'title' => 'Report failed requests', + 'desc' => 'When a request to Workshop Butler API fails, the plugin sends this information to our logging servers helping us to find the source of the problem faster. We do not collect any personal information, only detailed error reports.', + 'default' => true, + ), ); } diff --git a/workshop-butler/composer.json b/workshop-butler/composer.json index c80997b..5691461 100644 --- a/workshop-butler/composer.json +++ b/workshop-butler/composer.json @@ -3,7 +3,8 @@ "twig/twig": "1.34.4", "squizlabs/php_codesniffer": "3.5.3", "wp-coding-standards/wpcs": "2.2.0", - "dealerdirect/phpcodesniffer-composer-installer": "v0.5.0" + "dealerdirect/phpcodesniffer-composer-installer": "v0.5.0", + "ext-json": "*" }, "scripts": { "phpcs": "phpcs --standard=WordPress" diff --git a/workshop-butler/includes/class-wsb-integration-upgrade.php b/workshop-butler/includes/class-wsb-integration-upgrade.php index 33694c6..20fae8a 100644 --- a/workshop-butler/includes/class-wsb-integration-upgrade.php +++ b/workshop-butler/includes/class-wsb-integration-upgrade.php @@ -38,7 +38,8 @@ public function upgrade() { if ( empty( $new_key ) ) { $self->transfer_settings(); } - $self->update_templates_2_7_1(); + $self->update_templates(); + $self->update_settings(); $self->save_internal_settings( $self->get_version() ); $event_page = WSB_Options::get_option( WSB_Options::EVENT_PAGE ); @@ -66,10 +67,19 @@ public function upgrade() { } } + /** + * Updates selected settings + */ + protected function update_settings() { + if ( $this->get_version() && $this->get_version() < '2.11.0' ) { + WSB_Options::set_option( WSB_Options::REPORT_ERRORS, true ); + } + } + /** * Updates the classes that changed in version 2.7.1 for all related pages */ - protected function update_templates_2_7_1() { + protected function update_templates() { if ( $this->get_version() && $this->get_version() < '2.7.1' ) { $this->update_classes_2_7_1( WSB_Options::EVENT_TEMPLATE ); $this->update_classes_2_7_1( WSB_Options::TRAINER_TEMPLATE ); diff --git a/workshop-butler/includes/class-wsb-options.php b/workshop-butler/includes/class-wsb-options.php index 8108ddd..b08d283 100644 --- a/workshop-butler/includes/class-wsb-options.php +++ b/workshop-butler/includes/class-wsb-options.php @@ -10,8 +10,7 @@ namespace WorkshopButler; -if ( ! class_exists( 'ReduxFramework' ) - && file_exists( dirname( __FILE__ ) . '/../lib/ReduxFramework/ReduxCore/framework.php' ) ) { +if ( ! class_exists( 'ReduxFramework' ) && file_exists( dirname( __FILE__ ) . '/../lib/ReduxFramework/ReduxCore/framework.php' ) ) { require_once dirname( __FILE__ ) . '/../lib/ReduxFramework/ReduxCore/framework.php'; } @@ -25,44 +24,45 @@ */ class WSB_Options { - const OLD_API_KEY = 'wb_token'; + const OLD_API_KEY = 'wb_token'; const OLD_SCHEDULE_PAGE = 'wb_url'; - const PLUGIN_SETTINGS = 'wsb-settings'; + const PLUGIN_SETTINGS = 'wsb-settings'; const INTERNAL_SETTINGS = 'wsb-internal-settings'; - const INT_STATE = '_state'; - const INT_VERSION = '_version'; + const INT_STATE = '_state'; + const INT_VERSION = '_version'; const INT_TEMPLATE_VERSION = '_tmpl_version'; const API_KEY = 'api-key'; - const SCHEDULE_TILE_TEMPLATE = 'schedule-tile-template'; + const SCHEDULE_TILE_TEMPLATE = 'schedule-tile-template'; const SCHEDULE_TABLE_TEMPLATE = 'schedule-table-template'; - const EVENT_TEMPLATE = 'event-template'; - const REGISTRATION_TEMPLATE = 'registration-template'; - const TRAINER_LIST_TEMPLATE = 'trainer-list-template'; - const TRAINER_TEMPLATE = 'trainer-template'; + const EVENT_TEMPLATE = 'event-template'; + const REGISTRATION_TEMPLATE = 'registration-template'; + const TRAINER_LIST_TEMPLATE = 'trainer-list-template'; + const TRAINER_TEMPLATE = 'trainer-template'; const CUSTOM_CSS = 'custom-css'; - const THEME = 'theme'; - const CUSTOM_THEME = 'custom-theme'; - const GA_API_KEY = 'google-analytics-key'; - - const CUSTOM_EVENT_DETAILS = 'custom-event-page'; - const SHOW_EXPIRED_TICKETS = 'show-expired-tickets'; - const SHOW_NUMBER_OF_TICKETS = 'show-number-of-tickets'; - const SCHEDULE_NO_EVENTS = 'no-events-caption'; - const SCHEDULE_LAYOUT = 'event-list-layout'; - const SCHEDULE_PAGE = 'event-list-page-id'; - const EVENT_PAGE = 'event-page-id'; + const THEME = 'theme'; + const CUSTOM_THEME = 'custom-theme'; + const GA_API_KEY = 'google-analytics-key'; + const REPORT_ERRORS = 'report-errors'; + + const CUSTOM_EVENT_DETAILS = 'custom-event-page'; + const SHOW_EXPIRED_TICKETS = 'show-expired-tickets'; + const SHOW_NUMBER_OF_TICKETS = 'show-number-of-tickets'; + const SCHEDULE_NO_EVENTS = 'no-events-caption'; + const SCHEDULE_LAYOUT = 'event-list-layout'; + const SCHEDULE_PAGE = 'event-list-page-id'; + const EVENT_PAGE = 'event-page-id'; const EVENT_PAGE_SIDEBAR_TYPE = 'event-page-sidebar-type'; const EVENT_PAGE_SIDEBAR_SIZE = 'event-page-sidebar-size'; - const REGISTRATION_PAGE = 'registration-page-id'; + const REGISTRATION_PAGE = 'registration-page-id'; - const TRAINER_MODULE = 'trainer-module'; - const TRAINER_LIST_PAGE = 'trainer-list-page-id'; + const TRAINER_MODULE = 'trainer-module'; + const TRAINER_LIST_PAGE = 'trainer-list-page-id'; const TRAINER_PROFILE_PAGE = 'trainer-page-id'; /** diff --git a/workshop-butler/public/class-wsb-integration-public.php b/workshop-butler/public/class-wsb-integration-public.php index 557e56a..97d0005 100644 --- a/workshop-butler/public/class-wsb-integration-public.php +++ b/workshop-butler/public/class-wsb-integration-public.php @@ -256,6 +256,8 @@ public function init() { add_shortcode( 'wsb_trainer', array( 'WorkshopButler\WSB_Trainer_Page', 'page' ) ); // Elements. + add_shortcode( 'wsb_schedule_date', array( 'WorkshopButler\WSB_Schedule_Page', 'tag' ) ); + add_shortcode( 'wsb_schedule_time', array( 'WorkshopButler\WSB_Schedule_Page', 'tag' ) ); add_shortcode( 'wsb_schedule_filters', array( 'WorkshopButler\WSB_Schedule_Page', 'tag' ) ); add_shortcode( 'wsb_schedule_item', array( 'WorkshopButler\WSB_Schedule_Page', 'tag' ) ); add_shortcode( 'wsb_schedule_register', array( 'WorkshopButler\WSB_Schedule_Page', 'tag' ) ); diff --git a/workshop-butler/public/includes/class-sidebar-widget.php b/workshop-butler/public/includes/class-sidebar-widget.php index 6ef99ac..9485d5e 100644 --- a/workshop-butler/public/includes/class-sidebar-widget.php +++ b/workshop-butler/public/includes/class-sidebar-widget.php @@ -92,25 +92,25 @@ public function form( $instance ) { case 'eventtype': ?> -

- - -

+

+ + +

-

- - -

- + + +

+ 'future', - 'public' => true, - 'fields' => $fields, + 'dates' => 'future', + 'public' => true, + 'fields' => $fields, 'per_page' => $instance['length'], ); @@ -207,7 +207,7 @@ public function render( $instance ) { */ private function render_list( $response, $instance ) { if ( $response->is_error() ) { - $html = '

' . __( 'Workshop Butler API: Request failed', 'wsbintegration' ) . '

'; + $html = '

' . __( 'Workshop Butler API: Request failed', 'wsbintegration' ) . '

'; $html .= '

' . __( 'Reason : ', 'wsbintegration' ) . $response->error . '

'; return $html; @@ -226,10 +226,10 @@ private function render_list( $response, $instance ) { $target = ' target="_blank" '; } $events .= '
  • ' . - Formatter::format( $event->schedule, 'full_short' ) . ', ' . - Formatter::format( $event->location ) . '
    ' . - '' . - $event->title . '
  • '; + Formatter::format( $event->schedule, 'full_short' ) . ', ' . + Formatter::format( $event->location ) . '
    ' . + '' . + $event->title . ''; } $events .= ''; diff --git a/workshop-butler/public/includes/class-wsb-requests.php b/workshop-butler/public/includes/class-wsb-requests.php index 87088e5..25545da 100644 --- a/workshop-butler/public/includes/class-wsb-requests.php +++ b/workshop-butler/public/includes/class-wsb-requests.php @@ -15,6 +15,7 @@ define( 'WSB_API_END_POINT', 'https://api.workshopbutler.com/' ); require_once plugin_dir_path( __FILE__ ) . 'class-wsb-response.php'; +require_once plugin_dir_path( __FILE__ ) . 'utils/log-error.php'; /** * The request wrapper class @@ -82,8 +83,10 @@ public function get( $method, $query ) { 'referer' => $this->get_referer(), ), ); + $resp = wp_remote_get( $url, $args ); + $this->report_error( $resp, $query, $method ); - return new WSB_Response( wp_remote_get( $url, $args ) ); + return new WSB_Response( $resp ); } /** @@ -113,6 +116,7 @@ public function post( $method, $data ) { 'body' => $data_string, ) ); + $this->report_error( $resp, $data, $method ); return new WSB_Response( $resp ); } @@ -215,4 +219,23 @@ protected function build_url( $method, $query ) { protected function get_referer() { return filter_input( INPUT_SERVER, 'HTTP_HOST' ) . filter_input( INPUT_SERVER, 'REQUEST_URI' ); } + + /** + * If there is a error in response, report it to Workshop Butler + * + * @param array|WP_Error $resp Response. + * @param array $data Method data. + * @param string $method Method type (POST, GET). + */ + protected function report_error( $resp, $data, $method ) { + if ( is_a( $resp, 'WP_Error' ) ) { + $error_data = array(); + $error_data['data'] = $data; + $error_data['method'] = $method; + $error_data['code'] = $resp->get_error_code(); + $error_data['message'] = $resp->get_error_message(); + $error_data['errors'] = $resp->get_error_data(); + log_error( 'WSB_Requests', $method, $error_data ); + } + } } diff --git a/workshop-butler/public/includes/models/class-event.php b/workshop-butler/public/includes/models/class-event.php index 9051bf0..cb65b07 100644 --- a/workshop-butler/public/includes/models/class-event.php +++ b/workshop-butler/public/includes/models/class-event.php @@ -154,6 +154,14 @@ class Event { */ public $description; + /** + * True if the event is featured. + * + * @var boolean $featured + * @since 2.11.0 + */ + public $featured; + /** * Registration form * @@ -246,6 +254,7 @@ public function __construct( $json_data, $event_page_url, $trainer_page_url, $re $this->trainers = $this->get_trainers( $json_data, $trainer_page_url ); $this->state = new Event_State( $this ); $this->payment = Payment::from_json( $json_data->card_payment ); + $this->featured = $json_data->featured; } /** diff --git a/workshop-butler/public/includes/models/class-schedule.php b/workshop-butler/public/includes/models/class-schedule.php index ce7b111..14ada11 100644 --- a/workshop-butler/public/includes/models/class-schedule.php +++ b/workshop-butler/public/includes/models/class-schedule.php @@ -51,6 +51,11 @@ public function __construct( $json_data ) { } $this->start = new \DateTime( $json_data->start ); $this->end = new \DateTime( $json_data->end ); + if ( $this->timezone ) { + $timezone = new \DateTimeZone( $this->timezone ); + $this->start->setTimezone( $timezone ); + $this->end->setTimezone( $timezone ); + } } /** @@ -62,6 +67,7 @@ public function ended() { $now = new \DateTime( 'now', $this->default_timezone() ); $end = clone $this->end; $end->setTimezone( $this->default_timezone() ); + return $end < $now; } diff --git a/workshop-butler/public/includes/shortcodes/class-wsb-event-page.php b/workshop-butler/public/includes/shortcodes/class-wsb-event-page.php index e7141bb..41b0079 100644 --- a/workshop-butler/public/includes/shortcodes/class-wsb-event-page.php +++ b/workshop-butler/public/includes/shortcodes/class-wsb-event-page.php @@ -11,6 +11,7 @@ namespace WorkshopButler; require_once plugin_dir_path( dirname( __FILE__ ) ) . 'class-wsb-page.php'; +require_once plugin_dir_path( dirname( __FILE__ ) ) . 'utils/log-error.php'; /** * Event Page class which handles the rendering and logic for the event page @@ -63,6 +64,8 @@ private function load_dependencies() { public function render( $attrs = array(), $content = null ) { $id = get_query_var( 'id', 0 ); if ( 0 === $id ) { + log_error( 'WSB_Event_Page', 'Incorrect workshop ID', array() ); + return $this->format_error( 'Incorrect workshop ID' ); } $may_be_event = $this->dict->get_event(); diff --git a/workshop-butler/public/includes/shortcodes/class-wsb-registration-page.php b/workshop-butler/public/includes/shortcodes/class-wsb-registration-page.php index ec8ec18..aa58fc1 100644 --- a/workshop-butler/public/includes/shortcodes/class-wsb-registration-page.php +++ b/workshop-butler/public/includes/shortcodes/class-wsb-registration-page.php @@ -11,6 +11,7 @@ namespace WorkshopButler; require_once plugin_dir_path( dirname( __FILE__ ) ) . 'class-wsb-page.php'; +require_once plugin_dir_path( dirname( __FILE__ ) ) . 'utils/log-error.php'; /** * Event Page class which handles the rendering and logic for the event page @@ -84,6 +85,8 @@ private function load_dependencies() { public function render( $attrs = array(), $content = null ) { $id = get_query_var( 'id', 0 ); if ( 0 === $id ) { + log_error( 'WSB_Registration_Page', 'Incorrect workshop ID', array() ); + return $this->format_error( 'Incorrect workshop ID' ); } $may_be_event = $this->dict->get_event(); diff --git a/workshop-butler/public/includes/shortcodes/class-wsb-schedule-page.php b/workshop-butler/public/includes/shortcodes/class-wsb-schedule-page.php index 3028c93..6fcf705 100644 --- a/workshop-butler/public/includes/shortcodes/class-wsb-schedule-page.php +++ b/workshop-butler/public/includes/shortcodes/class-wsb-schedule-page.php @@ -99,10 +99,11 @@ public function render_page( $attrs = array(), $content = null ) { private function get_attrs( $attrs ) { $defaults = array( - 'category' => null, - 'event_type' => null, - 'layout' => $this->settings->get( WSB_Options::SCHEDULE_LAYOUT, 'table' ), - 'wrapper' => false, + 'category' => null, + 'event_type' => null, + 'layout' => $this->settings->get( WSB_Options::SCHEDULE_LAYOUT, 'table' ), + 'wrapper' => false, + 'only_featured' => false, ); return shortcode_atts( $defaults, $attrs ); @@ -131,7 +132,9 @@ private function render_list( $response, $attrs, $content ) { $this->settings->get_trainer_page_url(), $this->settings->get_registration_page_url() ); - array_push( $events, $event ); + if ( ! $attrs['only_featured'] || $event->featured ) { + array_push( $events, $event ); + } } if ( 0 === count( $events ) ) { @@ -216,6 +219,11 @@ protected function get_default_attrs( $shortcode_name ) { case 'register': case 'table_register': return array( 'registration' => 'false' ); + case 'time': + return array( + 'timezone' => 'online', + 'timezone_format' => 'short', + ); case 'title': return array( 'truncate' => '60', @@ -251,7 +259,7 @@ protected function render_item( $attrs = array(), $content = null ) { $this->dict->set_event( $event ); $item_content = $this->compile_string( $content, array( 'event' => $event ) ); $processed_item_content = do_shortcode( $item_content ); - $html .= $this->compile_string( + $html .= $this->compile_string( $item_template, array( 'event' => $event, diff --git a/workshop-butler/public/includes/shortcodes/class-wsb-trainer-list-page.php b/workshop-butler/public/includes/shortcodes/class-wsb-trainer-list-page.php index 1c0f3f0..169ad4e 100644 --- a/workshop-butler/public/includes/shortcodes/class-wsb-trainer-list-page.php +++ b/workshop-butler/public/includes/shortcodes/class-wsb-trainer-list-page.php @@ -183,7 +183,7 @@ protected function render_trainer( $attrs = array(), $content = null ) { $this->dict->set_trainer( $trainer ); $item_content = $this->compile_string( $content, array( 'trainer' => $trainer ) ); $processed_item_content = do_shortcode( $item_content ); - $html .= $this->compile_string( + $html .= $this->compile_string( $item_template, array( 'trainer' => $trainer, diff --git a/workshop-butler/public/includes/utils/log-error.php b/workshop-butler/public/includes/utils/log-error.php new file mode 100644 index 0000000..aa538e0 --- /dev/null +++ b/workshop-butler/public/includes/utils/log-error.php @@ -0,0 +1,43 @@ + 'POST', + 'body' => json_encode( $params ), + ) + ); + } +} diff --git a/workshop-butler/public/includes/view/class-date-formatter.php b/workshop-butler/public/includes/view/class-date-formatter.php index 3b9b413..bdb7b7d 100644 --- a/workshop-butler/public/includes/view/class-date-formatter.php +++ b/workshop-butler/public/includes/view/class-date-formatter.php @@ -10,6 +10,8 @@ namespace WorkshopButler; +use DateTime; + /** * Formats a date * @@ -20,35 +22,69 @@ class Date_Formatter { /** * Removes the year from the date if the date is at the current year * - * @param \DateTime $date Date. - * @param bool $with_time True if the time should be added. + * @param DateTime $date Date. + * @param bool $with_time True if the time should be added. + * * @return string * @since 2.0.0 */ public static function format( $date, $with_time = false ) { - $formatted_date = date_i18n( self::get_date_format( $date ), $date->getTimestamp() ); + $formatted_date = date_i18n( self::get_date_format( $date ), self::get_timestamp_with_offset( $date ) ); $formatted_time = $with_time ? $date->format( get_option( 'time_format' ) ) : ''; + return trim( $formatted_date . ' ' . $formatted_time, '.,-/ ' ); } /** - * Shows start and end times for the event if it's at one day + * Returns time of the date. + * + * @param DateTime $date Date. + * + * @return string + * @since 2.11.0 + */ + public static function format_time( $date ) { + $formatted_time = $date->format( get_option( 'time_format' ) ); + + return trim( $formatted_time, '.,-/ ' ); + } + + /** + * Shows date + start and end times for the event if it's at one day + * + * @param DateTime $start_date Date. + * @param DateTime $end_date Date. * - * @param \DateTime $start_date Date. - * @param \DateTime $end_date Date. * @return string * @since 2.1.2 */ - public static function format_at_one_day_time( $start_date, $end_date ) { - $formatted_date = date_i18n( self::get_date_format( $start_date ), $start_date->getTimestamp() ); + public static function format_one_day( $start_date, $end_date ) { + $formatted_date = date_i18n( self::get_date_format( $start_date ), self::get_timestamp_with_offset( $start_date ) ); $formatted_time = $start_date->format( get_option( 'time_format' ) ) . '—' . $end_date->format( get_option( 'time_format' ) ); + return trim( $formatted_date . ' ' . $formatted_time, '.,-/ ' ); } + + /** + * Shows only start and end times for the event if it's at one day + * + * @param DateTime $start_date Date. + * @param DateTime $end_date Date. + * + * @return string + * @since 2.11.0 + */ + public static function format_one_day_time( $start_date, $end_date ) { + $formatted_time = $start_date->format( get_option( 'time_format' ) ) . '—' . $end_date->format( get_option( 'time_format' ) ); + + return trim( $formatted_time, '.,-/ ' ); + } + /** * Returns a date format (with year or without) for the given date * - * @param \DateTime $date Date. + * @param DateTime $date Date. * * @return string */ @@ -65,18 +101,33 @@ public static function get_date_format( $date ) { */ public static function is_textual_month() { $format = get_option( 'date_format' ); + return strpos( $format, 'F' ) !== false || strpos( $format, 'M' ) !== false; } /** * Returns true if the date is in the current year * - * @param \DateTime $date Date of interest. + * @param DateTime $date Date of interest. + * * @return boolean * @since 2.0.0 */ protected static function is_this_year( $date ) { - $now = new \DateTime( 'now', $date->getTimezone() ); + $now = new DateTime( 'now', $date->getTimezone() ); + return $now->format( 'Y' ) === $date->format( 'Y' ); } + + /** + * Returns timestamp with offset for the date. + * + * @param DateTime $date Date of interest. + * + * @return int + * @since 2.11.0 + */ + protected static function get_timestamp_with_offset( $date ) { + return $date->getTimestamp() + $date->getOffset(); + } } diff --git a/workshop-butler/public/includes/view/class-schedule-formatter.php b/workshop-butler/public/includes/view/class-schedule-formatter.php index fc9b37f..82f2662 100644 --- a/workshop-butler/public/includes/view/class-schedule-formatter.php +++ b/workshop-butler/public/includes/view/class-schedule-formatter.php @@ -23,10 +23,10 @@ class Schedule_Formatter { * Formats the schedule * * @param Schedule $schedule Schedule to format. - * @param string|null $type Additional format type. + * @param string|null $type Additional format type. * - * @since 2.0.0 * @return string + * @since 2.0.0 */ public static function format( $schedule, $type ) { $type = $type ? $type : 'full_long'; @@ -43,11 +43,9 @@ public static function format( $schedule, $type ) { case 'timezone_long': return $schedule->timezone ? $schedule->timezone : ''; case 'timezone_short': - $start = clone $schedule->start; - if ( $schedule->timezone ) { - $start->setTimezone( $schedule->default_timezone() ); - } - return $schedule->timezone ? $start->format( 'T' ) : ''; + return self::format_timezone( $schedule ); + case 'time': + return self::format_time( $schedule ); case 'full_short': return self::format_full_date( $schedule, false ); case 'full_long': @@ -61,23 +59,61 @@ public static function format( $schedule, $type ) { } } + /** + * Produces a formatted timezone for the schedule + * + * @param Schedule $schedule Schedule to format. + * + * @return string + * @since 2.11.0 + */ + protected static function format_timezone( $schedule ) { + $start = clone $schedule->start; + if ( $schedule->timezone ) { + $start->setTimezone( $schedule->default_timezone() ); + } + $abbreviation = $start->format( 'T' ); + if ( 0 === strpos( $abbreviation, '-' ) || 0 === strpos( $abbreviation, '+' ) ) { + $abbreviation = 'GMT' . $abbreviation; + } + + return $schedule->timezone ? $abbreviation : ''; + } + + /** + * Produces a formatted time for the schedule + * + * @param Schedule $schedule Schedule to format. + * + * @return string + * @since 2.11.0 + */ + protected static function format_time( $schedule ) { + if ( $schedule->at_one_day() ) { + return Date_Formatter::format_one_day_time( $schedule->start, $schedule->end ); + } else { + return Date_Formatter::format_time( $schedule->start ); + } + } + /** * Produces a formatted schedule in a full-date format * - * @param Schedule $schedule Schedule to format. + * @param Schedule $schedule Schedule to format. * @param boolean $with_time When true, the time is added. + * * @return string * @since 2.0.0 */ protected static function format_full_date( $schedule, $with_time ) { if ( $schedule->at_one_day() ) { if ( $with_time ) { - return Date_Formatter::format_at_one_day_time( $schedule->start, $schedule->end ); + return Date_Formatter::format_one_day( $schedule->start, $schedule->end ); } else { return Date_Formatter::format( $schedule->start ); } } elseif ( $schedule->start->format( 'Y' ) !== $schedule->end->format( 'Y' ) - || $schedule->start->format( 'm' ) !== $schedule->end->format( 'm' ) ) { + || $schedule->start->format( 'm' ) !== $schedule->end->format( 'm' ) ) { return Date_Formatter::format( $schedule->start ) . ' — ' . Date_Formatter::format( $schedule->end ); } else { return self::format_same_month_interval( $schedule->start, $schedule->end ); @@ -92,7 +128,8 @@ protected static function format_full_date( $schedule, $with_time ) { * - 19-20 April 2018 in Germany * * @param \DateTime $start Start of the workshop. - * @param \DateTime $end End of the workshop. + * @param \DateTime $end End of the workshop. + * * @return string * @since 2.0.0 */ @@ -100,8 +137,8 @@ protected static function format_same_month_interval( $start, $end ) { global $wp_locale; if ( Date_Formatter::is_textual_month() ) { - $numeric_days = $start->format( 'd' ) . '-' . $end->format( 'd' ); - $without_zero_ays = $start->format( 'j' ) . '-' . $end->format( 'j' ); + $numeric_days = $start->format( 'd' ) . '—' . $end->format( 'd' ); + $without_zero_ays = $start->format( 'j' ) . '—' . $end->format( 'j' ); if ( ( ! empty( $wp_locale->month ) ) ) { $textual_month = $wp_locale->get_month( date( 'm', $start->getTimestamp() ) ); diff --git a/workshop-butler/readme.txt b/workshop-butler/readme.txt index 51e0bdf..e78817a 100644 --- a/workshop-butler/readme.txt +++ b/workshop-butler/readme.txt @@ -2,7 +2,7 @@ Contributors: workshopbutlers Tags: event management, training management, event schedule, workshop crm, online registrations Requires at least: 4.6 -Tested up to: 5.3.0 +Tested up to: 5.4.1 Requires PHP: 5.3 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -68,6 +68,14 @@ Please, open an issue [here](https://github.com/workshopbutler/wordpress-plugin) Please, open an issue [here](https://github.com/workshopbutler/wordpress-plugin) == Changelog == += 2.11.0 = +* Improves the output of event dates +* Adds `only_featured` parameter to `wsb_schedule` to show only featured workshops +* Fixes an issue with incorrect workshop dates in some border cases +* Adds two new shortcodes for `wsb_schedule`: `wsb_schedule_date` and `wsb_schedule_time` +* Improves the output for timezone abbreviations which have no abbreviations (adds GMT before them) +* Adds failed request logging with the ability to switch it off + = 2.10.0 = * Fixes an issue with non-working registration form for free events * On the trainer's profile, the newest past events are shown, not the oldest ones diff --git a/workshop-butler/views/schedule/date.twig b/workshop-butler/views/schedule/date.twig new file mode 100644 index 0000000..e00e435 --- /dev/null +++ b/workshop-butler/views/schedule/date.twig @@ -0,0 +1,4 @@ +
    + {{ wsb_f(event.schedule, 'full_short') }} +
    diff --git a/workshop-butler/views/schedule/time.twig b/workshop-butler/views/schedule/time.twig new file mode 100644 index 0000000..a086ada --- /dev/null +++ b/workshop-butler/views/schedule/time.twig @@ -0,0 +1,13 @@ +
    + {{ wsb_f(event.schedule, 'time') }} + {% if timezone and event.schedule.timezone %} + {% if timezone == 'online' and event.location.online or timezone == 'all' %} + {% if timezone_format == 'long' %} + {{ wsb_f(event.schedule, 'timezone_long') }} + {% else %} + {{ wsb_f(event.schedule, 'timezone_short') }} + {% endif %} + {% endif %} + {% endif %} +
    diff --git a/workshop-butler/workshop-butler.php b/workshop-butler/workshop-butler.php index 076604c..7194df0 100644 --- a/workshop-butler/workshop-butler.php +++ b/workshop-butler/workshop-butler.php @@ -11,7 +11,7 @@ * Plugin URI: https://github.com/workshopbutler/wordpress-plugin * Description: This plugin integrates Workshop Butler Events, Trainers and Testimonials to your WordPress * website. - * Version: 2.10.0 + * Version: 2.11.0 * Author: Workshop Butler * Author URI: https://workshopbutler.com/ * License: GPL-2.0+ @@ -28,7 +28,7 @@ /** * Currently plugin version. */ -define( 'WSB_INTEGRATION_VERSION', '2.10.0' ); +define( 'WSB_INTEGRATION_VERSION', '2.11.0' ); /** * Version of Workshop Butler API, used by this plugin