diff --git a/includes/activitypub/handler/class-create.php b/includes/activitypub/handler/class-create.php index 5dc3809..f83e42a 100644 --- a/includes/activitypub/handler/class-create.php +++ b/includes/activitypub/handler/class-create.php @@ -67,14 +67,13 @@ class Create { return; } - $transmogrifier_class = Setup::get_transmogrifier(); + $transmogrifier = Setup::get_transmogrifier(); - if ( ! $transmogrifier_class ) { + if ( ! $transmogrifier ) { return; } - $transmogrifier = new $transmogrifier_class( $activity['object'] ); - $transmogrifier->save(); + $transmogrifier->save( $activity['object'] ); } /** diff --git a/includes/activitypub/handler/class-delete.php b/includes/activitypub/handler/class-delete.php index 88558f2..9fa2224 100644 --- a/includes/activitypub/handler/class-delete.php +++ b/includes/activitypub/handler/class-delete.php @@ -47,13 +47,12 @@ class Delete { return; } - $transmogrifier_class = Setup::get_transmogrifier(); + $transmogrifier = Setup::get_transmogrifier(); - if ( ! $transmogrifier_class ) { + if ( ! $transmogrifier ) { return; } - $transmogrifier = new $transmogrifier_class( $activity['object'] ); - $transmogrifier->delete(); + $transmogrifier->delete( $activity['object'] ); } } diff --git a/includes/activitypub/transmogrifier/class-base.php b/includes/activitypub/transmogrifier/class-base.php index 0aceb09..b32d264 100644 --- a/includes/activitypub/transmogrifier/class-base.php +++ b/includes/activitypub/transmogrifier/class-base.php @@ -34,6 +34,8 @@ abstract class Base { /** * Internal function to actually save the event. + * + * @return false|int Post-ID on success, false on failure. */ abstract protected function save_event(); @@ -50,7 +52,13 @@ abstract class Base { } $this->activitypub_event = $activitypub_event; - $this->save_event(); + + $post_id = $this->save_event(); + + if ( $post_id ) { + update_post_meta( $post_id, 'event_bridge_for_activitypub_is_cached', 'yes' ); + update_post_meta( $post_id, 'activitypub_content_visibility', constant( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) ?? '' ); + } } /** @@ -287,9 +295,19 @@ abstract class Base { } /** - * Save the ActivityPub event object as GatherPress event. + * Delete a local event in WordPress that is a cached remote one. + * + * @param array $activitypub_event The ActivityPub event as associative array. */ - public function delete() { + public function delete( $activitypub_event ) { + $activitypub_event = Event::init_from_array( $activitypub_event ); + + if ( is_wp_error( $activitypub_event ) ) { + return; + } + + $this->activitypub_event = $activitypub_event; + $post_id = $this->get_post_id_from_activitypub_id(); if ( ! $post_id ) { diff --git a/includes/activitypub/transmogrifier/class-gatherpress.php b/includes/activitypub/transmogrifier/class-gatherpress.php index bb0170d..78128c6 100644 --- a/includes/activitypub/transmogrifier/class-gatherpress.php +++ b/includes/activitypub/transmogrifier/class-gatherpress.php @@ -120,9 +120,9 @@ class GatherPress extends Base { /** * Save the ActivityPub event object as GatherPress Event. * - * @return void + * @return false|int */ - protected function save_event(): void { + protected function save_event() { // Limit this as a safety measure. add_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) ); @@ -135,10 +135,6 @@ class GatherPress extends Base { 'post_excerpt' => wp_kses_post( $this->activitypub_event->get_summary() ), 'post_status' => 'publish', 'guid' => sanitize_url( $this->activitypub_event->get_id() ), - 'meta_input' => array( - 'event_bridge_for_activitypub_is_cached' => 'GatherPress', - 'activitypub_content_visibility' => ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL, - ), ); if ( $post_id ) { @@ -151,7 +147,7 @@ class GatherPress extends Base { } if ( ! $post_id || is_wp_error( $post_id ) ) { - return; + return false; } // Insert the dates. @@ -182,5 +178,7 @@ class GatherPress extends Base { // Limit this as a safety measure. remove_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) ); + + return $post_id; } } diff --git a/includes/admin/class-user-interface.php b/includes/admin/class-user-interface.php index 9a3046f..52381e3 100644 --- a/includes/admin/class-user-interface.php +++ b/includes/admin/class-user-interface.php @@ -28,15 +28,7 @@ class User_Interface { public static function init() { \add_filter( 'page_row_actions', array( self::class, 'row_actions' ), 10, 2 ); \add_filter( 'post_row_actions', array( self::class, 'row_actions' ), 10, 2 ); - \add_action( - 'admin_init', - \add_filter( - 'map_meta_cap', - array( self::class, 'disable_editing_for_external_events' ), - 10, - 4 - ) - ); + \add_filter( 'map_meta_cap', array( self::class, 'disable_editing_for_external_events' ), 10, 4 ); } /** diff --git a/includes/class-event-sources.php b/includes/class-event-sources.php index 25520de..8b8f629 100644 --- a/includes/class-event-sources.php +++ b/includes/class-event-sources.php @@ -14,7 +14,8 @@ use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_S use Event_Bridge_For_ActivityPub\Activitypub\Transmogrifier\GatherPress; use Event_Bridge_For_ActivityPub\Activitypub\Handler; use Event_Bridge_For_ActivityPub\Admin\User_Interface; - +use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration; +use Event_Bridge_For_ActivityPub\Integrations\Feature_Event_Sources; use function Activitypub\get_remote_metadata_by_actor; use function Activitypub\is_activitypub_request; @@ -31,7 +32,8 @@ class Event_Sources { public static function init() { \add_action( 'init', array( Event_Sources_Collection::class, 'init' ) ); \add_action( 'activitypub_register_handlers', array( Handler::class, 'register_handlers' ) ); - \add_action( 'admin_init', array( User_Interface::class, 'init' ) ); + \add_action( 'init', array( User_Interface::class, 'init' ) ); + \add_action( 'init', array( self::class, 'register_post_meta' ) ); \add_filter( 'activitypub_is_post_disabled', array( self::class, 'is_cached_external_post' ), 10, 2 ); if ( ! \wp_next_scheduled( 'event_bridge_for_activitypub_event_sources_clear_cache' ) ) { \wp_schedule_event( time(), 'daily', 'event_bridge_for_activitypub_event_sources_clear_cache' ); @@ -41,6 +43,31 @@ class Event_Sources { \add_filter( 'template_include', array( self::class, 'redirect_activitypub_requests_for_cached_external_events' ), 100 ); } + + /** + * Register post meta. + */ + public static function register_post_meta() { + $setup = Setup::get_instance(); + + foreach ( $setup->get_active_event_plugins() as $event_plugin_integration ) { + if ( ! $event_plugin_integration instanceof Feature_Event_Sources && $event_plugin_integration instanceof Event_Plugin_Integration ) { + continue; + } + \register_post_meta( + $event_plugin_integration::get_post_type(), + 'event_bridge_for_activitypub_is_cached', + array( + 'type' => 'string', + 'single' => false, + 'sanitize_callback' => function ( $value ) { + return esc_sql( $value ); + }, + ) + ); + } + } + /** * Get metadata of ActivityPub Actor by ID/URL. * @@ -117,7 +144,7 @@ class Event_Sources { * @return bool */ public static function is_cached_external_event_post( $post ): bool { - if ( get_post_meta( $post->id, 'event_bridge_for_activitypub_is_cached', true ) ) { + if ( get_post_meta( $post->ID, 'event_bridge_for_activitypub_is_cached', true ) ) { return true; } @@ -157,9 +184,18 @@ class Event_Sources { * Delete old cached events that took place in the past. */ public static function clear_cache() { + // Get the event plugin integration that is used. + $event_plugin_integration = Setup::get_event_plugin_integration_used_for_event_sources_feature(); + + if ( ! $event_plugin_integration ) { + return; + } + $cache_retention_period = get_option( 'event_bridge_for_activitypub_event_source_cache_retention', WEEK_IN_SECONDS ); - $past_event_ids = GatherPress::get_past_events( $cache_retention_period ); + $ended_before_time = gmdate( 'Y-m-d H:i:s', time() - $cache_retention_period ); + + $past_event_ids = $event_plugin_integration::get_cached_remote_events( $ended_before_time ); foreach ( $past_event_ids as $post_id ) { if ( has_post_thumbnail( $post_id ) ) { diff --git a/includes/class-settings.php b/includes/class-settings.php index d1fa7b4..a9a91f8 100644 --- a/includes/class-settings.php +++ b/includes/class-settings.php @@ -120,12 +120,12 @@ class Settings { \register_setting( 'event-bridge-for-activitypub', - 'event_bridge_for_activitypub_plugin_used_for_event_source_feature', + 'event_bridge_for_activitypub_integration_used_for_event_sources_feature', array( 'type' => 'array', 'description' => \__( 'Define which plugin/integration is used for the event sources feature', 'event-bridge-for-activitypub' ), 'default' => array(), - 'sanitize_callback' => array( self::class, 'sanitize_plugin_used_for_event_sources' ), + 'sanitize_callback' => array( self::class, 'sanitize_event_plugin_integration_used_for_event_sources' ), ) ); @@ -144,11 +144,11 @@ class Settings { /** * Sanitize the option which event plugin. * - * @param string $plugin The setting. + * @param string $event_plugin_integration The setting. * @return string */ - public static function sanitize_plugin_used_for_event_sources( $plugin ) { - if ( ! is_string( $plugin ) ) { + public static function sanitize_event_plugin_integration_used_for_event_sources( $event_plugin_integration ) { + if ( ! is_string( $event_plugin_integration ) ) { return ''; } $setup = Setup::get_instance(); @@ -157,14 +157,13 @@ class Settings { $valid_options = array(); foreach ( $active_event_plugins as $active_event_plugin ) { if ( $active_event_plugin instanceof Feature_Event_Sources ) { - $full_class = $active_event_plugin::class; - $valid_options[] = substr( $full_class, strrpos( $full_class, '\\' ) + 1 ); + $valid_options[] = $active_event_plugin::class; } } - if ( in_array( $plugin, $valid_options, true ) ) { - return $plugin; + if ( in_array( $event_plugin_integration, $valid_options, true ) ) { + return $event_plugin_integration; } - return ''; + return Setup::get_default_integration_class_name_used_for_event_sources_feature(); } /** diff --git a/includes/class-setup.php b/includes/class-setup.php index e3d3ca3..1c42639 100644 --- a/includes/class-setup.php +++ b/includes/class-setup.php @@ -15,12 +15,11 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore -use Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier\Base as Transmogrifier_Base; +use Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier\Base as Transmogrifier; use Event_Bridge_For_ActivityPub\Admin\Event_Plugin_Admin_Notices; use Event_Bridge_For_ActivityPub\Admin\General_Admin_Notices; use Event_Bridge_For_ActivityPub\Admin\Health_Check; use Event_Bridge_For_ActivityPub\Admin\Settings_Page; -use Event_Bridge_For_ActivityPub\Admin\User_Interface; use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin; use Event_Bridge_For_ActivityPub\Integrations\Feature_Event_Sources; @@ -381,42 +380,66 @@ class Setup { self::activate_activitypub_support_for_active_event_plugins(); } + /** + * Get the event plugin integration class name used for the event sources feature. + * + * @return string The class name of the event plugin integration class. + */ + public static function get_event_plugin_integration_used_for_event_sources_feature() { + // Get plugin option. + $event_plugin_integration = get_option( 'event_bridge_for_activitypub_integration_used_for_event_sources_feature', '' ); + + // Exit if event sources are not active or no plugin is specified. + if ( empty( $event_plugin_integration ) ) { + return null; + } + + // Validate if setting is actual existing class. + if ( ! class_exists( $event_plugin_integration ) ) { + return null; + } + + return $event_plugin_integration; + } + /** * Get the transmogrifier class. * * Retrieves the appropriate transmogrifier class based on the active event plugins and settings. * - * @return Transmogrifier_Base|null The transmogrifier class name or null if not available. + * @return ?Transmogrifier The transmogrifier class name or null if not available. */ - public static function get_transmogrifier() { - // Retrieve singleton instance. - $setup = self::get_instance(); + public static function get_transmogrifier(): ?Transmogrifier { + $event_plugin_integration = self::get_event_plugin_integration_used_for_event_sources_feature(); - // Get plugin options. - $event_sources_active = (bool) get_option( 'event_bridge_for_activitypub_event_sources_active', false ); - $event_plugin = get_option( 'event_bridge_for_activitypub_plugin_used_for_event_source_feature', '' ); - - // Exit if event sources are not active or no plugin is specified. - if ( ! $event_sources_active || empty( $event_plugin ) ) { + if ( ! $event_plugin_integration ) { return null; } - // Get the list of active event plugins. - $active_event_plugins = $setup->get_active_event_plugins(); - - // Loop through active plugins to find a match. - foreach ( $active_event_plugins as $active_event_plugin ) { - // Retrieve the class name of the active plugin. - $active_plugin_class_name = get_class( $active_event_plugin ); - - // Check if the active plugin class name contains the specified event plugin name. - if ( false !== strpos( $active_plugin_class_name, $event_plugin ) ) { - // Return the transmogrifier class provided by the plugin. - return $active_event_plugin->get_transmogrifier(); - } + // Validate if get_transformer method exists in event plugin integration. + if ( ! method_exists( $event_plugin_integration, 'get_transmogrifier' ) ) { + return null; } - // Return null if no matching plugin is found. - return null; + $transmogrifier = $event_plugin_integration::get_transmogrifier(); + + return $transmogrifier; + } + + /** + * Get the full class name of the first event plugin integration that is active and supports the event source feature. + * + * @return string The full class name of the event plugin integration. + */ + public static function get_default_integration_class_name_used_for_event_sources_feature(): string { + $setup = self::get_instance(); + + $event_plugin_integrations = $setup->get_active_event_plugins(); + foreach ( $event_plugin_integrations as $event_plugin_integration ) { + if ( $event_plugin_integration instanceof Feature_Event_Sources ) { + return $event_plugin_integration::class; + } + } + return ''; } } diff --git a/templates/settings.php b/templates/settings.php index 41b2c83..860fdaa 100644 --- a/templates/settings.php +++ b/templates/settings.php @@ -38,7 +38,7 @@ if ( ! isset( $args ) || ! array_key_exists( 'supports_event_sources', $args ) ) $event_plugins_supporting_event_sources = $args['supports_event_sources']; -$selected_plugin = \get_option( 'event_bridge_for_activitypub_plugin_used_for_event_source_feature', '' ); +$selected_plugin = \get_option( 'event_bridge_for_activitypub_integration_used_for_event_sources_feature', '' ); $event_sources_active = \get_option( 'event_bridge_for_activitypub_event_sources_active', false ); $cache_retention_period = \get_option( 'event_bridge_for_activitypub_event_source_cache_retention', DAY_IN_SECONDS ); @@ -128,18 +128,18 @@ $current_category_mapping = \get_option( 'event_bridge_for_activitypub_ev ?>