updated plugin Event Bridge for ActivityPub version 1.3.0

This commit is contained in:
2026-06-03 21:28:57 +00:00
committed by Gitium
parent 1f3438440f
commit f2d6714572
84 changed files with 1721 additions and 1361 deletions

View File

@ -10,7 +10,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
use Activitypub\Activity\Extended_Object\Event;
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources;
@ -48,9 +48,18 @@ abstract class Base {
return;
}
// Add hook to insert post meta to flag post as remote and remember where we received it from.
$add_origin_post_meta_callback = function ( $post_id ) use ( $event_source_post_id ): void {
self::add_origin_post_meta( $post_id, $event_source_post_id );
};
\add_action( 'wp_after_insert_post', $add_origin_post_meta_callback, 10, 1 );
// Pass the saving to the actual Transmogrifier implementation.
$post_id = static::save_event( $activitypub_event, $event_source_post_id );
// Remove hook added above.
\remove_action( 'wp_after_insert_post', $add_origin_post_meta_callback, 10 );
// Post processing: Logging and marking the imported event's origin.
$event_activitypub_id = $activitypub_event->get_id();
$event_source_activitypub_id = \get_the_guid( $event_source_post_id );
@ -60,9 +69,6 @@ abstract class Base {
'event_bridge_for_activitypub_write_log',
array( "[ACTIVITYPUB] Processed incoming event {$event_activitypub_id} from {$event_source_activitypub_id}" )
);
// Use post meta to remember who we received this event from.
\update_post_meta( $post_id, '_event_bridge_for_activitypub_event_source', absint( $event_source_post_id ) );
\update_post_meta( $post_id, 'activitypub_content_visibility', defined( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) ? constant( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) : '' );
} else {
\do_action(
'event_bridge_for_activitypub_write_log',
@ -71,6 +77,20 @@ abstract class Base {
}
}
/**
* Insert post meta to remember who we received an event from.
*
* @param int $post_id The WordPress post ID of the event itself.
* @param int $event_source_post_id The WordPress post ID of the event source custom post type.
*
* @return void
*/
public static function add_origin_post_meta( $post_id, $event_source_post_id ): void {
// Use post meta to remember who we received this event from.
\update_post_meta( $post_id, '_event_bridge_for_activitypub_event_source', absint( $event_source_post_id ) );
\update_post_meta( $post_id, 'activitypub_content_visibility', defined( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) ? constant( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL' ) : '' );
}
/**
* Delete a local event in WordPress that is a cached remote one.
*
@ -129,6 +149,8 @@ abstract class Base {
*/
protected static function get_post_id_from_activitypub_id( $activitypub_id ): int {
global $wpdb;
// phpcs:disable WordPress.DB.DirectDatabaseQuery
return (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT ID FROM $wpdb->posts WHERE guid=%s",
@ -227,15 +249,13 @@ abstract class Base {
// Include necessary WordPress file for media handling.
if ( ! function_exists( 'media_sideload_image' ) ) {
// @phpstan-ignore-next-line
require_once ABSPATH . 'wp-admin/includes/media.php';
// @phpstan-ignore-next-line
require_once ABSPATH . 'wp-admin/includes/file.php';
// @phpstan-ignore-next-line
require_once ABSPATH . 'wp-admin/includes/image.php';
}
// Check to see if the URL has already been fetched, if so return the attachment ID.
// phpcs:disable WordPress.DB.DirectDatabaseQuery
$attachment_id = $wpdb->get_var(
$wpdb->prepare( "SELECT `post_id` FROM {$wpdb->postmeta} WHERE `meta_key` = '_source_url' AND `meta_value` = %s", $url )
);
@ -243,6 +263,7 @@ abstract class Base {
return $attachment_id;
}
// phpcs:disable WordPress.DB.DirectDatabaseQuery
$attachment_id = $wpdb->get_var(
$wpdb->prepare( "SELECT `ID` FROM {$wpdb->posts} WHERE guid=%s", $url )
);

View File

@ -12,7 +12,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
use Activitypub\Activity\Extended_Object\Event;
use Activitypub\Activity\Extended_Object\Place;
@ -40,7 +40,7 @@ class GatherPress extends Base {
$tags_array = $event->get_tag();
// Ensure the input is valid.
if ( empty( $tags_array ) || ! is_array( $tags_array ) || ! $post_id ) {
if ( empty( $tags_array ) || ! $post_id ) {
return false;
}

View File

@ -12,7 +12,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
use Activitypub\Activity\Extended_Object\Event;
use Activitypub\Activity\Extended_Object\Place;
@ -43,19 +43,18 @@ class The_Events_Calendar extends Base {
add_filter( 'wp_revisions_to_keep', array( self::class, 'revisions_to_keep' ) );
$post_id = self::get_post_id_from_activitypub_id( $activitypub_event->get_id() );
$duration = self::get_duration( $activitypub_event );
$venue_id = self::add_venue( $activitypub_event, $event_source_post_id );
$organizer_id = self::add_organizer( $activitypub_event );
$args = array(
'title' => $activitypub_event->get_name(),
'content' => $activitypub_event->get_content() ?? '',
'start_date' => gmdate( 'Y-m-d H:i:s', strtotime( $activitypub_event->get_start_time() ) ),
'duration' => $duration,
'status' => 'publish',
'guid' => $activitypub_event->get_id(),
'title' => $activitypub_event->get_name(),
'content' => $activitypub_event->get_content() ?? '',
'status' => 'publish',
'guid' => $activitypub_event->get_id(),
);
$args = self::enrich_event_args_with_date_info( $args, $activitypub_event );
if ( $venue_id ) {
$args['venue'] = $venue_id;
$args['VenueID'] = $venue_id;
@ -103,6 +102,33 @@ class The_Events_Calendar extends Base {
return $post_id;
}
/**
* Enrich event arguments with normalized start date and timezone.
*
* @param array $args Existing event arguments.
* @param Event $activitypub_event The ActivityPub event as associative array.
* @return array Modified $args array including 'start_date' and 'timezone' and 'duration'.
*/
private static function enrich_event_args_with_date_info( $args, $activitypub_event ): array {
$start_time_str = $activitypub_event->get_start_time();
$timezone_string = $activitypub_event->get_timezone();
$start_time = new \DateTime( $start_time_str );
if ( empty( $timezone_string ) ) {
$timezone_string = 'UTC';
}
$start_time->setTimezone( new \DateTimeZone( $timezone_string ) );
$args['timezone'] = $timezone_string;
$args['start_date'] = $start_time->format( 'Y-m-d H:i:s' );
$args['duration'] = self::get_duration( $activitypub_event );
return $args;
}
/**
* Map an ActivityStreams Place to the Events Calendar venue.
*
@ -148,6 +174,14 @@ class The_Events_Calendar extends Base {
$args['guid'] = $location['id'];
}
if ( isset( $location['latitude'] ) ) {
$args['latitude'] = $location['latitude'];
}
if ( isset( $location['longitude'] ) ) {
$args['longitude'] = $location['longitude'];
}
return $args;
}
@ -210,7 +244,6 @@ class The_Events_Calendar extends Base {
$results = $tribe_venue->search( $location['name'] )->all();
foreach ( $results as $potential_matching_post_id ) {
// @phpstan-ignore-next-line
if ( $potential_matching_post_id instanceof \WP_Post ) {
$potential_matching_post_id = $potential_matching_post_id->ID;
}
@ -251,6 +284,13 @@ class The_Events_Calendar extends Base {
// This might likely change, because of FEP-8a8e.
$actor = $activitypub_event->get_attributed_to();
/**
* Allow filtering of incoming organizer.
*
* @var mixed
*/
$actor = \apply_filters( 'event_bridge_for_activitypub_remote_organizer', $actor, $activitypub_event );
if ( is_null( $actor ) ) {
return false;
}
@ -270,6 +310,7 @@ class The_Events_Calendar extends Base {
'website' => $event_source->get_url(),
'excerpt' => $event_source->get_summary(),
'post_parent' => $event_source->get__id(), // Maybe just use post meta too here.
'post_status' => 'publish',
);
if ( $event_source->get_published() ) {
@ -334,7 +375,7 @@ class The_Events_Calendar extends Base {
$tags_array = $activitypub_event->get_tag();
// Ensure the input is valid.
if ( empty( $tags_array ) || ! is_array( $tags_array ) || ! $post_id ) {
if ( empty( $tags_array ) || ! $post_id ) {
return false;
}

View File

@ -13,7 +13,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
use Activitypub\Activity\Extended_Object\Event;
use Activitypub\Activity\Extended_Object\Place;
@ -77,7 +77,7 @@ class VS_Event_List extends Base {
$tags_array = $activitypub_event->get_tag();
// Ensure the input is valid.
if ( empty( $tags_array ) || ! is_array( $tags_array ) || ! $post_id ) {
if ( empty( $tags_array ) || ! $post_id ) {
return false;
}

View File

@ -13,7 +13,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier\Helper;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
use Activitypub\Activity\Extended_Object\Event;
use Activitypub\Activity\Extended_Object\Place;
@ -67,6 +67,10 @@ class Sanitizer {
$event->set_end_time( \sanitize_text_field( $data['endTime'] ) );
}
if ( isset( $data['timezone'] ) && in_array( $data['timezone'], \DateTimeZone::listIdentifiers(), true ) ) {
$event->set_timezone( \sanitize_text_field( $data['timezone'] ) );
}
if ( isset( $data['published'] ) ) {
$event->set_published( \sanitize_text_field( $data['published'] ) );
}
@ -177,6 +181,17 @@ class Sanitizer {
return array_is_list( $arr );
}
/**
* Sanitize an validate a float.
*
* @param mixed $value The input value.
* @return float|null
*/
private static function validate_and_sanitize_float( $value ) {
$sanitized = filter_var( $value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION );
return is_numeric( $sanitized ) ? (float) $sanitized : null;
}
/**
* Convert input array to an Location.
*
@ -189,9 +204,18 @@ class Sanitizer {
return null;
}
// If the array is a list, work with the first item.
if ( array_key_exists( 0, $data ) ) {
$data = $data[0];
// If the array is a list, search for the first item with 'type' === 'Place'.
if ( self::array_is_list( $data ) ) {
foreach ( $data as $item ) {
if ( is_array( $item ) && ( 'Place' === ( $item['type'] ?? null ) ) ) {
$data = $item;
break;
}
}
}
if ( ! isset( $data['type'] ) || 'Place' !== $data['type'] ) {
return null;
}
$place = new Place();
@ -204,6 +228,14 @@ class Sanitizer {
$place->set_id( \sanitize_url( $data['id'] ) );
}
if ( isset( $data['latitude'] ) ) {
$place->set_latitude( self::validate_and_sanitize_float( $data['latitude'] ) );
}
if ( isset( $data['longitude'] ) ) {
$place->set_longitude( self::validate_and_sanitize_float( $data['longitude'] ) );
}
if ( isset( $data['url'] ) ) {
$place->set_url( \sanitize_url( $data['url'] ) );
}

View File

@ -10,7 +10,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier\Helper;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
/**
* Extending the Tribe Events API to allow setting of the guid.

View File

@ -10,7 +10,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier\Helper;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
/**
* Extending the Organizer Venue API to allow setting of the guid.

View File

@ -10,7 +10,7 @@
namespace Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier\Helper;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
/**
* Extending the Tribe Venue API to allow setting of the guid.
@ -29,6 +29,30 @@ class The_Events_Calendar_Venue_Repository extends \Tribe__Events__Repositories_
'comment_count',
);
/**
* Tribe__Events__Repositories__Venue constructor.
*
* Add aliases for longitude an latitude.
*
* @since 4.9
* @since 6.10.1 Added `show_map` and `show_map_link` aliases.
*/
public function __construct() {
parent::__construct();
// Add venue specific aliases.
$this->update_fields_aliases = array_merge(
$this->update_fields_aliases,
array(
'latitude' => '_VenueLat',
'longitude' => '_VenueLng',
)
);
$this->add_simple_meta_schema_entry( 'latitude', '_VenueLat' );
$this->add_simple_meta_schema_entry( 'longitude', '_VenueLng' );
}
/**
* Whether the current key can be updated by this repository or not.
*