diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9a605a7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,12 @@ +# Changelog + +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). + +## [0.1.0] - 2024-10-20 + +### Added + +* Initial version tag. diff --git a/assets/css/activitypub-event-bridge-admin.css b/assets/css/activitypub-event-bridge-admin.css new file mode 100644 index 0000000..b6eaae1 --- /dev/null +++ b/assets/css/activitypub-event-bridge-admin.css @@ -0,0 +1,70 @@ +.activitypub-event-bridge-settings-page .box { + border: 1px solid #c3c4c7; + background-color: #fff; + padding: 1em 1.5em; + margin-bottom: 1.5em; +} + +.activitypub-event-bridge-settings-page .box ul.activitypub-event-bridge-list { + list-style-type: disc; + margin-left: 1.4rem; +} + +.activitypub-event-bridge-settings-page .box pre { + padding: 1rem; + min-height: 200px; + box-shadow: none; + border-radius: 15px; + border: 1px solid #dfe0e2; + background-color: #f7f7f7; +} + +.activitypub-event-bridge-settings { + max-width: 800px; + margin: 0 auto; +} + +.activitypub-event-bridge-settings-header { + text-align: center; + margin: 0 0 1rem; + background: #fff; + border-bottom: 1px solid #dcdcde; +} + +.activitypub-event-bridge-settings-title-section { + display: flex; + align-items: center; + justify-content: center; + clear: both; + padding-top: 8px; +} + +.activitypub-event-bridge-settings-tabs-wrapper { + display: -ms-inline-grid; + -ms-grid-columns: auto auto auto auto; + vertical-align: top; + display: inline-grid; + grid-template-columns: auto auto auto auto; +} + +.activitypub-event-bridge-settings-tab.active { + box-shadow: inset 0 -3px #3582c4; + font-weight: 600; +} + +.activitypub-event-bridge-settings-tab { + display: block; + text-decoration: none; + color: inherit; + padding: .5rem 1rem 1rem; + margin: 0 1rem; + transition: box-shadow .5s ease-in-out; +} + +.activitypub-event-bridge-settings .box h3 { + font-size: 1.1rem!important; +} + +#activitypub_event_bridge_initially_activated { + display: hidden; +} diff --git a/assets/css/activitypub-event-extensions-admin.css b/assets/css/activitypub-event-extensions-admin.css deleted file mode 100644 index c59d1a1..0000000 --- a/assets/css/activitypub-event-extensions-admin.css +++ /dev/null @@ -1,6 +0,0 @@ -.activitypub-event-bridge-settings-page .box { - border: 1px solid #c3c4c7; - background-color: #fff; - padding: 1em 1.5em; - margin-bottom: 1.5em; -} diff --git a/includes/admin/class-health-check.php b/includes/admin/class-health-check.php new file mode 100644 index 0000000..1f44905 --- /dev/null +++ b/includes/admin/class-health-check.php @@ -0,0 +1,181 @@ + __( 'ActivityPub Event Transformer Test', 'activitypub-event-bridge' ), + 'test' => array( self::class, 'test_event_transformation' ), + ); + + return $tests; + } + + /** + * The the transformation of the most recent event posts. + * + * @return array + */ + public static function test_event_transformation() { + $result = array( + 'label' => \__( 'Transformation of Events to a valid ActivityStreams representation.', 'activitypub' ), + 'status' => 'good', + 'badge' => array( + 'label' => \__( 'ActivityPub Event Bridge', 'activitypub-event-bridge' ), + 'color' => 'green', + ), + 'description' => \sprintf( + '
%s
', + \__( 'The transformation of your most recent events was successful.', 'activitypub-event-bridge' ) + ), + 'actions' => '', + 'test' => 'test_event_transformation', + ); + + $check = self::transform_most_recent_event_posts(); + + if ( true === $check ) { + return $result; + } + + $result['status'] = 'critical'; + $result['label'] = \__( 'One or more of your most recent events failed to transform to ActivityPub', 'activitypub-event-bridge' ); + $result['badge']['color'] = 'red'; + $result['description'] = \sprintf( + '%s
', + $check->get_error_message() + ); + + return $result; + } + + /** + * Test if right transformer gets applied. + * + * @param Event_Plugin $event_plugin The event plugin definition. + * + * @return bool True if the check passed. + */ + public static function test_if_event_transformer_is_used( $event_plugin ) { + // Get a (random) event post. + $event_posts = self::get_most_recent_event_posts( $event_plugin->get_post_type(), 1 ); + + // If no post is found, we can not do this test. + if ( ! $event_posts || is_wp_error( $event_posts ) || empty( $event_posts ) ) { + return true; + } + + // Call the transformer Factory. + $transformer = Transformer_Factory::get_transformer( $event_posts[0] ); + // Check that we got the right transformer. + $desired_transformer_class = $event_plugin::get_activitypub_event_transformer_class(); + if ( $transformer instanceof $desired_transformer_class ) { + return true; + } + return false; + } + + /** + * Retrieves the most recently published event posts of a certain event post type. + * + * @param string $event_post_type The post type of the events. + * @param int $number_of_posts The maximum number of events to return. + * + * @return WP_Post[]|false Array of event posts, or false if none are found. + */ + public static function get_most_recent_event_posts( $event_post_type, $number_of_posts = 5 ) { + $args = array( + 'numberposts' => $number_of_posts, + 'category' => 0, + 'orderby' => 'date', + 'order' => 'DESC', + 'include' => array(), + 'exclude' => array(), + 'meta_key' => '', + 'meta_value' => '', + 'post_type' => $event_post_type, + 'suppress_filters' => true, + ); + + $query = new WP_Query(); + return $query->query( $args ); + } + + /** + * Transform the most recent event posts. + */ + public static function transform_most_recent_event_posts() { + return true; + } + + /** + * Retrieves information like name and version from active event plugins. + */ + private static function get_info_about_active_event_plugins() { + $active_event_plugins = Setup::get_instance()->get_active_event_plugins(); + $info = array(); + foreach ( $active_event_plugins as $active_event_plugin ) { + $event_plugin_file = $active_event_plugin->get_plugin_file(); + $event_plugin_data = \get_plugin_data( $event_plugin_file ); + $event_plugin_name = isset( $event_plugin_data['Plugin Name'] ) ? $event_plugin_data['Plugin Name'] : 'Name not found'; + $event_plugin_version = isset( $event_plugin_version['Plugin Version'] ) ? $event_plugin_version['Plugin Version'] : 'Version not found'; + + $info[] = array( + 'event_plugin_name' => $event_plugin_name, + 'event_plugin_version' => $event_plugin_version, + 'event_plugin_file' => $event_plugin_file, + ); + } + } + + /** + * Static function for generating site debug data when required. + * + * @param array $info The debug information to be added to the core information page. + * @return array The extended information. + */ + public static function add_debug_information( $info ) { + $info['activitypub_event_bridge'] = array( + 'label' => __( 'ActivityPub Event Bridge', 'activitypub-event-bridge' ), + 'fields' => array( + 'plugin_version' => array( + 'label' => __( 'Plugin Version', 'activitypub' ), + 'value' => ACTIVITYPUB_EVENT_BRIDGE_PLUGIN_VERSION, + 'private' => true, + ), + 'active_event_plugins' => self::get_info_about_active_event_plugins(), + ), + ); + + return $info; + } +} diff --git a/includes/admin/class-settings-page.php b/includes/admin/class-settings-page.php index 08a36d6..9694d98 100644 --- a/includes/admin/class-settings-page.php +++ b/includes/admin/class-settings-page.php @@ -89,21 +89,41 @@ class Settings_Page { * @return void */ public static function settings_page(): void { - $plugin_setup = Setup::get_instance(); - - $event_plugins = $plugin_setup->get_active_event_plugins(); - - $event_terms = array(); - - foreach ( $event_plugins as $event_plugin ) { - $event_terms = array_merge( $event_terms, self::get_event_terms( $event_plugin ) ); + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( empty( $_GET['tab'] ) ) { + $tab = 'welcome'; + } else { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $tab = sanitize_key( $_GET['tab'] ); } - $args = array( - 'slug' => self::SETTINGS_SLUG, - 'event_terms' => $event_terms, - ); + switch ( $tab ) { + case 'settings': + $plugin_setup = Setup::get_instance(); - \load_template( ACTIVITYPUB_EVENT_BRIDGE_PLUGIN_DIR . 'templates/settings.php', true, $args ); + $event_plugins = $plugin_setup->get_active_event_plugins(); + + $event_terms = array(); + + foreach ( $event_plugins as $event_plugin ) { + $event_terms = array_merge( $event_terms, self::get_event_terms( $event_plugin ) ); + } + + $args = array( + 'slug' => self::SETTINGS_SLUG, + 'event_terms' => $event_terms, + ); + + \load_template( ACTIVITYPUB_EVENT_BRIDGE_PLUGIN_DIR . 'templates/settings.php', true, $args ); + break; + case 'welcome': + default: + wp_enqueue_script( 'plugin-install' ); + add_thickbox(); + wp_enqueue_script( 'updates' ); + + \load_template( ACTIVITYPUB_EVENT_BRIDGE_PLUGIN_DIR . 'templates/welcome.php', true ); + break; + } } } diff --git a/includes/class-settings.php b/includes/class-settings.php index 922531f..e5f69f0 100644 --- a/includes/class-settings.php +++ b/includes/class-settings.php @@ -61,6 +61,16 @@ class Settings { 'sanitize_callback' => array( self::class, 'sanitize_event_category_mappings' ), ) ); + + \register_setting( + 'activitypub-event-bridge', + 'activitypub_event_bridge_initially_activated', + array( + 'type' => 'boolean', + 'description' => \__( 'Whether the plugin just got activated for the first time.', 'activitypub' ), + 'default' => 1, + ) + ); } /** diff --git a/includes/class-setup.php b/includes/class-setup.php index a03c988..e9b602c 100644 --- a/includes/class-setup.php +++ b/includes/class-setup.php @@ -17,6 +17,7 @@ defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use ActivityPub_Event_Bridge\Admin\Event_Plugin_Admin_Notices; use ActivityPub_Event_Bridge\Admin\General_Admin_Notices; +use ActivityPub_Event_Bridge\Admin\Health_Check; use ActivityPub_Event_Bridge\Admin\Settings_Page; use ActivityPub_Event_Bridge\Plugins\Event_Plugin; @@ -167,20 +168,19 @@ class Setup { add_action( 'admin_init', array( $this, 'do_admin_notices' ) ); add_action( 'admin_init', array( Settings::class, 'register_settings' ) ); + add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_styles' ) ); + add_action( 'admin_menu', array( Settings_Page::class, 'admin_menu' ) ); + add_filter( + 'plugin_action_links_' . ACTIVITYPUB_EVENT_BRIDGE_PLUGIN_BASENAME, + array( Settings_Page::class, 'settings_link' ) + ); // If we don't have any active event plugins, or the ActivityPub plugin is not enabled, abort here. if ( empty( $this->active_event_plugins ) || ! $this->activitypub_plugin_is_active ) { return; } - add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_styles' ) ); - - add_action( 'admin_menu', array( Settings_Page::class, 'admin_menu' ) ); - - add_filter( - 'plugin_action_links_' . ACTIVITYPUB_EVENT_BRIDGE_PLUGIN_BASENAME, - array( Settings_Page::class, 'settings_link' ) - ); + add_action( 'init', array( Health_Check::class, 'init' ) ); // Check if the minimum required version of the ActivityPub plugin is installed. if ( ! version_compare( $this->activitypub_plugin_version, ACTIVITYPUB_EVENT_BRIDGE_ACTIVITYPUB_PLUGIN_MIN_VERSION ) ) { @@ -287,7 +287,7 @@ class Setup { * This method handles the activation of the ActivityPub Event Bridge plugin. * * @since 1.0.0 - * + * @see register_activation_hook() * @return void */ public function activate(): void { diff --git a/includes/plugins/class-event-plugin.php b/includes/plugins/class-event-plugin.php index f70cfa0..a5c5734 100644 --- a/includes/plugins/class-event-plugin.php +++ b/includes/plugins/class-event-plugin.php @@ -45,12 +45,24 @@ abstract class Event_Plugin { abstract public static function get_event_category_taxonomy(): string; /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The IDs of one or several admin/settings pages. */ - public static function get_settings_page(): string { - return ''; + public static function get_settings_pages(): array { + return array(); + } + + /** + * Get the plugins name from the main plugin-file's top-level-file-comment. + */ + final public static function get_plugin_name(): string { + $plugin_data = get_plugin_data( WP_PLUGIN_DIR . '/' . static::get_plugin_file() ); + if ( isset( $plugin_data['Name'] ) ) { + return $plugin_data['Name']; + } else { + return ''; + } } /** @@ -62,7 +74,7 @@ abstract class Event_Plugin { // 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 && static::get_post_type() === $screen->post_type; - $is_event_plugins_settings_page = static::get_settings_page() === $screen->id; + $is_event_plugins_settings_page = in_array( $screen->id, static::get_settings_pages(), true ); return $is_event_plugins_edit_page || $is_event_plugins_settings_page; } diff --git a/includes/plugins/class-eventin.php b/includes/plugins/class-eventin.php index fcab7c8..6584e85 100644 --- a/includes/plugins/class-eventin.php +++ b/includes/plugins/class-eventin.php @@ -41,12 +41,12 @@ final class Eventin extends Event_plugin { } /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The settings page url. */ - public static function get_settings_page(): string { - return 'eventin'; // Base always is wp-admin/admin.php?page=eventin. + public static function get_settings_pages(): array { + return array( 'eventin' ); // Base always is wp-admin/admin.php?page=eventin. } /** diff --git a/includes/plugins/class-events-manager.php b/includes/plugins/class-events-manager.php index feffcc5..02ca060 100644 --- a/includes/plugins/class-events-manager.php +++ b/includes/plugins/class-events-manager.php @@ -41,12 +41,12 @@ final class Events_Manager extends Event_Plugin { } /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The settings page urls. */ - public static function get_settings_page(): string { - return 'wp-admin/edit.php?post_type=event&page=events-manager-options#general'; + public static function get_settings_page(): array { + return array(); } /** diff --git a/includes/plugins/class-gatherpress.php b/includes/plugins/class-gatherpress.php index dead962..6c6af0f 100644 --- a/includes/plugins/class-gatherpress.php +++ b/includes/plugins/class-gatherpress.php @@ -41,12 +41,12 @@ final class GatherPress extends Event_Plugin { } /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The settings page urls. */ - public static function get_settings_page(): string { - return class_exists( '\GatherPress\Core\Utility' ) ? \GatherPress\Core\Utility::prefix_key( 'general' ) : 'gatherpress_general'; + public static function get_settings_pages(): array { + return array( class_exists( '\GatherPress\Core\Utility' ) ? \GatherPress\Core\Utility::prefix_key( 'general' ) : 'gatherpress_general' ); } /** diff --git a/includes/plugins/class-modern-events-calendar-lite.php b/includes/plugins/class-modern-events-calendar-lite.php index f8f5552..796634d 100644 --- a/includes/plugins/class-modern-events-calendar-lite.php +++ b/includes/plugins/class-modern-events-calendar-lite.php @@ -42,12 +42,12 @@ final class Modern_Events_Calendar_Lite extends Event_plugin { } /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The settings page urls. */ - public static function get_settings_page(): string { - return 'mec-event'; + public static function get_settings_pages(): array { + return array( 'MEC-settings', 'MEC-support', 'MEC-ix', 'MEC-wizard', 'MEC-addons', 'mec-intro' ); } /** diff --git a/includes/plugins/class-the-events-calendar.php b/includes/plugins/class-the-events-calendar.php index ef07590..36ab8e0 100644 --- a/includes/plugins/class-the-events-calendar.php +++ b/includes/plugins/class-the-events-calendar.php @@ -41,17 +41,17 @@ final class The_Events_Calendar extends Event_plugin { } /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The settings page urls. */ - public static function get_settings_page(): string { + public static function get_settings_pages(): array { if ( class_exists( '\Tribe\Events\Admin\Settings' ) ) { $page = \Tribe\Events\Admin\Settings::$settings_page_id; } else { $page = 'tec-events-settings'; } - return sprintf( 'edit.php?post_type=tribe_events&page=%s', $page ); + return array( $page ); } /** diff --git a/includes/plugins/class-vs-event-list.php b/includes/plugins/class-vs-event-list.php index 0e1b0dc..f1bd96b 100644 --- a/includes/plugins/class-vs-event-list.php +++ b/includes/plugins/class-vs-event-list.php @@ -44,12 +44,12 @@ final class VS_Event_List extends Event_Plugin { } /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The settings page urls. */ - public static function get_settings_page(): string { - return 'settings_page_vsel'; + public static function get_settings_pages(): array { + return array( 'settings_page_vsel' ); } /** diff --git a/includes/plugins/class-wp-event-manager.php b/includes/plugins/class-wp-event-manager.php index e3d3493..28a852a 100644 --- a/includes/plugins/class-wp-event-manager.php +++ b/includes/plugins/class-wp-event-manager.php @@ -44,12 +44,12 @@ final class WP_Event_Manager extends Event_Plugin { } /** - * Returns the ID of the main settings page of the plugin. + * Returns the IDs of the admin pages of the plugin. * - * @return string The settings page url. + * @return array The settings page urls. */ - public static function get_settings_page(): string { - return 'event-manager-settings'; + public static function get_settings_pages(): array { + return array( 'event-manager-settings' ); } /** diff --git a/templates/admin-header.php b/templates/admin-header.php new file mode 100644 index 0000000..efc02bc --- /dev/null +++ b/templates/admin-header.php @@ -0,0 +1,33 @@ + '', + 'settings' => '', + ) +); +?> + +