From 1232aaf4bcca520e6b0ad5fae4f08c1fd52eeb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Sun, 30 Jun 2024 14:17:59 +0200 Subject: [PATCH] refactoring the plugin structure --- activitypub-event-extensions.php | 92 +++----- admin/class-admin-notices.php | 115 ---------- includes/activitypub/handler/class-join.php | 6 - .../activitypub/transformer/class-event.php | 17 ++ .../transformer/class-events-manager.php | 22 +- .../transformer/class-gatherpress.php | 2 +- .../activitypub/transformer/class-tribe.php | 4 +- .../transformer/class-vs-event.php | 62 +----- includes/category-mapper.php | 67 ------ includes/class-admin-notices.php | 93 ++++++++ includes/class-autoloader.php | 66 ++++++ includes/class-settings.php | 0 includes/class-setup.php | 200 ++++++++++++++++++ 13 files changed, 420 insertions(+), 326 deletions(-) delete mode 100644 admin/class-admin-notices.php delete mode 100644 includes/activitypub/handler/class-join.php create mode 100644 includes/activitypub/transformer/class-event.php delete mode 100644 includes/category-mapper.php create mode 100644 includes/class-admin-notices.php create mode 100644 includes/class-autoloader.php create mode 100644 includes/class-settings.php create mode 100644 includes/class-setup.php diff --git a/activitypub-event-extensions.php b/activitypub-event-extensions.php index 68bea23..e039439 100644 --- a/activitypub-event-extensions.php +++ b/activitypub-event-extensions.php @@ -1,7 +1,7 @@ post_type === 'event' ) { - require_once __DIR__ . '/includes/activitypub/transformer/class-vs-event.php'; - return new \VS_Event( $wp_object ); - } +define( 'ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); +define( 'ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_BASENAME', plugin_basename( __FILE__ ) ); +define( 'ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) ); +define( 'ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); - /** - * Events manager - * @see https://wordpress.org/plugins/events-manager/ - */ - if ( class_exists( 'EM_Events' ) && $wp_object->post_type === 'event' ) { - require_once __DIR__ . '/includes/activitypub/transformer/class-events-manager.php'; - return new \Events_Manager( $wp_object ); - } +// Include and register the autoloader class for automatic loading of plugin classes. +require_once ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_DIR . '/includes/class-autoloader.php'; +Activitypub_Event_Extensions\Autoloader::register(); - /** - * Events manager - * @see https://wordpress.org/plugins/events-manager/ - */ - if ( class_exists( 'GatherPress\Core\Event' ) && $wp_object->post_type === 'gp_event' ) { - require_once __DIR__ . '/includes/activitypub/transformer/class-gatherpress.php'; - return new \GatherPress( $wp_object ); - } - - // Return the default transformer. - - return $transformer; - }, - 10, - 3 -); +// Initialize the plugin. +Activitypub_Event_Extensions\Setup::get_instance(); -/** - * Activate the plugin. - */ -function activitypub_event_extensions_activate() { - // Don't allow plugin activation, when the ActivityPub plugin is not activated yet. - if( ! class_exists( 'ActivtiyPub' ) ) { - deactivate_plugins( plugin_basename( __FILE__ ) ); - wp_die( __( 'Please install and Activate ActivityPub.', 'activitypub-event-extensions' ), 'Plugin dependency check', array( 'back_link' => true ) ); - } -} - -register_activation_hook( __FILE__, 'activitypub_event_extensions_activate' ); -// TODO: -// require_once __DIR__ . '/admin/class-admin-notices.php'; -// new \Admin_Notices(); + + +// For local development purposes: TODO. Remove everything after here. /** * Add a filter for http_request_host_is_external * - * TODO: Remove this. + * TODO: Remove this for release. * * @todo This filter is temporary code needed to do local testing. */ add_filter( 'http_request_host_is_external', 'custom_http_request_host_is_external', 10, 3 ); -// Your custom callback function +/** + * Add a filter for http_request_host_is_external + * + * TODO: Remove this for release. + * + * @todo This filter is temporary code needed to do local testing. + */ function custom_http_request_host_is_external( $is_external, $host, $url ) { $is_external = true; @@ -102,7 +64,7 @@ function custom_http_request_host_is_external( $is_external, $host, $url ) { /** * Don't verify ssl certs for testing. * - * TODO: Remove this. + * TODO: Remove this for release. * * @todo This filter is temporary code needed to do local testing. */ diff --git a/admin/class-admin-notices.php b/admin/class-admin-notices.php deleted file mode 100644 index d936461..0000000 --- a/admin/class-admin-notices.php +++ /dev/null @@ -1,115 +0,0 @@ -%1$s settings.', - 'admin notice', - 'your-text-domain' - ), - $activitypub_plugin_data['Name'], - $vsel_plugin_data['Name'], - admin_url( 'options-general.php?page=activitypub&tab=settings' ) - ); - wp_admin_notice( - $notice, - array( - 'type' => 'warning', - 'dismissible' => true, - ) - ); - } -} diff --git a/includes/activitypub/handler/class-join.php b/includes/activitypub/handler/class-join.php deleted file mode 100644 index 20e4d45..0000000 --- a/includes/activitypub/handler/class-join.php +++ /dev/null @@ -1,6 +0,0 @@ -em_event->event_location_type; } /** * Get the event location. * - * @param int $post_id The WordPress post ID. * @return array The Place. */ public function get_location() { - if ( 'url' === $this->em_event->event_location_type ) { return null; } @@ -132,7 +124,6 @@ class Events_Manager extends Post { * Get the end time from the events metadata. */ protected function get_end_time() { - return null; } @@ -140,7 +131,6 @@ class Events_Manager extends Post { * Get the end time from the events metadata. */ protected function get_start_time() { - $date_string = $this->em_event->event_start_date; $time_string = $this->em_event->event_start_time; $timezone_string = $this->em_event->event_timezone; @@ -157,7 +147,6 @@ class Events_Manager extends Post { } protected function get_maximum_attendee_capacity() { - return $this->em_event->event_spaces; } @@ -165,25 +154,21 @@ class Events_Manager extends Post { * @todo decide whether to include pending bookings or not! */ protected function get_remaining_attendee_capacity() { - $em_bookings = $this->em_event->get_bookings()->get_bookings(); $remaining_attendee_capacity = $this->em_event->event_spaces - count( $em_bookings->bookings ); return $remaining_attendee_capacity; } protected function get_participant_count() { - $em_bookings = $this->em_event->get_bookings()->get_bookings(); return count( $em_bookings->bookings ); } protected function get_content() { - return $this->wp_object->post_content; } protected function get_summary() { - if ( $this->em_event->post_excerpt ) { $excerpt = $this->em_event->post_excerpt; } else { @@ -202,7 +187,6 @@ class Events_Manager extends Post { // } private function get_event_link_attachment() { - $event_link_url = $this->em_event->event_location->data['url']; $event_link_text = $this->em_event->event_location->data['text']; return array( @@ -218,7 +202,7 @@ class Events_Manager extends Post { * Overrides/extends the get_attachments function to also add the event Link. */ protected function get_attachment() { - // Get attachments via parent function + // Get attachments via parent function. $attachments = parent::get_attachment(); // The first attachment is the featured image, make sure it is compatible with Mobilizon. diff --git a/includes/activitypub/transformer/class-gatherpress.php b/includes/activitypub/transformer/class-gatherpress.php index c6fd70a..a86dde1 100644 --- a/includes/activitypub/transformer/class-gatherpress.php +++ b/includes/activitypub/transformer/class-gatherpress.php @@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) { class GatherPress extends Post { /** - * The target transformet ActivityPub Event object. + * The target ActivityPub Event object of the transformer. * * @var Event */ diff --git a/includes/activitypub/transformer/class-tribe.php b/includes/activitypub/transformer/class-tribe.php index b67d3ae..3727e99 100644 --- a/includes/activitypub/transformer/class-tribe.php +++ b/includes/activitypub/transformer/class-tribe.php @@ -11,7 +11,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } -use Activitypub\Transformer\Post; +use Activitypub_Event_Extensions\Activitypub\Transformer\Event as Event_Transformer; use Activitypub\Activity\Extended_Object\Event; use Activitypub\Activity\Extended_Object\Place; @@ -20,7 +20,7 @@ use Activitypub\Activity\Extended_Object\Place; * * @since 1.0.0 */ -class Tribe extends Post { +class Tribe extends Event_Transformer { /** * The Tribe Event object. diff --git a/includes/activitypub/transformer/class-vs-event.php b/includes/activitypub/transformer/class-vs-event.php index 4eaa23e..5e01d27 100644 --- a/includes/activitypub/transformer/class-vs-event.php +++ b/includes/activitypub/transformer/class-vs-event.php @@ -1,5 +1,4 @@ get_event_link(); if ( $event_link ) { - $attachments[] = $this->get_event_link(); + $attachments[] = $event_link; } return $attachments; } @@ -159,47 +160,7 @@ class VS_Event extends Post { * @return string $category */ protected function get_category() { - - $post_categories = wp_get_post_terms( $this->wp_object->ID, 'event_cat' ); - - if ( empty( $post_categories ) ) { - return 'MEETING'; - } - - // Prepare an array to store all category information for comparison. - $category_info = array(); - - // Extract relevant category information (name, slug, description) from the categories array. - foreach ( $post_categories as $category ) { - $category_info[] = strtolower( $category->name ); - $category_info[] = strtolower( $category->slug ); - $category_info[] = strtolower( $category->description ); - } - - // Convert mobilizon categories to lowercase for case-insensitive comparison. - $mobilizon_categories = array_map( 'strtolower', Event::DEFAULT_EVENT_CATEGORIES ); - - // Initialize variables to track the best match. - $best_mobilizon_category_match = ''; - $best_match_length = 0; - - // Check for the best match. - foreach ( $mobilizon_categories as $mobilizon_category ) { - foreach ( $category_info as $category ) { - foreach ( explode( '_', $mobilizon_category ) as $mobilizon_category_slice ) { - if ( stripos( $category, $mobilizon_category_slice ) !== false ) { - // Check if the current match is longer than the previous best match. - $current_match_legnth = strlen( $mobilizon_category_slice ); - if ( $current_match_legnth > $best_match_length ) { - $best_mobilizon_category_match = $mobilizon_category; - $best_match_length = $current_match_legnth; - } - } - } - } - } - - return ( '' != $best_mobilizon_category_match ) ? strtoupper( $best_mobilizon_category_match ) : 'MEETING'; + return 'MEETING'; } /** @@ -210,8 +171,7 @@ class VS_Event extends Post { * @return string The User-URL. */ protected function get_attributed_to() { - - $user = new Blog_User(); + $user = new Blog(); return $user->get_url(); } @@ -224,7 +184,6 @@ class VS_Event extends Post { * @return string $summary The custom event summary. */ public function get_summary() { - if ( $this->wp_object->excerpt ) { $excerpt = $this->wp_object->post_excerpt; } elseif ( get_post_meta( $this->wp_object->ID, 'event-summary', true ) ) { @@ -315,7 +274,8 @@ class VS_Event extends Post { ->set_in_language( $this->get_locale() ) ->set_actor( get_rest_url_by_path( 'application' ) ) ->set_to( array( 'https://www.w3.org/ns/activitystreams#Public' ) ) - ->set_location(); + ->set_location() + ->set_id(); return $this->ap_object; } } diff --git a/includes/category-mapper.php b/includes/category-mapper.php deleted file mode 100644 index 3ba9f75..0000000 --- a/includes/category-mapper.php +++ /dev/null @@ -1,67 +0,0 @@ -name ); - $category_info[] = strtolower( $category->slug ); - $category_info[] = strtolower( $category->description ); - } - - // Convert mobilizon categories to lowercase for case-insensitive comparison. - $mobilizon_categories = array_map( 'strtolower', Event::DEFAULT_EVENT_CATEGORIES ); - - // Initialize variables to track the best match. - $best_mobilizon_category_match = ''; - $best_match_length = 0; - - // Check for the best match. - foreach ( $mobilizon_categories as $mobilizon_category ) { - foreach ( $category_info as $category ) { - foreach ( explode( '_', $mobilizon_category ) as $mobilizon_category_slice ) { - if ( stripos( $category, $mobilizon_category_slice ) !== false ) { - // Check if the current match is longer than the previous best match. - $current_match_legnth = strlen( $mobilizon_category_slice ); - if ( $current_match_legnth > $best_match_length ) { - $best_mobilizon_category_match = $mobilizon_category; - $best_match_length = $current_match_legnth; - } - } - } - } - } - - return ( '' != $best_mobilizon_category_match ) ? strtoupper( $best_mobilizon_category_match ) : 'MEETING'; - } -} diff --git a/includes/class-admin-notices.php b/includes/class-admin-notices.php new file mode 100644 index 0000000..6749fa8 --- /dev/null +++ b/includes/class-admin-notices.php @@ -0,0 +1,93 @@ +event_plugin = $event_plugin; + if ( $this->event_post_type_is_not_activitypub_enabled() ) { + add_action( 'admin_notices', array( $this, 'admin_notice_activitypub_not_enabled_for_post_type' ), 10, 1 ); + } + } + + /** + * Check if ActivityPub is enabled for the custom post type of the event plugin. + * + * @return bool + */ + private function event_post_type_is_not_activitypub_enabled() { + return ! in_array( $this->event_plugin['post_type'], get_option( 'activitypub_support_post_types', array() ), true ); + } + + /** + * Display the admin notices for the plugins. + */ + public function admin_notice_activitypub_not_enabled_for_post_type() { + // Get the current page. + $screen = get_current_screen(); + // Check if we are on a edit page for the event, or on the settings page of the event plugin. + $is_event_plugins_edit_page = 'edit' === $screen->base && $this->event_plugin['post_type'] === $screen->event_post_type; + $is_event_plugins_settings_page = $this->event_plugin['settings_page_id'] === $screen->id; + + if ( $is_event_plugins_edit_page || $is_event_plugins_settings_page ) { + $this->do_admin_notice_post_type_not_activitypub_enabled( $this->event_plugin['plugin_file'] ); + } + } + + /** + * Print admin notice that the current post type is not enabled in the ActivityPub plugin. + * + * @param string $event_plugin_file The event plugin file path. + */ + private function do_admin_notice_post_type_not_activitypub_enabled( $event_plugin_file ) { + $event_plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . $event_plugin_file ); + $activitypub_plugin_data = get_plugin_data( ACTIVITYPUB_PLUGIN_FILE ); + $notice = sprintf( + /* translators: 1: the name of the event plugin a admin notice is shown. 2: The name of the ActivityPub plugin. */ + _x( + 'You have installed the %1$s plugin, but the event post type of the plugin %2$s is not enabled in the %1$s settings.', + 'admin notice', + 'activitypub-event-extensions' + ), + esc_html( $activitypub_plugin_data['Name'] ), + esc_html( $event_plugin_data['Name'] ), + admin_url( 'options-general.php?page=activitypub&tab=settings' ) + ); + $allowed_html = array( + 'a' => array( + 'href' => true, + 'title' => true, + ), + 'b' => array(), + 'i' => array(), + ); + echo '

