Compare commits
13 commits
plugin_doc
...
main
Author | SHA1 | Date | |
---|---|---|---|
2257e86f0f | |||
11bf3a2048 | |||
6f744b9e14 | |||
c599384006 | |||
f92c5853ad | |||
19457a9f19 | |||
7ab51b104e | |||
3dbd3e21ee | |||
20f0ea2823 | |||
c13230ac6f | |||
4d4328f3fd | |||
35bd198f47 | |||
ac99300949 |
15 changed files with 294 additions and 96 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
vendor
|
vendor/
|
||||||
composer.lock
|
composer.lock
|
||||||
.phpunit.result.cache
|
.phpunit.result.cache
|
||||||
|
node_modules/
|
||||||
|
|
|
@ -33,7 +33,7 @@ Once you create an event on your WordPress site, it is seamlessly shared across
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Your events can be automatically delivered to platforms that fully support events, such as [Mobilizon](https://joinmobilizon.org/), [Gancio](https://gancio.org), [Friendica](https://friendi.ca), [Hubzilla](https://hubzilla.org), and [Pleroma](https://pleroma.social/).
|
Your events can be automatically delivered to platforms that fully support events, such as [Mobilizon](https://joinmobilizon.org/), [Gancio](https://gancio.org), [Friendica](https://friendi.ca), [Hubzilla](https://hubzilla.org), and [Pleroma](https://pleroma.social/).
|
||||||
These platforms build public event calendars utilizing multiple event sources, including your site. Updates are also handled automatically whenever you make changes — no extra work for you than managing the event on your own website.
|
These platforms create public event calendars by pulling in events from various sources, including your website. Any updates you make to your events are synced across these platforms—so you only need to manage your events on your own site, with no extra work required.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./.wordpress-org/decentralized-event-calenders.gif" alt="Logo" width="250" />
|
<img src="./.wordpress-org/decentralized-event-calenders.gif" alt="Logo" width="250" />
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
*
|
*
|
||||||
* Requires at least ActivityPub plugin with version >= 3.2.2. ActivityPub plugin tested up to: 3.2.2.
|
* Requires at least ActivityPub plugin with version >= 3.2.2. ActivityPub plugin tested up to: 3.2.2.
|
||||||
*
|
*
|
||||||
* @package activitypub-event-extensions
|
* @package Activitypub_Event_Extensions
|
||||||
* @license AGPL-3.0-or-later
|
* @license AGPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,13 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
use Activitypub\Activity\Extended_Object\Event as Event_Object;
|
use Activitypub\Activity\Extended_Object\Event as Event_Object;
|
||||||
|
use Activitypub\Activity\Extended_Object\Place;
|
||||||
use Activitypub\Transformer\Post;
|
use Activitypub\Transformer\Post;
|
||||||
|
use DateTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base transformer for WordPress event post types to ActivityPub events.
|
* Base transformer for WordPress event post types to ActivityPub events.
|
||||||
|
@ -17,7 +22,7 @@ use Activitypub\Transformer\Post;
|
||||||
* Everything that transforming several WordPress post types that represent events
|
* Everything that transforming several WordPress post types that represent events
|
||||||
* have in common, as well as sane defaults for events should be defined here.
|
* 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.
|
* The WordPress event taxonomy.
|
||||||
|
@ -116,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 = '<ul><li>' . implode( '</li><li>', $formatted_items ) . '</li></ul>';
|
||||||
|
} elseif ( 1 === count( $formatted_items ) ) {
|
||||||
|
$summary = $formatted_items[0]; // Just the one item without <ul><li>.
|
||||||
|
} 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.
|
* Generic function that converts an WP-Event object to an ActivityPub-Event object.
|
||||||
*
|
*
|
||||||
|
|
|
@ -8,17 +8,17 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
|
use Activitypub\Activity\Extended_Object\Event;
|
||||||
|
use Activitypub\Activity\Extended_Object\Place;
|
||||||
use Activitypub_Event_Extensions\Activitypub\Transformer\Event as Event_Transformer;
|
use Activitypub_Event_Extensions\Activitypub\Transformer\Event as Event_Transformer;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use DateTimeZone;
|
use DateTimeZone;
|
||||||
use EM_Event;
|
use EM_Event;
|
||||||
use Activitypub\Activity\Extended_Object\Event;
|
|
||||||
use Activitypub\Activity\Extended_Object\Place;
|
|
||||||
use function Activitypub\esc_hashtag;
|
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
use function Activitypub\esc_hashtag;
|
||||||
exit; // Exit if accessed directly.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ActivityPub Transformer for events from the WordPress plugin 'Events Manager'
|
* ActivityPub Transformer for events from the WordPress plugin 'Events Manager'
|
||||||
|
@ -89,7 +89,7 @@ final class Events_Manager extends Event_Transformer {
|
||||||
*
|
*
|
||||||
* @return array The Place.
|
* @return array The Place.
|
||||||
*/
|
*/
|
||||||
public function get_location() {
|
public function get_location(): ?Place {
|
||||||
if ( 'url' === $this->em_event->event_location_type ) {
|
if ( 'url' === $this->em_event->event_location_type ) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -125,14 +125,14 @@ final class Events_Manager extends Event_Transformer {
|
||||||
/**
|
/**
|
||||||
* Get the end time from the events metadata.
|
* Get the end time from the events metadata.
|
||||||
*/
|
*/
|
||||||
public function get_end_time() {
|
public function get_end_time(): ?string {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the end time from the events metadata.
|
* 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;
|
$date_string = $this->em_event->event_start_date;
|
||||||
$time_string = $this->em_event->event_start_time;
|
$time_string = $this->em_event->event_start_time;
|
||||||
$timezone_string = $this->em_event->event_timezone;
|
$timezone_string = $this->em_event->event_timezone;
|
||||||
|
@ -181,7 +181,7 @@ final class Events_Manager extends Event_Transformer {
|
||||||
/**
|
/**
|
||||||
* Hardcoded function for generating a summary.
|
* Hardcoded function for generating a summary.
|
||||||
*/
|
*/
|
||||||
public function get_summary() {
|
public function get_summary(): ?string {
|
||||||
if ( $this->em_event->post_excerpt ) {
|
if ( $this->em_event->post_excerpt ) {
|
||||||
$excerpt = $this->em_event->post_excerpt;
|
$excerpt = $this->em_event->post_excerpt;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -8,18 +8,15 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
||||||
|
|
||||||
use Activitypub_Event_Extensions\Activitypub\Transformer\Event;
|
// Exit if accessed directly.
|
||||||
use Activitypub\Model\Blog;
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
use Activitypub\Activity\Extended_Object\Event as Event_Object;
|
use Activitypub\Activity\Extended_Object\Event as Event_Object;
|
||||||
use Activitypub\Activity\Extended_Object\Place;
|
use Activitypub\Activity\Extended_Object\Place;
|
||||||
|
use Activitypub\Model\Blog;
|
||||||
|
use Activitypub_Event_Extensions\Activitypub\Transformer\Event;
|
||||||
use GatherPress\Core\Event as GatherPress_Event;
|
use GatherPress\Core\Event as GatherPress_Event;
|
||||||
|
|
||||||
use function Activitypub\get_rest_url_by_path;
|
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
|
||||||
exit; // Exit if accessed directly.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ActivityPub Transformer for VS Event
|
* ActivityPub Transformer for VS Event
|
||||||
*
|
*
|
||||||
|
@ -81,7 +78,7 @@ final class GatherPress extends Event {
|
||||||
*
|
*
|
||||||
* @return Place|null The place objector null if not place set.
|
* @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'];
|
$address = $this->gp_venue['full_address'];
|
||||||
if ( $address ) {
|
if ( $address ) {
|
||||||
$place = new Place();
|
$place = new Place();
|
||||||
|
@ -97,14 +94,14 @@ final class GatherPress extends Event {
|
||||||
/**
|
/**
|
||||||
* Get the end time from the event object.
|
* 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' );
|
return $this->gp_event->get_datetime_end( 'Y-m-d\TH:i:s\Z' );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the end time from the event object.
|
* 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' );
|
return $this->gp_event->get_datetime_start( 'Y-m-d\TH:i:s\Z' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,16 +8,16 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
// Exit if accessed directly.
|
||||||
exit; // Exit if accessed directly.
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
}
|
|
||||||
|
|
||||||
use Activitypub_Event_Extensions\Activitypub\Transformer\Event;
|
|
||||||
use Activitypub\Activity\Extended_Object\Place;
|
|
||||||
use Activitypub\Activity\Extended_Object\Event as Event_Object;
|
use Activitypub\Activity\Extended_Object\Event as Event_Object;
|
||||||
use WP_Error;
|
use Activitypub\Activity\Extended_Object\Place;
|
||||||
|
use Activitypub_Event_Extensions\Activitypub\Transformer\Event;
|
||||||
use WP_Post;
|
use WP_Post;
|
||||||
|
|
||||||
|
use function Activitypub\esc_hashtag;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ActivityPub Tribe Transformer
|
* ActivityPub Tribe Transformer
|
||||||
*
|
*
|
||||||
|
@ -47,24 +47,36 @@ final class The_Events_Calendar extends Event {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get tribe category of wp_post
|
* Get the tags, including also the set categories from The Events Calendar.
|
||||||
*
|
*
|
||||||
* @return string|null tribe category if it exists
|
* @return ?array The array if tags,
|
||||||
*/
|
*/
|
||||||
public function get_tribe_category() {
|
public function get_tag(): ?array {
|
||||||
$categories = tribe_get_event_cat_slugs( $this->wp_object->ID );
|
$tags = array();
|
||||||
|
$category_ids = tribe_get_event_cat_ids();
|
||||||
if ( count( $categories ) === 0 ) {
|
if ( $category_ids ) {
|
||||||
return null;
|
foreach ( $category_ids as $category_id ) {
|
||||||
|
$term = \get_term( $category_id );
|
||||||
|
$tag = array(
|
||||||
|
'type' => 'Hashtag',
|
||||||
|
'href' => \esc_url( \get_term_link( $term ) ),
|
||||||
|
'name' => esc_hashtag( $term->name ),
|
||||||
|
);
|
||||||
|
$tags[] = $tag;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
$tags[] = parent::get_tag();
|
||||||
|
|
||||||
return $categories[0];
|
return $tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the end time from the event object.
|
* Get the end time from the event object.
|
||||||
*/
|
*/
|
||||||
protected function get_end_time() {
|
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() );
|
$date = date_create( $this->tribe_event->end_date, wp_timezone() );
|
||||||
return \gmdate( 'Y-m-d\TH:i:s\Z', $date->getTimestamp() );
|
return \gmdate( 'Y-m-d\TH:i:s\Z', $date->getTimestamp() );
|
||||||
}
|
}
|
||||||
|
@ -72,7 +84,7 @@ final class The_Events_Calendar extends Event {
|
||||||
/**
|
/**
|
||||||
* Get the end time from the event object.
|
* 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() );
|
$date = date_create( $this->tribe_event->start_date, wp_timezone() );
|
||||||
return \gmdate( 'Y-m-d\TH:i:s\Z', $date->getTimestamp() );
|
return \gmdate( 'Y-m-d\TH:i:s\Z', $date->getTimestamp() );
|
||||||
}
|
}
|
||||||
|
@ -83,19 +95,15 @@ final class The_Events_Calendar extends Event {
|
||||||
* @return string status of the event
|
* @return string status of the event
|
||||||
*/
|
*/
|
||||||
public function get_tribe_status() {
|
public function get_tribe_status() {
|
||||||
|
|
||||||
if ( 'canceled' === $this->tribe_event->event_status ) {
|
if ( 'canceled' === $this->tribe_event->event_status ) {
|
||||||
return 'CANCELLED';
|
return 'CANCELLED';
|
||||||
}
|
}
|
||||||
if ( 'postponed' === $this->tribe_event->event_status ) {
|
if ( 'postponed' === $this->tribe_event->event_status ) {
|
||||||
return 'CANCELLED'; // This will be reflected in the cancelled reason.
|
return 'CANCELLED'; // This will be reflected in the cancelled reason.
|
||||||
}
|
}
|
||||||
if ( '' === $this->tribe_event->event_status ) {
|
|
||||||
return 'CONFIRMED';
|
return 'CONFIRMED';
|
||||||
}
|
}
|
||||||
|
|
||||||
return new WP_Error( 'invalid event_status value', __( 'invalid event_status', 'activitypub' ), array( 'status' => 404 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the comments are enabled for the current event.
|
* Check if the comments are enabled for the current event.
|
||||||
|
@ -119,7 +127,6 @@ final class The_Events_Calendar extends Event {
|
||||||
* @return string The content.
|
* @return string The content.
|
||||||
*/
|
*/
|
||||||
protected function get_content() {
|
protected function get_content() {
|
||||||
|
|
||||||
$content = parent::get_content();
|
$content = parent::get_content();
|
||||||
// /BeforeFirstRelease:
|
// /BeforeFirstRelease:
|
||||||
// * remove link at the end of the content.
|
// * remove link at the end of the content.
|
||||||
|
@ -136,7 +143,7 @@ final class The_Events_Calendar extends Event {
|
||||||
*/
|
*/
|
||||||
public function get_location(): Place|null {
|
public function get_location(): Place|null {
|
||||||
// Get short handle for the venues.
|
// Get short handle for the venues.
|
||||||
$venues = $this->wp_object->venues;
|
$venues = $this->tribe_event->venues;
|
||||||
|
|
||||||
// Get first venue. We currently only support a single venue.
|
// Get first venue. We currently only support a single venue.
|
||||||
if ( $venues instanceof \Tribe\Events\Collections\Lazy_Post_Collection ) {
|
if ( $venues instanceof \Tribe\Events\Collections\Lazy_Post_Collection ) {
|
||||||
|
@ -181,6 +188,8 @@ final class The_Events_Calendar extends Event {
|
||||||
$location = new Place();
|
$location = new Place();
|
||||||
if ( count( $address ) > 1 ) {
|
if ( count( $address ) > 1 ) {
|
||||||
$location->set_address( $address );
|
$location->set_address( $address );
|
||||||
|
} else {
|
||||||
|
$location->set_address( $venue->post_title );
|
||||||
}
|
}
|
||||||
$location->set_id( $venue->permalink );
|
$location->set_id( $venue->permalink );
|
||||||
$location->set_name( $venue->post_title );
|
$location->set_name( $venue->post_title );
|
||||||
|
|
|
@ -8,16 +8,12 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
namespace Activitypub_Event_Extensions\Activitypub\Transformer;
|
||||||
|
|
||||||
use Activitypub_Event_Extensions\Activitypub\Transformer\Event as Event_Transformer;
|
// Exit if accessed directly.
|
||||||
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
use Activitypub\Activity\Extended_Object\Event;
|
use Activitypub\Activity\Extended_Object\Event;
|
||||||
use Activitypub\Activity\Extended_Object\Place;
|
use Activitypub\Activity\Extended_Object\Place;
|
||||||
|
use Activitypub_Event_Extensions\Activitypub\Transformer\Event as Event_Transformer;
|
||||||
use WP_Error;
|
|
||||||
use function Activitypub\get_rest_url_by_path;
|
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
|
||||||
exit; // Exit if accessed directly.
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ActivityPub Transformer for VS Event.
|
* ActivityPub Transformer for VS Event.
|
||||||
|
@ -34,17 +30,6 @@ final class VS_Event_List extends Event_Transformer {
|
||||||
*/
|
*/
|
||||||
protected $ap_object;
|
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.
|
* Get the event location.
|
||||||
*
|
*
|
||||||
|
@ -71,6 +56,9 @@ final class VS_Event_List extends Event_Transformer {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
$end_time = get_post_meta( $this->wp_object->ID, 'event-date', true );
|
$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;
|
return $end_time ? \gmdate( 'Y-m-d\TH:i:s\Z', $end_time ) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,7 +67,7 @@ final class VS_Event_List extends Event_Transformer {
|
||||||
*/
|
*/
|
||||||
protected function get_start_time(): string {
|
protected function get_start_time(): string {
|
||||||
$start_time = get_post_meta( $this->wp_object->ID, 'event-start-date', true );
|
$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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -118,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
|
* @return ?string
|
||||||
* ActivityPub object type 'Event' is not supported, e.g. in Mastodon.
|
|
||||||
*
|
|
||||||
* @return string $summary The custom event summary.
|
|
||||||
*/
|
*/
|
||||||
public function get_summary(): ?string {
|
protected function get_excerpt(): ?string {
|
||||||
if ( $this->wp_object->excerpt ) {
|
if ( get_post_meta( $this->wp_object->ID, 'event-summary', true ) ) {
|
||||||
$excerpt = $this->wp_object->post_excerpt;
|
return get_post_meta( $this->wp_object->ID, 'event-summary', true );
|
||||||
} elseif ( get_post_meta( $this->wp_object->ID, 'event-summary', true ) ) {
|
} elseif ( $this->wp_object->excerpt ) {
|
||||||
$excerpt = get_post_meta( $this->wp_object->ID, 'event-summary', true );
|
return $this->wp_object->post_excerpt;
|
||||||
} else {
|
} 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Admin;
|
namespace Activitypub_Event_Extensions\Admin;
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
use Activitypub_Event_Extensions\Plugins\Event_Plugin;
|
use Activitypub_Event_Extensions\Plugins\Event_Plugin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,6 +11,9 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Admin;
|
namespace Activitypub_Event_Extensions\Admin;
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class responsible for general admin notices.
|
* Class responsible for general admin notices.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,12 +11,12 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions\Admin;
|
namespace Activitypub_Event_Extensions\Admin;
|
||||||
|
|
||||||
use Activitypub_Event_Extensions\Setup;
|
|
||||||
use Activitypub_Event_Extensions\Plugins\Event_Plugin;
|
|
||||||
|
|
||||||
// Exit if accessed directly.
|
// Exit if accessed directly.
|
||||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
|
use Activitypub_Event_Extensions\Plugins\Event_Plugin;
|
||||||
|
use Activitypub_Event_Extensions\Setup;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class responsible for the ActivityPub Event Extension related Settings.
|
* Class responsible for the ActivityPub Event Extension related Settings.
|
||||||
*
|
*
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions;
|
namespace Activitypub_Event_Extensions;
|
||||||
|
|
||||||
use Activitypub\Activity\Extended_Object\Event;
|
|
||||||
|
|
||||||
// Exit if accessed directly.
|
// Exit if accessed directly.
|
||||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
|
use Activitypub\Activity\Extended_Object\Event;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class responsible for the ActivityPui Event Extension related Settings.
|
* Class responsible for the ActivityPui Event Extension related Settings.
|
||||||
*
|
*
|
||||||
|
|
|
@ -12,14 +12,14 @@
|
||||||
|
|
||||||
namespace Activitypub_Event_Extensions;
|
namespace Activitypub_Event_Extensions;
|
||||||
|
|
||||||
|
// Exit if accessed directly.
|
||||||
|
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||||
|
|
||||||
use Activitypub_Event_Extensions\Admin\Event_Plugin_Admin_Notices;
|
use Activitypub_Event_Extensions\Admin\Event_Plugin_Admin_Notices;
|
||||||
use Activitypub_Event_Extensions\Admin\General_Admin_Notices;
|
use Activitypub_Event_Extensions\Admin\General_Admin_Notices;
|
||||||
use Activitypub_Event_Extensions\Admin\Settings_Page;
|
use Activitypub_Event_Extensions\Admin\Settings_Page;
|
||||||
use Activitypub_Event_Extensions\Plugins\Event_Plugin;
|
use Activitypub_Event_Extensions\Plugins\Event_Plugin;
|
||||||
|
|
||||||
// Exit if accessed directly.
|
|
||||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
|
||||||
|
|
||||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
47
includes/event-categories.php
Normal file
47
includes/event-categories.php
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* File responsible for defining the event category strings.
|
||||||
|
*
|
||||||
|
* @package Activitypub_Event_Extensions
|
||||||
|
* @since 1.0.0
|
||||||
|
* @license AGPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Activitypub_Event_Extensions;
|
||||||
|
|
||||||
|
define(
|
||||||
|
'ACTIVITYPUB_EVENT_EXTENSIONS_EVENT_CATEGORIES',
|
||||||
|
array(
|
||||||
|
'ARTS' => __( '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.
|
||||||
|
),
|
||||||
|
);
|
|
@ -27,7 +27,7 @@ Once you create an event on your WordPress site, it is seamlessly shared across
|
||||||
![](./.wordpress-org/event-activitypub-publishing.gif)
|
![](./.wordpress-org/event-activitypub-publishing.gif)
|
||||||
|
|
||||||
Your events can be automatically delivered to platforms that fully support events, such as [Mobilizon](https://joinmobilizon.org/), [Gancio](https://gancio.org), [Friendica](https://friendi.ca), [Hubzilla](https://hubzilla.org), and [Pleroma](https://pleroma.social/).
|
Your events can be automatically delivered to platforms that fully support events, such as [Mobilizon](https://joinmobilizon.org/), [Gancio](https://gancio.org), [Friendica](https://friendi.ca), [Hubzilla](https://hubzilla.org), and [Pleroma](https://pleroma.social/).
|
||||||
These platforms build public event calendars utilizing multiple event sources, including your site. Updates are also handled automatically whenever you make changes — no extra work for you than managing the event on your own website.
|
These platforms create public event calendars by pulling in events from various sources, including your website. Any updates you make to your events are synced across these platforms—so you only need to manage your events on your own site, with no extra work required.
|
||||||
|
|
||||||
![](./.wordpress-org/decentralized-event-calenders.gif)
|
![](./.wordpress-org/decentralized-event-calenders.gif)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue