From da9076a4f503750cc0939211d4d8002831e52eb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Tue, 15 Oct 2024 13:02:33 +0200 Subject: [PATCH 1/6] wip --- README.md | 2 +- .../class-modern-events-calendar-lite.php | 78 +++++++++++++++++++ includes/class-setup.php | 1 + .../class-modern-events-calendar-lite.php | 61 +++++++++++++++ 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 includes/activitypub/transformer/class-modern-events-calendar-lite.php create mode 100644 includes/plugins/class-modern-events-calendar-lite.php diff --git a/README.md b/README.md index a23638c..f14da67 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ The Event Federation plugin ensures that users from those platforms are provided ### Features for Your WordPress Events and the Fediverse -**ActivityPub-Enabled Event Sharing:** Your WordPress events are now compatible with the Fediverse, using the ActivityStreams format. This means your events can be easily discovered and followed by users on platforms like Mastodon and other ActivityPub-compatible services. +**ActivityPub-Enabled Event Sharing:** Your WordPress events are not part of the Fediverse and **Automatic Event Summaries:** When your event is shared on the Fediverse, platforms like Mastodon that don't fully support events will display a brief HTML summary of key details — such as the event's title, start time, and location. This ensures that even if someone can't view the full event on their platform, they still get the important info at a glance, with a link to your WordPress event page. diff --git a/includes/activitypub/transformer/class-modern-events-calendar-lite.php b/includes/activitypub/transformer/class-modern-events-calendar-lite.php new file mode 100644 index 0000000..d281c92 --- /dev/null +++ b/includes/activitypub/transformer/class-modern-events-calendar-lite.php @@ -0,0 +1,78 @@ +mec_event = new MEC_Event( $wp_object ); + } + + /** + * Get the end time from the event object. + */ + public function get_start_time(): string { + return \gmdate( 'Y-m-d\TH:i:s\Z', $this->mec_event->get_datetime()['start']['timestamp'] ); + } + + /** + * Get the end time from the event object. + */ + public function get_end_time(): ?string { + return \gmdate( 'Y-m-d\TH:i:s\Z', $this->mec_event->get_datetime()['end']['timestamp'] ); + } + + /** + * Get the location. + */ + public function get_location(): ?Place { + return null; + } + + /** + * Get the location. + */ + public function get_timezone(): string { + $timezone = get_post_meta( $this->wp_object->ID, 'mec_timezone', true ); + + if ( 'global' === $timezone ) { + return parent::get_timezone(); + } + return $timezone; + } +} diff --git a/includes/class-setup.php b/includes/class-setup.php index e03c7d0..a03c988 100644 --- a/includes/class-setup.php +++ b/includes/class-setup.php @@ -130,6 +130,7 @@ class Setup { '\ActivityPub_Event_Bridge\Plugins\VS_Event_List', '\ActivityPub_Event_Bridge\Plugins\WP_Event_Manager', '\ActivityPub_Event_Bridge\Plugins\Eventin', + '\ActivityPub_Event_Bridge\Plugins\Modern_Events_Calendar_Lite', ); /** diff --git a/includes/plugins/class-modern-events-calendar-lite.php b/includes/plugins/class-modern-events-calendar-lite.php new file mode 100644 index 0000000..f8f5552 --- /dev/null +++ b/includes/plugins/class-modern-events-calendar-lite.php @@ -0,0 +1,61 @@ +get_main_post_type(). + return apply_filters( 'mec_post_type_name', 'mec-events' ); // phpcs:ignore + } + + /** + * Returns the ID of the main settings page of the plugin. + * + * @return string The settings page url. + */ + public static function get_settings_page(): string { + return 'mec-event'; + } + + /** + * Returns the taxonomy used for the plugin's event categories. + * + * @return string + */ + public static function get_event_category_taxonomy(): string { + return 'mec_category'; + } +} -- 2.39.5 From bee70bcb88fd566c2a601ea133d9f1c2e86ae0fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Tue, 15 Oct 2024 17:47:54 +0200 Subject: [PATCH 2/6] add location --- .../class-modern-events-calendar-lite.php | 38 ++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/includes/activitypub/transformer/class-modern-events-calendar-lite.php b/includes/activitypub/transformer/class-modern-events-calendar-lite.php index d281c92..0877abf 100644 --- a/includes/activitypub/transformer/class-modern-events-calendar-lite.php +++ b/includes/activitypub/transformer/class-modern-events-calendar-lite.php @@ -14,7 +14,9 @@ defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use ActivityPub_Event_Bridge\Activitypub\Transformer\Event; +use MEC; use MEC\Events\Event as MEC_Event; +use MEC_main; /** * ActivityPub Tribe Transformer @@ -29,6 +31,14 @@ final class Modern_Events_Calendar_Lite extends Event { */ protected $mec_event; + /** + * The MEC main instance. + * + * @var MEC_main|null + */ + protected $mec_main; + + /** * Extend the constructor, to also set the tribe object. * @@ -40,6 +50,7 @@ final class Modern_Events_Calendar_Lite extends Event { */ public function __construct( $wp_object, $wp_taxonomy ) { parent::__construct( $wp_object, $wp_taxonomy ); + $this->mec_main = MEC::getInstance( 'app.libraries.main' ); $this->mec_event = new MEC_Event( $wp_object ); } @@ -61,7 +72,31 @@ final class Modern_Events_Calendar_Lite extends Event { * Get the location. */ public function get_location(): ?Place { - return null; + $location_id = $this->mec_main->get_master_location_id( $this->mec_event->ID ); + + if ( ! $location_id ) { + return null; + } + + $data = $this->mec_main->get_location_data( $location_id ); + + $location = new Place(); + $location->set_sensitive( null ); + + if ( ! empty( $data['address'] ) ) { + $location->set_address( $data['address'] ); + } + if ( ! empty( $data['name'] ) ) { + $location->set_name( $data['name'] ); + } + if ( ! empty( $data['longitude'] ) ) { + $location->set_longitude( $data['longitude'] ); + } + if ( ! empty( $data['latitude'] ) ) { + $location->set_latitude( $data['latitude'] ); + } + + return $location; } /** @@ -73,6 +108,7 @@ final class Modern_Events_Calendar_Lite extends Event { if ( 'global' === $timezone ) { return parent::get_timezone(); } + return $timezone; } } -- 2.39.5 From 6964e08559054560765c280e8ba25126a1fa484d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Thu, 17 Oct 2024 20:50:21 +0200 Subject: [PATCH 3/6] add basic integration tests ffor modern-events-calendar-lite --- .forgejo/workflows/phpunit.yml | 7 +- bin/install-wp-tests.sh | 16 ++++ composer.json | 6 +- improvements.md | 16 ++++ tests/bootstrap.php | 3 + ...ass-plugin-modern-events-calendar-lite.php | 79 +++++++++++++++++++ 6 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 improvements.md create mode 100644 tests/test-class-plugin-modern-events-calendar-lite.php diff --git a/.forgejo/workflows/phpunit.yml b/.forgejo/workflows/phpunit.yml index 3cb7904..a893dce 100644 --- a/.forgejo/workflows/phpunit.yml +++ b/.forgejo/workflows/phpunit.yml @@ -37,7 +37,7 @@ jobs: path: | ${{ env.WP_CORE_DIR }} ${{ env.WP_TESTS_DIR }} - key: cache-wordpress-8 + key: cache-wordpress-9 - name: Cache Composer id: cache-composer-phpunit @@ -101,5 +101,10 @@ jobs: - name: Run Integration tests for Eventin (WP Event Solution) run: cd /workspace/Event-Federation/wordpress-activitypub-event-bridge/ && ./vendor/bin/phpunit --filter=eventin + env: + PHP_VERSION: ${{ matrix.php-version }} + + - name: Run Integration tests for Modern Events Calendar Lite + run: cd /workspace/Event-Federation/wordpress-activitypub-event-bridge/ && ./vendor/bin/phpunit --filter=modern_events_calendar_lite env: PHP_VERSION: ${{ matrix.php-version }} \ No newline at end of file diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh index 759ad25..f0bf333 100755 --- a/bin/install-wp-tests.sh +++ b/bin/install-wp-tests.sh @@ -226,6 +226,20 @@ install_wp_plugin() { unzip -q -o "$TMPDIR/$PLUGIN_FILE" -d "$WP_CORE_DIR/wp-content/plugins/" } +install_wp_plugin_mec() { + mkdir -p "$WP_CORE_DIR/wp-content/plugins/" + + if [ -d "$WP_CORE_DIR/wp-content/plugins/modern-events-calendar-lite" ]; then + return; + fi + + PLUGIN_VERSION="v7.15.0" + + URL="https://code.event-federation.eu/Event-Federation/modern-events-calendar-lite" + + git clone $URL "$WP_CORE_DIR/wp-content/plugins/modern-events-calendar-lite" +} + install_wp_plugins() { if [ "$SKIP_PLUGINS_INSTALL" = "true" ]; then echo "Skipping WordPress plugin installation." @@ -240,6 +254,8 @@ install_wp_plugins() { install_wp_plugin events-manager install_wp_plugin wp-event-manager install_wp_plugin wp-event-solution + # Mec is not installable via wordpress.org, we use our own mirror. + install_wp_plugin_mec } install_wp diff --git a/composer.json b/composer.json index 940dff0..eaf1ea5 100644 --- a/composer.json +++ b/composer.json @@ -53,11 +53,12 @@ "@test-gatherpress", "@test-events-manager", "@test-wp-event-manager", - "@test-eventin" + "@test-eventin", + "@test-modern-events-calendar-lite" ], "test-debug": [ "@prepare-test", - "@test-eventin" + "@test-modern-events-calendar-lite" ], "test-vs-event-list": "phpunit --filter=vs_event_list", "test-the-events-calendar": "phpunit --filter=the_events_calendar", @@ -65,6 +66,7 @@ "test-events-manager": "phpunit --filter=events_manager", "test-wp-event-manager": "phpunit --filter=wp_event_manager", "test-eventin": "phpunit --filter=eventin", + "test-modern-events-calendar-lite": "phpunit --filter=modern_events_calendar_lite", "test-all": "phpunit" } } diff --git a/improvements.md b/improvements.md new file mode 100644 index 0000000..c095490 --- /dev/null +++ b/improvements.md @@ -0,0 +1,16 @@ +Make use of: + +https://docs.theeventscalendar.com/reference/classes/tribe__events__api/get_event_terms/ + +for getting all tags/terms for an event! + +``` +public static function get_event_terms( $event_id, array $args = array() ) { + $terms = array(); + foreach ( get_post_taxonomies( $event_id ) as $taxonomy ) { + $tax_terms = wp_get_object_terms( $event_id, $taxonomy, $args ); + $terms[ $taxonomy ] = $tax_terms; + } + return $terms; +} +``` diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 4bbd83a..95f0da5 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -62,6 +62,9 @@ function _manually_load_plugin() { case 'eventin': $plugin_file = 'wp-event-solution/eventin.php'; break; + case 'modern_events_calendar_lite': + $plugin_file = 'modern-events-calendar-lite/modern-events-calendar-lite.php'; + break; case 'gatherpress': $plugin_file = 'gatherpress/gatherpress.php'; break; diff --git a/tests/test-class-plugin-modern-events-calendar-lite.php b/tests/test-class-plugin-modern-events-calendar-lite.php new file mode 100644 index 0000000..fa658ec --- /dev/null +++ b/tests/test-class-plugin-modern-events-calendar-lite.php @@ -0,0 +1,79 @@ +activate_activitypub_support_for_active_event_plugins(); + + $this->mec_main = \MEC::getInstance( 'app.libraries.main' ); + + // Delete all posts afterwards. + _delete_all_posts(); + } + + /** + * Test that the right transformer gets applied. + */ + public function test_modern_events_calendar_lite_transformer_class() { + // We only test for one event plugin being active at the same time, + // even though we support multiple onces in theory. + // But testing all combinations is beyond scope. + $active_event_plugins = \ActivityPub_Event_Bridge\Setup::get_instance()->get_active_event_plugins(); + $this->assertEquals( 1, count( $active_event_plugins ) ); + + // Enable ActivityPub support for the event plugin. + $this->assertContains( 'mec-events', get_option( 'activitypub_support_post_types' ) ); + + // Insert a new Event. + $event = array( + 'title' => 'MEC Test Event', + 'status' => 'publish', + 'start_time_hour' => '3', + 'start_time_minutes' => '00', + 'start_time_ampm' => 'PM', + 'start' => '2025-01-01', + 'end' => '2025-01-01', + 'end_time_hour' => '4', + 'end_time_minutes' => '00', + 'end_time_ampm' => 'PM', + 'repeat_status' => 0, + 'repeat_type' => 'daily', + 'interval' => 1, + ); + + $post_id = $this->mec_main->save_event( $event ); + + $wp_object = get_post( $post_id ); + + // Call the transformer Factory. + $transformer = \Activitypub\Transformer\Factory::get_transformer( $wp_object ); + + // Check that we got the right transformer. + $this->assertInstanceOf( \ActivityPub_Event_Bridge\Activitypub\Transformer\Modern_Events_Calendar_Lite::class, $transformer ); + } +} -- 2.39.5 From 34f5d9e750904518385135f176c86c493e9c7b5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Thu, 17 Oct 2024 20:53:17 +0200 Subject: [PATCH 4/6] add MEC to readme --- README.md | 2 ++ readme.txt | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index f14da67..892dc58 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,8 @@ This plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/ac * [Events Manager](https://de.wordpress.org/plugins/events-manager/) * [WP Event Manager](https://de.wordpress.org/plugins/wp-event-manager/) * [Eventin](https://de.wordpress.org/plugins/wp-event-solution/) +* [Modern Events Calendar Lite](https://webnus.net/modern-events-calendar/) + ## Configuration diff --git a/readme.txt b/readme.txt index 59e8103..149fe68 100644 --- a/readme.txt +++ b/readme.txt @@ -53,6 +53,7 @@ This plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/ac * [Events Manager](https://de.wordpress.org/plugins/events-manager/) * [WP Event Manager](https://de.wordpress.org/plugins/wp-event-manager/) * [Eventin](https://de.wordpress.org/plugins/wp-event-solution/) +* [Modern Events Calendar Lite](https://webnus.net/modern-events-calendar/) == Configuration == -- 2.39.5 From 04e418d90419d5cf27de6aafcd3c0c6f750774fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Fri, 18 Oct 2024 08:05:25 +0200 Subject: [PATCH 5/6] generate tables for mec (install hook) --- tests/bootstrap.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 95f0da5..df5b41e 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -91,6 +91,12 @@ function _manually_load_plugin() { em_create_locations_table(); } + if ( 'modern_events_calendar_lite' === $activitypub_event_extension_integration_filter ) { + require_once $plugin_dir . 'modern-events-calendar-lite/app/libraries/factory.php'; + $mec_factory = new MEC_factory(); + $mec_factory->install(); + } + // At last manually load our WordPress plugin. require dirname( __DIR__ ) . '/activitypub-event-bridge.php'; } -- 2.39.5 From 4c2e2c70c172e223b8ea2c81726e2cd0a5963a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Fri, 18 Oct 2024 13:43:37 +0200 Subject: [PATCH 6/6] basic tests --- ...ass-plugin-modern-events-calendar-lite.php | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) diff --git a/tests/test-class-plugin-modern-events-calendar-lite.php b/tests/test-class-plugin-modern-events-calendar-lite.php index fa658ec..55114d9 100644 --- a/tests/test-class-plugin-modern-events-calendar-lite.php +++ b/tests/test-class-plugin-modern-events-calendar-lite.php @@ -76,4 +76,110 @@ class Test_Modern_Events_Calendar_Lite extends WP_UnitTestCase { // Check that we got the right transformer. $this->assertInstanceOf( \ActivityPub_Event_Bridge\Activitypub\Transformer\Modern_Events_Calendar_Lite::class, $transformer ); } + + /** + * Test that the transformation of minimal event. + */ + public function test_modern_events_calendar_lite_minimal_event() { + $start_timestamp = strtotime( '+10 days 15:00:00' ); + $end_timestamp = strtotime( '+10 days 16:00:00' ); + + // Insert a new Event. + $event = array( + 'title' => 'MEC Test Event', + 'status' => 'publish', + 'content' => 'This is the content of the MEC!', + 'start_time_hour' => gmdate( 'h', $start_timestamp ), + 'start_time_minutes' => gmdate( 'i', $start_timestamp ), + 'start_time_ampm' => gmdate( 'A', $start_timestamp ), + 'start' => gmdate( 'Y-m-d', $start_timestamp ), + 'end' => gmdate( 'Y-m-d', $end_timestamp ), + 'end_time_hour' => gmdate( 'h', $end_timestamp ), + 'end_time_minutes' => gmdate( 'i', $end_timestamp ), + 'end_time_ampm' => gmdate( 'A', $end_timestamp ), + 'repeat_status' => 0, + 'repeat_type' => 'daily', + 'interval' => 1, + ); + + $post_id = $this->mec_main->save_event( $event ); + + $wp_object = get_post( $post_id ); + + // Call the transformer to make the ActivityStreams representation of the event. + $event_array = \Activitypub\Transformer\Factory::get_transformer( $wp_object )->to_object()->to_array(); + + $this->assertEquals( 'Event', $event_array['type'] ); + $this->assertEquals( 'MEC Test Event', $event_array['name'] ); + $this->assertEquals( 'This is the content of the MEC!', wp_strip_all_tags( $event_array['content'] ) ); + $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 15:00:00' ) ) . 'T15:00:00Z', $event_array['startTime'] ); + $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 16:00:00' ) ) . 'T16:00:00Z', $event_array['endTime'] ); + $this->assertTrue( $event_array['commentsEnabled'] ); + $this->assertEquals( 'allow_all', $event_array['repliesModerationOption'] ); + $this->assertEquals( 'external', $event_array['joinMode'] ); + $this->assertEquals( get_permalink( $wp_object ), $event_array['externalParticipationUrl'] ); + $this->assertArrayNotHasKey( 'location', $event_array ); + $this->assertEquals( 'MEETING', $event_array['category'] ); + } + + /** + * Test that the transformation of minimal event. + */ + public function test_modern_events_calendar_lite_event_with_location() { + $start_timestamp = strtotime( '+10 days 15:00:00' ); + $end_timestamp = strtotime( '+10 days 16:00:00' ); + + // Add new location. + $location = array( + 'name' => 'MEC Location', + 'latitude' => '52.356370', + 'longitude' => '4.955760', + 'address' => 'Stichting NLnet, Science Park 400, 1098 XH Amsterdam', + 'url' => 'https://nlnet.nl/', + ); + + $location_id = $this->mec_main->save_location( $location ); + + // Insert a new Event. + $event = array( + 'title' => 'MEC Test Event', + 'status' => 'publish', + 'content' => 'This is the content of the MEC!', + 'start_time_hour' => gmdate( 'h', $start_timestamp ), + 'start_time_minutes' => gmdate( 'i', $start_timestamp ), + 'start_time_ampm' => gmdate( 'A', $start_timestamp ), + 'start' => gmdate( 'Y-m-d', $start_timestamp ), + 'end' => gmdate( 'Y-m-d', $end_timestamp ), + 'end_time_hour' => gmdate( 'h', $end_timestamp ), + 'end_time_minutes' => gmdate( 'i', $end_timestamp ), + 'end_time_ampm' => gmdate( 'A', $end_timestamp ), + 'repeat_status' => 0, + 'repeat_type' => 'daily', + 'interval' => 1, + 'location_id' => $location_id, + ); + + $post_id = $this->mec_main->save_event( $event ); + + $wp_object = get_post( $post_id ); + + // Call the transformer to make the ActivityStreams representation of the event. + $event_array = \Activitypub\Transformer\Factory::get_transformer( $wp_object )->to_object()->to_array(); + + $this->assertEquals( 'Event', $event_array['type'] ); + $this->assertEquals( 'MEC Test Event', $event_array['name'] ); + $this->assertEquals( 'This is the content of the MEC!', wp_strip_all_tags( $event_array['content'] ) ); + $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 15:00:00' ) ) . 'T15:00:00Z', $event_array['startTime'] ); + $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 16:00:00' ) ) . 'T16:00:00Z', $event_array['endTime'] ); + $this->assertTrue( $event_array['commentsEnabled'] ); + $this->assertEquals( 'allow_all', $event_array['repliesModerationOption'] ); + $this->assertEquals( 'external', $event_array['joinMode'] ); + $this->assertEquals( get_permalink( $wp_object ), $event_array['externalParticipationUrl'] ); + $this->assertArrayHasKey( 'location', $event_array ); + $this->assertEquals( 'MEETING', $event_array['category'] ); + $this->assertEquals( $location['address'], $event_array['location']['address'] ); + $this->assertEquals( $location['name'], $event_array['location']['name'] ); + $this->assertEquals( $location['latitude'], $event_array['location']['latitude'] ); + $this->assertEquals( $location['longitude'], $event_array['location']['longitude'] ); + } } -- 2.39.5