' . \wp_kses( $notice, $allowed_html ) . '

'; + } +} diff --git a/includes/class-autoloader.php b/includes/class-autoloader.php new file mode 100644 index 0000000..dcc18dc --- /dev/null +++ b/includes/class-autoloader.php @@ -0,0 +1,66 @@ + array( + 'plugin_file' => 'events-manager/events-manager.php', + 'post_type' => 'event', + 'settings_page' => 'options-general.php?page=vsel', + 'transformer_class' => 'Events_Manager', + ), + 'gatherpress' => array( + 'plugin_file' => 'gatherpress/gatherpress.php', + 'post_type' => 'gatherpress_event', + 'transformer_class' => 'GatherPress', + 'settings_page_id' => 'gatherpress_general', + ), + 'the_events_calendar' => array( + 'plugin_file' => 'the-events-calendar/the-events-calendar.php', + 'post_type' => 'tribe_events', + 'transformer_class' => 'Tribe_Events', + 'settings_page_id' => 'tribe_general', + ), + 'vsel' => array( + 'plugin_file' => 'very-simple-event-list/vsel.php', + 'post_type' => 'event', + 'settings_page_id' => 'settings_page_vsel', + 'transformer_class' => 'VS_Event', + ), + ); + + /** + * Holds an array of the currently activated supported event plugins. + * + * @var array + */ + protected $active_event_plugins = array(); + + /** + * Constructor for the Setup class. + * + * Initializes and sets up various components of the plugin. + * + * @since 1.0.0 + */ + protected function __construct() { + $this->active_event_plugins = self::detect_supported_event_plugins(); + if ( empty( $this->active_event_plugins ) ) { + return; + } + $this->setup_hooks(); + } + + /** + * The single instance of the class. + * + * @since 1.0.0 + * @var ?self|null The instance of the class. + */ + private static $instance = null; + + /** + * Get the instance of the Singleton class. + * + * If an instance does not exist, it creates one; otherwise, it returns the existing instance. + * + * @since 1.0.0 + * + * @return self The instance of the class. + */ + public static function get_instance(): self { + if ( null === self::$instance ) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Function that checks for supported activated event plugins. + * + * @return array List of supported event plugins as keys from the SUPPORTED_EVENT_PLUGINS const. + */ + public static function detect_supported_event_plugins(): array { + $active_event_plugins = array(); + foreach ( self::SUPPORTED_EVENT_PLUGINS as $event_plugin_key => $event_plugin ) { + if ( \is_plugin_active( $event_plugin['plugin_file'] ) ) { + $active_event_plugins[ $event_plugin_key ] = $event_plugin; + } + } + return $active_event_plugins; + } + + /** + * Set up hooks for various purposes. + * + * This method adds hooks for different purposes as needed. + * + * @since 1.0.0 + * + * @return void + */ + protected function setup_hooks(): void { + register_activation_hook( ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_FILE, array( $this, 'activate' ) ); + + add_action( 'admin_init', array( $this, 'do_admin_notices' ) ); + + add_filter( 'activitypub_transformer', array( $this, 'register_activitypub_event_transformer' ), 10, 3 ); + } + + /** + * Fires the initialization of admin notices for all active supported event plugins.s + */ + public function do_admin_notices(): void { + foreach ( $this->active_event_plugins as $event_plugin ) { + new Admin_Notices( $event_plugin ); + } + } + + /** + * Add the custom transformers for the events of several WordPress event plugins. + * + * @param Activitypub\Transformer\Base $transformer The transformer to use. + * @param mixed $wp_object The WordPress object to transform. + * @param string $object_class The class of the object to transform. + * + * @returns \Activitypub\Transformer\Base + */ + public function register_activitypub_event_transformer( $transformer, $wp_object, $object_class ): \Activitypub\Transformer\Base { + // If the current WordPress object is not a post (e.g., a WP_Comment), don't change the transformer. + if ( 'WP_Post' !== $object_class ) { + return $transformer; + } + + // Get the transformer for a specific event plugins event-post type. + foreach ( $this->active_event_plugins as $event_plugin ) { + if ( $wp_object->post_type === $event_plugin['post_type'] ) { + $transformer_class = 'Activitypub_Event_Extensions\Activitypub\Transformer\\' . $event_plugin['transformer_class']; + return new $transformer_class( $wp_object ); + } + } + + // Return the default transformer. + return $transformer; + } + + /** + * Activates the ActivityPub Event Extensions plugin. + * + * This method handles the activation of the ActivityPub Event Extensions plugin. + * + * @since 1.0.0 + * + * @return void + */ + public function activate() { + // Don't allow plugin activation, when the ActivityPub plugin is not activated yet. + if ( ! is_plugin_active( 'activitypub/activitypub.php' ) ) { + deactivate_plugins( plugin_basename( ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_FILE ) ); + wp_die( + esc_html_e( + 'Please install and activate the ActivityPub plugin first.', + 'activitypub-event-extensions', + ), + 'Plugin dependency check', + array( 'back_link' => true ), + ); + } + // If someone installs this plugin, we simply enable ActivityPub support for the event post type, without asking. + $activitypub_supported_post_types = get_option( 'activitypub_support_post_types', array() ); + foreach ( $this->active_event_plugins as $event_plugin ) { + if ( ! in_array( $event_plugin['post_type'], $activitypub_supported_post_types, true ) ) { + $activitypub_supported_post_types[] = $event_plugin['post_type']; + } + } + update_option( 'activitypub_support_post_types', $activitypub_supported_post_types ); + } +}