From 44daeb5b59adde0a3337f2d2765e7e18a123e9a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Fri, 6 Dec 2024 18:27:07 +0100 Subject: [PATCH] Add the possibility to compose a custom event summary via shortcodes (#80) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the option to compose a custom summary via shortcodes. ToDo: - [x] Integretion-Tests (covering text-only and complex addresses) - [x] Remove duplicated code - [x] Evaluate move shortcodes to Base Event transformer - [x] Commennts - [x] Readability/Maintenability - [x] Explain shortcodes and usage in Admin UI Reviewed-on: https://code.event-federation.eu/Event-Federation/wordpress-event-bridge-for-activitypub/pulls/80 Co-authored-by: André Menrath Co-committed-by: André Menrath --- .forgejo/workflows/phpunit.yml | 5 + CHANGELOG.md | 6 + README.md | 6 + .../event-bridge-for-activitypub-admin.css | 8 + .../js/event-bridge-for-activitypub-admin.js | 20 ++ composer.json | 3 +- event-bridge-for-activitypub.php | 4 +- .../transformer/class-event-organiser.php | 6 +- .../activitypub/transformer/class-event.php | 258 ++++++++++++++++-- .../transformer/class-eventprime.php | 6 +- .../transformer/class-gatherpress.php | 4 +- .../transformer/class-the-events-calendar.php | 4 +- .../transformer/class-vs-event-list.php | 4 +- includes/class-settings.php | 22 ++ templates/settings.php | 46 ++++ tests/bootstrap.php | 28 +- ...ss-activitypub-event-bridge-shortcodes.php | 193 +++++++++++++ 17 files changed, 581 insertions(+), 42 deletions(-) create mode 100644 tests/test-class-activitypub-event-bridge-shortcodes.php diff --git a/.forgejo/workflows/phpunit.yml b/.forgejo/workflows/phpunit.yml index b695aff..5f300c7 100644 --- a/.forgejo/workflows/phpunit.yml +++ b/.forgejo/workflows/phpunit.yml @@ -75,6 +75,11 @@ jobs: if: steps.cache-wordpress.outputs.cache-hit != 'false' run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wordpress-version }} false true true true + - name: Run General Tests + run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=event_bridge_for_activitypub + env: + PHP_VERSION: ${{ matrix.php-version }} + - name: Run Integration tests for The Events Calendar run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=the_events_calendar env: diff --git a/CHANGELOG.md b/CHANGELOG.md index dd83e8e..870d722 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Unreleased + +### Added + +* Add custom summary via shortcodes + ## [0.3.1] - 2024-11-16 * Initial release on WordPress.org diff --git a/README.md b/README.md index e52e4a8..f61876b 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,12 @@ We're always interested in your feedback. Feel free to reach out to us via [E-Ma ## Changelog ## +### Unreleased + +#### Added + +* Add custom summary via shortcodes + ### [0.3.1] 2024-12-05 ### * Initial release on https://wordpress.org/ diff --git a/assets/css/event-bridge-for-activitypub-admin.css b/assets/css/event-bridge-for-activitypub-admin.css index 27e164a..6c62d22 100644 --- a/assets/css/event-bridge-for-activitypub-admin.css +++ b/assets/css/event-bridge-for-activitypub-admin.css @@ -177,3 +177,11 @@ code.event-bridge-for-activitypub-settings-example-url { overflow-x: auto; word-break: break-all; } + +#event_bridge_for_activitypub_summary_type_custom-details { + display: none; +} + +#event_bridge_for_activitypub_summary_type_custom-details > details { + padding: 0.5em; +} diff --git a/assets/js/event-bridge-for-activitypub-admin.js b/assets/js/event-bridge-for-activitypub-admin.js index d2eb9ea..93c64e3 100644 --- a/assets/js/event-bridge-for-activitypub-admin.js +++ b/assets/js/event-bridge-for-activitypub-admin.js @@ -11,4 +11,24 @@ jQuery( function( $ ) { $( '#' + $( this ).attr( 'aria-controls' ) ).attr( 'hidden', false ); } } ); + + // Function to toggle visibility of custom details based on selected radio button. + function toggleCustomDetailsForSummary() { + if ($("#event_bridge_for_activitypub_summary_type_custom").is(':checked')) { + $("#event_bridge_for_activitypub_summary_type_custom-details").show(); + } else { + $("#event_bridge_for_activitypub_summary_type_custom-details").hide(); + } + } + + // Run the toggle function on page load. + $(document).ready(function() { + window.console.log("test"); + toggleCustomDetailsForSummary(); // Set the correct state on load. + + // Listen for changes on the radio buttons + $("input[name=event_bridge_for_activitypub_summary_type]").change(function() { + toggleCustomDetailsForSummary(); // Update visibility on change. + }); + }); } ); diff --git a/composer.json b/composer.json index 0431a7b..01cb90e 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,7 @@ ], "test-debug": [ "@prepare-test", - "@test-event-organiser" + "@test-event-bridge-for-activitypub-shortcodes" ], "test-vs-event-list": "phpunit --filter=vs_event_list", "test-the-events-calendar": "phpunit --filter=the_events_calendar", @@ -71,6 +71,7 @@ "test-modern-events-calendar-lite": "phpunit --filter=modern_events_calendar_lite", "test-eventprime": "phpunit --filter=eventprime", "test-event-organiser": "phpunit --filter=event_organiser", + "test-event-bridge-for-activitypub-shortcodes": "phpunit --filter=event_bridge_for_activitypub_shortcodes", "test-all": "phpunit" } } diff --git a/event-bridge-for-activitypub.php b/event-bridge-for-activitypub.php index 4b1b01e..4bb34cf 100644 --- a/event-bridge-for-activitypub.php +++ b/event-bridge-for-activitypub.php @@ -3,7 +3,7 @@ * Plugin Name: Event Bridge for ActivityPub * Description: Integrating popular event plugins with the ActivityPub plugin. * Plugin URI: https://event-federation.eu/ - * Version: 0.3.1 + * Version: 0.3.1.1 * Author: André Menrath * Author URI: https://graz.social/@linos * Text Domain: event-bridge-for-activitypub @@ -27,6 +27,8 @@ define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION', current( get_file_data( __FILE__, array( 'Version' ), 'plugin' ) ) ); define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_DOMAIN', 'event-bridge-for-activitypub' ); define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION', '3.2.2' ); +define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_CUSTOM_SUMMARY', "
    \n
  • [ap_start_time]
  • \n
  • [ap_end_time]
  • \n
  • [ap_location]
  • \n
\n[ap_hashcats] [ap_hashtags]" ); +define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_DEFAULT_SUMMARY_TYPE', 'preset' ); // Include and register the autoloader class for automatic loading of plugin classes. require_once EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/includes/class-autoloader.php'; diff --git a/includes/activitypub/transformer/class-event-organiser.php b/includes/activitypub/transformer/class-event-organiser.php index 54e8cdf..6574f54 100644 --- a/includes/activitypub/transformer/class-event-organiser.php +++ b/includes/activitypub/transformer/class-event-organiser.php @@ -44,21 +44,21 @@ final class Event_Organiser extends Event { /** * Get the end time from the event object. */ - protected function get_end_time(): ?string { + public function get_end_time(): ?string { return eo_get_the_end( 'Y-m-d\TH:i:s\Z', $this->wp_object->ID, $this->wp_object->occurrence_id ); } /** * Get the end time from the event object. */ - protected function get_start_time(): string { + public function get_start_time(): string { return eo_get_the_start( 'Y-m-d\TH:i:s\Z', $this->wp_object->ID, $this->wp_object->occurrence_id ); } /** * Get location from the event object. */ - protected function get_location(): ?Place { + public function get_location(): ?Place { $venue_id = eo_get_venue( $this->wp_object->ID ); if ( ! $venue_id ) { diff --git a/includes/activitypub/transformer/class-event.php b/includes/activitypub/transformer/class-event.php index 730a943..cb388c2 100644 --- a/includes/activitypub/transformer/class-event.php +++ b/includes/activitypub/transformer/class-event.php @@ -13,7 +13,9 @@ defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Event as Event_Object; use Activitypub\Activity\Extended_Object\Place; +use Activitypub\Shortcodes; use Activitypub\Transformer\Post; + use DateTime; /** @@ -148,14 +150,14 @@ abstract class Event extends Post { * * This is mandatory and must be implemented in the final event transformer class. */ - abstract protected function get_start_time(): string; + abstract public function get_start_time(): string; /** * Get the end time. * * This is not mandatory and therefore just return null by default. */ - protected function get_end_time(): ?string { + public function get_end_time(): ?string { return null; } @@ -164,14 +166,14 @@ abstract class Event extends Post { * * This should be overridden in the actual event transformer. */ - protected function get_location(): ?Place { + public function get_location(): ?Place { return null; } /** * Default value for the event status. */ - protected function get_status(): ?string { + public function get_status(): ?string { return 'CONFIRMED'; } @@ -194,7 +196,7 @@ abstract class Event extends Post { * * @param ?string $time The time which needs to be formatted. */ - private static function format_time( $time ) { + protected static function format_time( $time ) { if ( is_null( $time ) ) { return ''; } @@ -205,24 +207,160 @@ abstract class Event extends Post { } /** - * Format a human readable address. + * Generates output for the 'ap_start_time' shortcode. + * + * @param ?array $atts The shortcode's attributes. + * @return string The formatted start date and time of the event. */ - protected function format_address(): string { + public function shortcode_start_time( $atts ) { + $start_timestamp = $this->get_start_time(); + return $this->generate_time_output( $start_timestamp, $atts, '🗓️', __( 'Start', 'event-bridge-for-activitypub' ) ); + } + + /** + * Generates output for the 'ap_end_time' shortcode. + * + * @param ?array $atts The shortcode's attributes. + * @return string The formatted end date and time of the event. + */ + public function shortcode_end_time( $atts ) { + $end_timestamp = $this->get_end_time(); + return $this->generate_time_output( $end_timestamp, $atts, '⏳', __( 'End', 'event-bridge-for-activitypub' ) ); + } + + /** + * Generates the formatted time output for a shortcode. + * + * @param int|null $timestamp The timestamp for the event time. + * @param array $atts The shortcode attributes. + * @param string $icon The icon to display. + * @param string $label The label to display (e.g., 'Start', 'End'). + * @return string The formatted date and time, or an empty string if the timestamp is invalid. + */ + private function generate_time_output( $timestamp, $atts, $icon, $label ) { + if ( ! $timestamp ) { + return ''; + } + + $args = shortcode_atts( + array( + 'icon' => 'true', + 'label' => 'true', + ), + $atts + ); + + $args['icon'] = filter_var( $args['icon'], FILTER_VALIDATE_BOOLEAN ); + $args['label'] = filter_var( $args['label'], FILTER_VALIDATE_BOOLEAN ); + + $output = array(); + + if ( $args['icon'] ) { + $output[] = $icon; + } + + if ( $args['label'] ) { + $output[] = $label . ':'; + } + + $output[] = self::format_time( $timestamp ); + + return implode( ' ', $output ); + } + + /** + * Generates output for the 'ap_location' shortcode. + * + * @param ?array $atts The shortcode's attributes. + * @return string The formatted location/address of the event. + */ + public function shortcode_location( $atts ) { + $args = shortcode_atts( + array( + 'icon' => 'true', + 'label' => 'true', + 'country' => 'true', + 'zip' => 'true', + 'city' => 'true', + 'street' => 'true', + 'name' => 'true', + ), + $atts, + 'ap_location' + ); + + // Convert attributes to booleans. + $args = array_map( + function ( $value ) { + return filter_var( $value, FILTER_VALIDATE_BOOLEAN ); + }, + $args + ); + $location = $this->get_location(); - if ( is_null( $location ) ) { + if ( ! $location ) { return ''; } - $address = $location->get_address(); - if ( ! $address ) { - return $location->get_name(); + + $output = array(); + if ( $args['icon'] ) { + $output[] = '📍'; } + if ( $args['label'] ) { + $output[] = esc_html__( 'Location', 'event-bridge-for-activitypub' ) . ':'; + } + + $output[] = self::format_address( $location->get_address(), $args ); + + // Join output array into a single string with spaces and return. + return implode( ' ', array_filter( $output ) ); + } + + /** + * Formats the address based on provided arguments. + * + * @param mixed $address The address data, either as a string or an array. + * @param array $args The arguments for which components to include. + * @return string The formatted address. + */ + protected static function format_address( $address, $args = null ) { if ( is_string( $address ) ) { - return $address; + return esc_html( $address ); } - if ( ! is_array( $address ) ) { - return ''; + + if ( is_null( $args ) ) { + $args = array( + 'icon' => 'true', + 'title' => 'true', + 'country' => 'true', + 'zip' => 'true', + 'city' => 'true', + 'street' => 'true', + 'name' => 'true', + ); } - return isset( $address['locality'] ) ? $address['locality'] : ''; + + if ( is_array( $address ) ) { + $address_parts = array(); + + $components = array( + 'name' => 'name', + 'street' => 'streetAddress', + 'zip' => 'postalCode', + 'city' => 'addressLocality', + 'country' => 'addressCountry', + ); + + foreach ( $components as $arg_key => $address_key ) { + if ( $args[ $arg_key ] && ! empty( $address[ $address_key ] ) ) { + $address_parts[] = esc_html( $address[ $address_key ] ); + } + } + + return implode( ', ', $address_parts ); + } + + return ''; } /** @@ -255,6 +393,68 @@ abstract class Event extends Post { return ''; } + /** + * Register the shortcodes. + */ + public function register_shortcodes() { + foreach ( get_class_methods( self::class ) as $function ) { + if ( 'shortcode_' === substr( $function, 0, 10 ) ) { + add_shortcode( 'ap_' . substr( $function, 10, strlen( $function ) ), array( $this, $function ) ); + } + } + } + + /** + * Register the shortcodes. + */ + public function unregister_shortcodes() { + foreach ( get_class_methods( self::class ) as $function ) { + if ( 'shortcode_' === substr( $function, 0, 10 ) ) { + remove_shortcode( 'ap_' . substr( $function, 10, strlen( $function ) ), array( $this, $function ) ); + } + } + } + + /** + * Get the summary. + */ + public function get_summary(): ?string { + if ( 'preset' === get_option( 'event_bridge_for_activitypub_summary_type', 'preset' ) ) { + return $this->format_preset_summary(); + } + + // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + $post = $this->wp_object; + $summary = $this->get_event_summary_template(); + + // It seems that shortcodes are only applied to published posts. + if ( is_preview() ) { + $post->post_status = 'publish'; + } + + // Register our shortcodes just in time. + + Shortcodes::register(); + $this->register_shortcodes(); + + // Fill in the shortcodes. + \setup_postdata( $post ); + $summary = \do_shortcode( $summary ); + \wp_reset_postdata(); + + $summary = \wpautop( $summary ); + $summary = \preg_replace( '/[\n\r\t]/', '', $summary ); + $summary = \trim( $summary ); + + $summary = \apply_filters( 'event_bridge_for_activitypub_the_summary', $summary, $post ); + + // Unregister the shortcodes. + Shortcodes::unregister(); + $this->unregister_shortcodes(); + + return $summary; + } + /** * Create a custom summary. * @@ -263,7 +463,7 @@ abstract class Event extends Post { * * @return string $summary The custom event summary. */ - public function get_summary(): ?string { + public function format_preset_summary(): ?string { add_filter( 'activitypub_object_content_template', array( self::class, 'remove_ap_permalink_from_template' ), 2, 2 ); $excerpt = $this->retrieve_excerpt(); // BeforeFirstRelease: decide whether this should be a admin setting. @@ -274,9 +474,13 @@ abstract class Event extends Post { remove_filter( 'activitypub_object_content_template', array( self::class, 'remove_ap_permalink_from_template' ) ); $category = $this->format_categories(); - $start_time = $this->format_start_time(); - $end_time = $this->format_end_time(); - $address = $this->format_address(); + $start_time = $this->get_start_time(); + $end_time = $this->get_end_time(); + $address = $this->format_address( $this->get_location() ); + $time_atts = array( + 'icon' => true, + 'label' => true, + ); $formatted_items = array(); if ( ! empty( $category ) ) { @@ -284,11 +488,11 @@ abstract class Event extends Post { } if ( ! empty( $start_time ) ) { - $formatted_items[] = '🗓️ ' . __( 'Start', 'event-bridge-for-activitypub' ) . ': ' . $start_time; + $formatted_items[] = $this->generate_time_output( $start_time, $time_atts, '🗓️', __( 'Start', 'event-bridge-for-activitypub' ) ); } if ( ! empty( $end_time ) ) { - $formatted_items[] = '⏳ ' . __( 'End', 'event-bridge-for-activitypub' ) . ': ' . $end_time; + $formatted_items[] = $this->generate_time_output( $end_time, $time_atts, '⏳', __( 'End', 'event-bridge-for-activitypub' ) ); } if ( ! empty( $address ) ) { @@ -308,6 +512,18 @@ abstract class Event extends Post { return $summary; } + /** + * Gets the template to use to generate the summary of the ActivityStreams representation of an event post. + * + * @return string The Template. + */ + protected function get_event_summary_template() { + $summary = \get_option( 'event_bridge_for_activitypub_custom_summary', EVENT_BRIDGE_FOR_ACTIVITYPUB_CUSTOM_SUMMARY ); + $template = $summary ?? EVENT_BRIDGE_FOR_ACTIVITYPUB_CUSTOM_SUMMARY; + + return apply_filters( 'event_bridge_for_activitypub_summary_template', $template, $this->wp_object ); + } + /** * By default set the timezone of the WordPress site. * diff --git a/includes/activitypub/transformer/class-eventprime.php b/includes/activitypub/transformer/class-eventprime.php index 8fa5d4b..c85548e 100644 --- a/includes/activitypub/transformer/class-eventprime.php +++ b/includes/activitypub/transformer/class-eventprime.php @@ -23,7 +23,7 @@ final class EventPrime extends Event { /** * Get the end time from the event object. */ - protected function get_end_time(): ?string { + public function get_end_time(): ?string { $timestamp = get_post_meta( $this->wp_object->ID, 'em_end_date', true ); if ( $timestamp ) { return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp ); @@ -35,7 +35,7 @@ final class EventPrime extends Event { /** * Get the end time from the event object. */ - protected function get_start_time(): string { + public function get_start_time(): string { $timestamp = get_post_meta( $this->wp_object->ID, 'em_start_date', true ); if ( $timestamp ) { return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp ); @@ -47,7 +47,7 @@ final class EventPrime extends Event { /** * Get location from the event object. */ - protected function get_location(): ?Place { + public function get_location(): ?Place { $venue_term_id = get_post_meta( $this->wp_object->ID, 'em_venue', true ); if ( ! $venue_term_id ) { return null; diff --git a/includes/activitypub/transformer/class-gatherpress.php b/includes/activitypub/transformer/class-gatherpress.php index 5adf245..79eb601 100644 --- a/includes/activitypub/transformer/class-gatherpress.php +++ b/includes/activitypub/transformer/class-gatherpress.php @@ -73,14 +73,14 @@ final class GatherPress extends Event { /** * Get the end time from the event object. */ - protected function get_end_time(): ?string { + public function get_end_time(): ?string { return $this->gp_event->get_datetime_end( 'Y-m-d\TH:i:s\Z' ); } /** * Get the end time from the event object. */ - protected function get_start_time(): string { + public function get_start_time(): string { return $this->gp_event->get_datetime_start( 'Y-m-d\TH:i:s\Z' ); } diff --git a/includes/activitypub/transformer/class-the-events-calendar.php b/includes/activitypub/transformer/class-the-events-calendar.php index faa6f4f..880fee3 100644 --- a/includes/activitypub/transformer/class-the-events-calendar.php +++ b/includes/activitypub/transformer/class-the-events-calendar.php @@ -72,7 +72,7 @@ final class The_Events_Calendar extends Event { /** * Get the end time from the event object. */ - protected function get_end_time(): ?string { + public function get_end_time(): ?string { if ( empty( $this->tribe_event->end_date ) ) { return null; } @@ -83,7 +83,7 @@ final class The_Events_Calendar extends Event { /** * Get the end time from the event object. */ - protected function get_start_time(): string { + public function get_start_time(): string { $date = date_create( $this->tribe_event->start_date, wp_timezone() ); return \gmdate( 'Y-m-d\TH:i:s\Z', $date->getTimestamp() ); } diff --git a/includes/activitypub/transformer/class-vs-event-list.php b/includes/activitypub/transformer/class-vs-event-list.php index d67cd77..42fdb14 100644 --- a/includes/activitypub/transformer/class-vs-event-list.php +++ b/includes/activitypub/transformer/class-vs-event-list.php @@ -44,7 +44,7 @@ final class VS_Event_List extends Event_Transformer { /** * Get the end time from the events metadata. */ - protected function get_end_time(): ?string { + public function get_end_time(): ?string { if ( 'yes' === get_post_meta( $this->wp_object->ID, 'event-hide-end-time', true ) ) { return null; } @@ -58,7 +58,7 @@ final class VS_Event_List extends Event_Transformer { /** * Get the end time from the events metadata. */ - protected function get_start_time(): string { + public function get_start_time(): string { $start_time = get_post_meta( $this->wp_object->ID, 'event-start-date', true ); return \gmdate( 'Y-m-d\TH:i:s\Z', $start_time ); } diff --git a/includes/class-settings.php b/includes/class-settings.php index b2a3744..3b15a2c 100644 --- a/includes/class-settings.php +++ b/includes/class-settings.php @@ -71,6 +71,28 @@ class Settings { 'default' => 1, ) ); + + \register_setting( + 'event-bridge-for-activitypub', + 'event_bridge_for_activitypub_summary_type', + array( + 'type' => 'string', + 'description' => \__( 'Summary type to use for ActivityStreams', 'event-bridge-for-activitypub' ), + 'show_in_rest' => true, + 'default' => 'preset', + ) + ); + + \register_setting( + 'event-bridge-for-activitypub', + 'event_bridge_for_activitypub_custom_summary', + array( + 'type' => 'string', + 'description' => \__( 'Define your own custom summary template for events', 'event-bridge-for-activitypub' ), + 'show_in_rest' => true, + 'default' => EVENT_BRIDGE_FOR_ACTIVITYPUB_CUSTOM_SUMMARY, + ) + ); } /** diff --git a/templates/settings.php b/templates/settings.php index a0ddab4..2c9c077 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -42,6 +42,52 @@ $current_category_mapping = \get_option( 'event_bridge_for_activitypub_ev
+
+

+

+

+ +

+

+ +

+
+ +
+ +
+
+
[ap_start_time]
+
+
[ap_end_time]
+
+
[ap_location]
+
+
[ap_hashtags]
+
+
[ap_excerpt]
+
+
[ap_content]
+
+
+
+
+
+

diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 709ef61..643a8aa 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -25,6 +25,21 @@ if ( ! file_exists( "{$_tests_dir}/includes/functions.php" ) ) { // Give access to tests_add_filter() function. require_once "{$_tests_dir}/includes/functions.php"; +/** + * Function to manually load an event plugin. + * + * @param string $plugin_file The main plugin file of the event plugin. + */ +function _manually_load_event_plugin( $plugin_file ) { + $plugin_dir = ABSPATH . '/wp-content/plugins/'; + require_once $plugin_dir . $plugin_file; + update_option( 'purchase_history_table_structure_migration_done', true ); + $current = get_option( 'active_plugins', array() ); + $current[] = $plugin_file; + sort( $current ); + update_option( 'active_plugins', $current ); +} + /** * Manually load the plugin being tested and its integrations. */ @@ -80,13 +95,12 @@ function _manually_load_plugin() { } if ( $plugin_file ) { - // Manually load the event plugin. - require_once $plugin_dir . $plugin_file; - update_option( 'purchase_history_table_structure_migration_done', true ); - $current = get_option( 'active_plugins', array() ); - $current[] = $plugin_file; - sort( $current ); - update_option( 'active_plugins', $current ); + _manually_load_event_plugin( $plugin_file ); + } else { + // For all other tests we mainly use the Events Calendar as a reference. + _manually_load_event_plugin( 'the-events-calendar/the-events-calendar.php' ); + _manually_load_event_plugin( 'very-simple-event-list/vsel.php' ); + } // Hot fix that allows using Events Manager within unit tests, because the em_init() is later not run as admin. diff --git a/tests/test-class-activitypub-event-bridge-shortcodes.php b/tests/test-class-activitypub-event-bridge-shortcodes.php new file mode 100644 index 0000000..1256665 --- /dev/null +++ b/tests/test-class-activitypub-event-bridge-shortcodes.php @@ -0,0 +1,193 @@ +activate_activitypub_support_for_active_event_plugins(); + + // Delete all posts afterwards. + _delete_all_posts(); + } + + /** + * Test the shortcode for rendering the events start time. + */ + public function test_start_time() { + // Create a The Events Calendar Event without content. + $wp_object = tribe_events() + ->set_args( Test_The_Events_Calendar::MOCKUP_EVENTS['minimal_event'] ) + ->create(); + + // Call the transformer Factory. + $transformer = \Activitypub\Transformer\Factory::get_transformer( $wp_object ); + + if ( ! $transformer instanceof \Event_Bridge_For_ActivityPub\Activitypub\Transformer\Event ) { + return; + } + + $transformer->register_shortcodes(); + + $summary = '[ap_start_time]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( '🗓️ Start: December 1, 2024 3:00 pm', $summary ); + + $summary = '[ap_start_time icon="false"]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( 'Start: December 1, 2024 3:00 pm', $summary ); + + $summary = '[ap_start_time icon="false" label="false"]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( 'December 1, 2024 3:00 pm', $summary ); + + $transformer->unregister_shortcodes(); + } + + /** + * Test the shortcode for rendering the events end time. + */ + public function test_end_time() { + // Create a The Events Calendar Event without content. + $wp_object = tribe_events() + ->set_args( Test_The_Events_Calendar::MOCKUP_EVENTS['minimal_event'] ) + ->create(); + + // Call the transformer Factory. + $transformer = \Activitypub\Transformer\Factory::get_transformer( $wp_object ); + + if ( ! $transformer instanceof \Event_Bridge_For_ActivityPub\Activitypub\Transformer\Event ) { + return; + } + + $transformer->register_shortcodes(); + + $summary = '[ap_end_time]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( '⏳ End: December 1, 2024 4:00 pm', $summary ); + + $summary = '[ap_end_time icon="false"]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( 'End: December 1, 2024 4:00 pm', $summary ); + + $summary = '[ap_end_time icon="false" label="false"]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( 'December 1, 2024 4:00 pm', $summary ); + + $transformer->unregister_shortcodes(); + } + + /** + * Test the shortcode for rendering the events location when no location is set. + */ + public function test_location_when_no_location_is_set() { + // Create a The Events Calendar Event without content. + $wp_object = tribe_events() + ->set_args( Test_The_Events_Calendar::MOCKUP_EVENTS['minimal_event'] ) + ->create(); + + // Call the transformer Factory. + $transformer = \Activitypub\Transformer\Factory::get_transformer( $wp_object ); + + if ( ! $transformer instanceof \Event_Bridge_For_ActivityPub\Activitypub\Transformer\Event ) { + return; + } + + $transformer->register_shortcodes(); + + $summary = '[ap_location]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( '', $summary ); + + $transformer->unregister_shortcodes(); + } + + /** + * Test the shortcode for rendering the events location when location is set. + */ + public function test_location_when_location_is_set() { + // Create Venue. + $venue = tribe_venues()->set_args( Test_The_Events_Calendar::MOCKUP_VENUS['minimal_venue'] )->create(); + // Create a The Events Calendar Event. + $wp_object = tribe_events() + ->set_args( Test_The_Events_Calendar::MOCKUP_EVENTS['complex_event'] ) + ->set( 'venue', $venue->ID ) + ->create(); + + // Call the transformer Factory. + $transformer = \Activitypub\Transformer\Factory::get_transformer( $wp_object ); + + if ( ! $transformer instanceof \Event_Bridge_For_ActivityPub\Activitypub\Transformer\Event ) { + return; + } + + $transformer->register_shortcodes(); + + $summary = '[ap_location]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( '📍 Location: Minimal Venue', $summary ); + + $summary = '[ap_location icon="false"]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( 'Location: Minimal Venue', $summary ); + + $summary = '[ap_location icon="false" label="false"]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( 'Minimal Venue', $summary ); + + $transformer->unregister_shortcodes(); + } + + /** + * Test the shortcode for rendering the events location when location with detailed address is set. + */ + public function test_location_when_detailed_location_is_set() { + // Create Venue. + $venue = tribe_venues()->set_args( Test_The_Events_Calendar::MOCKUP_VENUS['complex_venue'] )->create(); + // Create a The Events Calendar Event. + $wp_object = tribe_events() + ->set_args( Test_The_Events_Calendar::MOCKUP_EVENTS['complex_event'] ) + ->set( 'venue', $venue->ID ) + ->create(); + + // Call the transformer Factory. + $transformer = \Activitypub\Transformer\Factory::get_transformer( $wp_object ); + + if ( ! $transformer instanceof \Event_Bridge_For_ActivityPub\Activitypub\Transformer\Event ) { + return; + } + + $transformer->register_shortcodes(); + + $summary = '[ap_location]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( '📍 Location: Complex Venue, Venue address, Venue zip, Venue city, Venue country', $summary ); + + $summary = '[ap_location country="false"]'; + $summary = do_shortcode( $summary ); + $this->assertEquals( '📍 Location: Complex Venue, Venue address, Venue zip, Venue city', $summary ); + + $transformer->unregister_shortcodes(); + } +}