diff --git a/includes/activitypub/transformer/class-event.php b/includes/activitypub/transformer/class-event.php
index a60f585..893778f 100644
--- a/includes/activitypub/transformer/class-event.php
+++ b/includes/activitypub/transformer/class-event.php
@@ -12,7 +12,9 @@ namespace Activitypub_Event_Extensions\Activitypub\Transformer;
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
use Activitypub\Activity\Extended_Object\Event as Event_Object;
+use Activitypub\Activity\Extended_Object\Place;
use Activitypub\Transformer\Post;
+use DateTime;
/**
* Base transformer for WordPress event post types to ActivityPub events.
@@ -20,7 +22,7 @@ use Activitypub\Transformer\Post;
* Everything that transforming several WordPress post types that represent events
* have in common, as well as sane defaults for events should be defined here.
*/
-class Event extends Post {
+abstract class Event extends Post {
/**
* The WordPress event taxonomy.
@@ -119,6 +121,161 @@ class Event extends Post {
}
}
+ /**
+ * Retrieves the excerpt text (may be HTML). Used for constructing the summary.
+ *
+ * @return ?string
+ */
+ protected function extract_excerpt(): ?string {
+ if ( $this->wp_object->excerpt ) {
+ return $this->wp_object->post_excerpt;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Get the start time.
+ *
+ * This is mandatory and must be implemented in the final event transformer class.
+ */
+ abstract protected function get_start_time(): string;
+
+ /**
+ * Get the end time.
+ *
+ * This is not mandatory and therefore just return null by default.
+ */
+ protected function get_end_time(): ?string {
+ return null;
+ }
+
+ /**
+ * Get a default for the location.
+ *
+ * This should be overridden in the actual event transformer.
+ */
+ protected function get_location(): ?Place {
+ return null;
+ }
+
+ /**
+ * Compose a human readable formatted start time.
+ *
+ * @param bool $is_start_time Whether format the events start or end time.
+ */
+ protected function format_time( $is_start_time = true ) {
+ $time = $is_start_time ? $this->get_start_time() : $this->get_end_time();
+ if ( is_null( $time ) ) {
+ return '';
+ }
+ $start_datetime = new DateTime( $time );
+ $start_timestamp = $start_datetime->getTimestamp();
+ $datetime_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
+ return wp_date( $datetime_format, $start_timestamp );
+ }
+
+ /**
+ * Format a human readable address.
+ */
+ protected function format_address(): string {
+ $location = $this->get_location();
+ if ( is_null( $location ) ) {
+ return '';
+ }
+ $address = $location->get_address();
+ if ( ! $address ) {
+ return $location->get_name();
+ }
+ if ( is_string( $address ) ) {
+ return $address;
+ }
+ if ( ! is_array( $address ) ) {
+ return '';
+ }
+ return isset( $address['locality'] ) ? $address['locality'] : '';
+ }
+
+ /**
+ * Format the category using the translation.
+ */
+ protected function format_category(): string {
+ require_once ACTIVITYPUB_EVENT_EXTENSIONS_PLUGIN_DIR . '/includes/event-categories.php';
+ $category = $this->get_category();
+ if ( array_key_exists( $category, ACTIVITYPUB_EVENT_EXTENSIONS_EVENT_CATEGORIES ) ) {
+ return ACTIVITYPUB_EVENT_EXTENSIONS_EVENT_CATEGORIES[ $category ];
+ } else {
+ return ACTIVITYPUB_EVENT_EXTENSIONS_EVENT_CATEGORIES['MEETING'];
+ }
+ }
+
+ /**
+ * Create a custom summary.
+ *
+ * It contains also the most important meta-information. The summary is often used when the
+ * ActivityPub object type 'Event' is not supported, e.g. in Mastodon.
+ *
+ * @return string $summary The custom event summary.
+ */
+ public function get_summary(): ?string {
+ add_filter( 'activitypub_object_content_template', array( self::class, 'remove_ap_permalink_from_template' ), 2 );
+ $excerpt = $this->extract_excerpt();
+ // BeforeFirstRelease: decide whether this should be a admin setting.
+ $fallback_to_content = true;
+ if ( is_null( $excerpt ) && $fallback_to_content ) {
+ $excerpt = $this->get_content();
+ }
+ remove_filter( 'activitypub_object_content_template', array( self::class, 'remove_ap_permalink_from_template' ) );
+
+ $category = $this->format_category();
+ $start_time = $this->format_time();
+ $end_time = $this->format_time( false );
+ $address = $this->format_address();
+
+ $formatted_items = array();
+ if ( ! empty( $category ) ) {
+ $formatted_items[] = "š·ļø $category";
+ }
+
+ if ( ! empty( $start_time ) ) {
+ $formatted_items[] = "šļø {$start_time}";
+ }
+
+ if ( ! empty( $end_time ) ) {
+ $formatted_items[] = "ā³ {$end_time}";
+ }
+
+ if ( ! empty( $address ) ) {
+ $formatted_items[] = "š {$address}";
+ }
+ // Compose the summary based on the number of meta items.
+ if ( count( $formatted_items ) > 1 ) {
+ $summary = '
- ' . implode( '
- ', $formatted_items ) . '
';
+ } elseif ( 1 === count( $formatted_items ) ) {
+ $summary = $formatted_items[0]; // Just the one item without - .
+ } else {
+ $summary = ''; // No items, so no output.
+ }
+
+ $summary .= $excerpt;
+ return $summary;
+ }
+
+ /**
+ * Remove the permalink shortcode from a WordPress template.
+ *
+ * This used for the summary template, because the summary usually gets,
+ * used when converting a object, where the URL is usually appended anyway.
+ *
+ * @param string $template The template string.
+ */
+ public static function remove_ap_permalink_from_template( $template ) {
+ $template = str_replace( '[ap_permalink]', '', $template );
+ $template = str_replace( '[ap_permalink type="html"]', '', $template );
+
+ return $template;
+ }
+
/**
* Generic function that converts an WP-Event object to an ActivityPub-Event object.
*
diff --git a/includes/activitypub/transformer/class-events-manager.php b/includes/activitypub/transformer/class-events-manager.php
index 0a3ce85..8d7bfd6 100644
--- a/includes/activitypub/transformer/class-events-manager.php
+++ b/includes/activitypub/transformer/class-events-manager.php
@@ -89,7 +89,7 @@ final class Events_Manager extends Event_Transformer {
*
* @return array The Place.
*/
- public function get_location() {
+ public function get_location(): ?Place {
if ( 'url' === $this->em_event->event_location_type ) {
return null;
}
@@ -125,14 +125,14 @@ final class Events_Manager extends Event_Transformer {
/**
* Get the end time from the events metadata.
*/
- public function get_end_time() {
+ public function get_end_time(): ?string {
return null;
}
/**
* Get the end time from the events metadata.
*/
- public function get_start_time() {
+ public function get_start_time(): string {
$date_string = $this->em_event->event_start_date;
$time_string = $this->em_event->event_start_time;
$timezone_string = $this->em_event->event_timezone;
@@ -181,7 +181,7 @@ final class Events_Manager extends Event_Transformer {
/**
* Hardcoded function for generating a summary.
*/
- public function get_summary() {
+ public function get_summary(): ?string {
if ( $this->em_event->post_excerpt ) {
$excerpt = $this->em_event->post_excerpt;
} else {
diff --git a/includes/activitypub/transformer/class-gatherpress.php b/includes/activitypub/transformer/class-gatherpress.php
index 7224a82..81f2f22 100644
--- a/includes/activitypub/transformer/class-gatherpress.php
+++ b/includes/activitypub/transformer/class-gatherpress.php
@@ -78,7 +78,7 @@ final class GatherPress extends Event {
*
* @return Place|null The place objector null if not place set.
*/
- public function get_location(): Place|null {
+ public function get_location(): ?Place {
$address = $this->gp_venue['full_address'];
if ( $address ) {
$place = new Place();
@@ -94,14 +94,14 @@ final class GatherPress extends Event {
/**
* Get the end time from the event object.
*/
- protected function get_end_time() {
+ protected function get_end_time(): ?string {
return $this->gp_event->get_datetime_end( 'Y-m-d\TH:i:s\Z' );
}
/**
* Get the end time from the event object.
*/
- protected function get_start_time() {
+ protected function get_start_time(): string {
return $this->gp_event->get_datetime_start( 'Y-m-d\TH:i:s\Z' );
}
diff --git a/includes/activitypub/transformer/class-the-events-calendar.php b/includes/activitypub/transformer/class-the-events-calendar.php
index 795b6b7..eea12ac 100644
--- a/includes/activitypub/transformer/class-the-events-calendar.php
+++ b/includes/activitypub/transformer/class-the-events-calendar.php
@@ -11,11 +11,10 @@ namespace Activitypub_Event_Extensions\Activitypub\Transformer;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
-use WP_Post;
-
use Activitypub\Activity\Extended_Object\Event as Event_Object;
use Activitypub\Activity\Extended_Object\Place;
use Activitypub_Event_Extensions\Activitypub\Transformer\Event;
+use WP_Post;
use function Activitypub\esc_hashtag;
@@ -74,7 +73,10 @@ final class The_Events_Calendar extends Event {
/**
* Get the end time from the event object.
*/
- protected function get_end_time(): string {
+ protected function get_end_time(): ?string {
+ if ( empty( $this->tribe_event->end_date ) ) {
+ return null;
+ }
$date = date_create( $this->tribe_event->end_date, wp_timezone() );
return \gmdate( 'Y-m-d\TH:i:s\Z', $date->getTimestamp() );
}
@@ -82,7 +84,7 @@ final class The_Events_Calendar extends Event {
/**
* Get the end time from the event object.
*/
- protected function get_start_time() {
+ protected function get_start_time(): string {
$date = date_create( $this->tribe_event->start_date, wp_timezone() );
return \gmdate( 'Y-m-d\TH:i:s\Z', $date->getTimestamp() );
}
diff --git a/includes/activitypub/transformer/class-vs-event-list.php b/includes/activitypub/transformer/class-vs-event-list.php
index c592003..aef6470 100644
--- a/includes/activitypub/transformer/class-vs-event-list.php
+++ b/includes/activitypub/transformer/class-vs-event-list.php
@@ -30,17 +30,6 @@ final class VS_Event_List extends Event_Transformer {
*/
protected $ap_object;
- /**
- * Returns the ActivityStreams 2.0 Object-Type for an Event.
- *
- * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-event
- * @since 1.0.0
- * @return string The Event Object-Type.
- */
- protected function get_type(): string {
- return 'Event';
- }
-
/**
* Get the event location.
*
@@ -67,6 +56,9 @@ final class VS_Event_List extends Event_Transformer {
return null;
}
$end_time = get_post_meta( $this->wp_object->ID, 'event-date', true );
+ if ( is_null( $end_time ) || empty( $end_time ) || 'no' === $end_time ) {
+ return null;
+ }
return $end_time ? \gmdate( 'Y-m-d\TH:i:s\Z', $end_time ) : null;
}
@@ -75,7 +67,7 @@ final class VS_Event_List extends Event_Transformer {
*/
protected function get_start_time(): string {
$start_time = get_post_meta( $this->wp_object->ID, 'event-start-date', true );
- return $start_time ? \gmdate( 'Y-m-d\TH:i:s\Z', $start_time ) : null;
+ return \gmdate( 'Y-m-d\TH:i:s\Z', $start_time );
}
/**
@@ -114,27 +106,17 @@ final class VS_Event_List extends Event_Transformer {
}
/**
- * Create a custom summary.
+ * Retrieves the excerpt text (may be HTML). Used for constructing the summary.
*
- * It contains also the most important meta-information. The summary is often used when the
- * ActivityPub object type 'Event' is not supported, e.g. in Mastodon.
- *
- * @return string $summary The custom event summary.
+ * @return ?string
*/
- public function get_summary(): ?string {
- if ( $this->wp_object->excerpt ) {
- $excerpt = $this->wp_object->post_excerpt;
- } elseif ( get_post_meta( $this->wp_object->ID, 'event-summary', true ) ) {
- $excerpt = get_post_meta( $this->wp_object->ID, 'event-summary', true );
+ protected function get_excerpt(): ?string {
+ if ( get_post_meta( $this->wp_object->ID, 'event-summary', true ) ) {
+ return get_post_meta( $this->wp_object->ID, 'event-summary', true );
+ } elseif ( $this->wp_object->excerpt ) {
+ return $this->wp_object->post_excerpt;
} else {
- $excerpt = $this->get_content();
+ return null;
}
-
- $address = get_post_meta( $this->wp_object->ID, 'event-location', true );
- $start_time = get_post_meta( $this->wp_object->ID, 'event-start-date', true );
- $datetime_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
- $start_time_string = wp_date( $datetime_format, $start_time );
- $summary = "š {$address}\nš
{$start_time_string}\n\n{$excerpt}";
- return $summary;
}
}
diff --git a/includes/event-categories.php b/includes/event-categories.php
new file mode 100644
index 0000000..a867167
--- /dev/null
+++ b/includes/event-categories.php
@@ -0,0 +1,47 @@
+ __( 'Arts', 'activitypub-event-extensions' ),
+ 'BOOK_CLUBS' => __( 'Book clubs', 'activitypub-event-extensions' ),
+ 'BUSINESS' => __( 'Business', 'activitypub-event-extensions' ),
+ 'CAUSES' => __( 'Causes', 'activitypub-event-extensions' ),
+ 'COMEDY' => __( 'Comedy', 'activitypub-event-extensions' ),
+ 'CRAFTS' => __( 'Crafts', 'activitypub-event-extensions' ),
+ 'FOOD_DRINK' => __( 'Food & Drink', 'activitypub-event-extensions' ),
+ 'HEALTH' => __( 'Health', 'activitypub-event-extensions' ),
+ 'MUSIC' => __( 'Music', 'activitypub-event-extensions' ),
+ 'AUTO_BOAT_AIR' => __( 'Auto, boat and air', 'activitypub-event-extensions' ),
+ 'COMMUNITY' => __( 'Community', 'activitypub-event-extensions' ),
+ 'FAMILY_EDUCATION' => __( 'Family & Education', 'activitypub-event-extensions' ),
+ 'FASHION_BEAUTY' => __( 'Fashion & Beauty', 'activitypub-event-extensions' ),
+ 'FILM_MEDIA' => __( 'Film & Media', 'activitypub-event-extensions' ),
+ 'GAMES' => __( 'Games', 'activitypub-event-extensions' ),
+ 'LANGUAGE_CULTURE' => __( 'Language & Culture', 'activitypub-event-extensions' ),
+ 'LEARNING' => __( 'Learning', 'activitypub-event-extensions' ),
+ 'LGBTQ' => __( 'LGBTQ', 'activitypub-event-extensions' ),
+ 'MOVEMENTS_POLITICS' => __( 'Movements and politics', 'activitypub-event-extensions' ),
+ 'NETWORKING' => __( 'Networking', 'activitypub-event-extensions' ),
+ 'PARTY' => __( 'Party', 'activitypub-event-extensions' ),
+ 'PERFORMING_VISUAL_ARTS' => __( 'Performing & Visual Arts', 'activitypub-event-extensions' ),
+ 'PETS' => __( 'Pets', 'activitypub-event-extensions' ),
+ 'PHOTOGRAPHY' => __( 'Photography', 'activitypub-event-extensions' ),
+ 'OUTDOORS_ADVENTURE' => __( 'Outdoors & Adventure', 'activitypub-event-extensions' ),
+ 'SPIRITUALITY_RELIGION_BELIEFS' => __( 'Spirituality, Religion & Beliefs', 'activitypub-event-extensions' ),
+ 'SCIENCE_TECH' => __( 'Science & Tech', 'activitypub-event-extensions' ),
+ 'SPORTS' => __( 'Sports', 'activitypub-event-extensions' ),
+ 'THEATRE' => __( 'Theatre', 'activitypub-event-extensions' ),
+ 'MEETING' => __( 'Meeting', 'activitypub-event-extensions' ), // Default value in federation.
+ 'DEFAULT' => __( 'Default', 'activitypub-event-extensions' ), // Internal default for overrides.
+ ),
+);