diff --git a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/assets.yml b/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/assets.yml deleted file mode 100644 index f32e729c..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/assets.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Plugin asset/readme update on WordPress.org - -on: workflow_dispatch - -jobs: - trunk: - name: Push assets to trunk on WordPress.org - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: https://code.forgejo.org/actions/checkout@v4 - - - name: Install and cache rsync - uses: https://github.com/awalsh128/cache-apt-pkgs-action@latest - with: - packages: rsync subversion - version: 1.0 - - - name: WordPress.org plugin asset/readme update - uses: https://github.com/10up/action-wordpress-plugin-asset-update@stable - env: - SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} - SVN_USERNAME: ${{ secrets.SVN_USERNAME }} - SLUG: event-bridge-for-activitypub diff --git a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/deploy.yml b/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/deploy.yml deleted file mode 100644 index 45fae27a..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/deploy.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Deploy to WordPress.org - -on: - push: - tags: '[0-9]+.[0-9]+.[0-9]+' - -jobs: - tag: - name: Deploy tagged release on WordPress.org - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: https://code.forgejo.org/actions/checkout@v4 - - - name: Install and cache rsync and subversion - uses: https://github.com/awalsh128/cache-apt-pkgs-action@latest - with: - packages: rsync subversion - version: 1.0 - - - name: WordPress Plugin Deploy - uses: https://github.com/10up/action-wordpress-plugin-deploy@stable - env: - SVN_PASSWORD: ${{ secrets.SVN_PASSWORD }} - SVN_USERNAME: ${{ secrets.SVN_USERNAME }} - SLUG: event-bridge-for-activitypub diff --git a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpcs.yml b/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpcs.yml deleted file mode 100644 index 21622e2e..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpcs.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: PHP Code Checker - -on: - push: - branches: - - main - pull_request: - -jobs: - phpcs: - name: PHP Code Checker - runs-on: ubuntu-latest - strategy: - matrix: - php-versions: ['8.1'] - steps: - - name: Checkout - uses: https://code.forgejo.org/actions/checkout@v4 - - - name: Cache Composer - id: cache-composer - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: | - ./vendor/ - key: cache-composer-3 - - - name: Setup cache environment for PHP Extensions - id: php-extensions-cache - uses: https://github.com/shivammathur/cache-extensions@v1 - with: - php-version: ${{ matrix.php-versions }} - extensions: dom, iconv, json, libxml, zip - key: php-extensions-cache-v1 - - - name: Cache PHP extensions - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: ${{ steps.php-extensions-cache.outputs.dir }} - key: ${{ steps.php-extensions-cache.outputs.key }} - restore-keys: ${{ steps.php-extensions-cache.outputs.key }} - - - name: Setup PHP - uses: https://github.com/shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-versions }} - extensions: dom, iconv, json, libxml, zip - coverage: none - tools: composer, cs2pr - env: - runner: self-hosted - GITHUB_TOKEN: ${{ env.COMPOSER_TOKEN }} - - - name: Install Composer dependencies for PHP - if: steps.cache-composer.outputs.cache-hit != 'true' - uses: ramsey/composer-install@v3 - env: - COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.COMPOSER_TOKEN }}"}}' - - - name: Run PHP_CodeSniffer - run: ./vendor/bin/phpcs diff --git a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpstan.yml b/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpstan.yml deleted file mode 100644 index ce87dacc..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpstan.yml +++ /dev/null @@ -1,87 +0,0 @@ -name: PHPStan Tests - -on: - push: - branches: - - main - pull_request: - -env: - WP_TESTS_DIR: /workspace/wordpress-test-lib - WP_CORE_DIR: /workspace/wordpress - -jobs: - phpstan: - runs-on: ubuntu-latest - strategy: - matrix: - php-version: ['7.4','8.1','8.4'] - name: PHPStan for WordPress ${{ matrix.php-version }} - steps: - - name: Checkout - uses: https://code.forgejo.org/actions/checkout@v4 - - - name: Cache WordPress Setup and installed plugins (Event plugins and ActivityPub plugin). - id: cache-wordpress - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: | - ${{ env.WP_CORE_DIR }} - ${{ env.WP_TESTS_DIR }} - key: cache-phpstan-wordpress-6.7-activitypub-5.1.0-2 - - - name: Cache Composer - id: cache-composer - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: | - ./vendor/ - key: cache-composer-3 - - - name: Setup cache environment for PHP Extensions - id: php-extensions-cache - uses: https://github.com/shivammathur/cache-extensions@v1 - with: - php-version: ${{ matrix.php-version }} - extensions: dom, iconv, json, libxml, zip - key: php-extensions-cache-v1 - - - name: Cache PHP extensions - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: ${{ steps.php-extensions-cache.outputs.dir }} - key: ${{ steps.php-extensions-cache.outputs.key }} - restore-keys: ${{ steps.php-extensions-cache.outputs.key }} - - - name: Setup PHP - uses: https://github.com/shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - extensions: dom, iconv, json, libxml, zip - coverage: none - tools: composer, cs2pr - env: - runner: self-hosted - GITHUB_TOKEN: ${{ env.COMPOSER_TOKEN }} - - - name: Install Composer dependencies for PHP - if: steps.cache-composer.outputs.cache-hit != 'true' - uses: ramsey/composer-install@v3 - env: - COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.COMPOSER_TOKEN }}"}}' - - - name: Log debug information - run: | - git --version - php --version - composer --version - - - name: Install third party plugins, so that PHP Stan finds that functions - if: steps.cache-wordpress.outputs.cache-hit != 'true' - run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 latest true false false true - - - name: Running PHPStan Analyze - if: ${{ success() || failure() }} - run: | - ./vendor/bin/phpstan --version - ./vendor/bin/phpstan analyze -vv --memory-limit=2G --error-format=checkstyle | cs2pr diff --git a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpunit.yml b/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpunit.yml deleted file mode 100644 index 9c07a0db..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/phpunit.yml +++ /dev/null @@ -1,147 +0,0 @@ -name: PHPUnit - -on: - push: - branches: - - main - pull_request: - -env: - WP_TESTS_DIR: /workspace/wordpress-test-lib - WP_CORE_DIR: /workspace/wordpress - -jobs: - phpunit: - runs-on: ubuntu-latest - services: - mysql: - image: mariadb - env: - MYSQL_ROOT_PASSWORD: root - strategy: - matrix: - php-version: ['7.4', '8.1', '8.3', '8.4'] - wordpress-version: ['6.7', '6.8-RC3'] - name: "PHPUnit: PHP ${{ matrix.php-version }} - WordPress ${{ matrix.wordpress-version }}" - continue-on-error: true - steps: - - name: Checkout - uses: https://code.forgejo.org/actions/checkout@v4 - - - name: Cache WordPress Setup and installed plugins (Event plugins and ActivityPub plugin). - id: cache-wordpress - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: | - ${{ env.WP_CORE_DIR }} - ${{ env.WP_TESTS_DIR }} - key: cache-phpunit-wordpress-${{ matrix.wordpress-version }}-activitypub-5.7.0 - - - name: Cache Composer - id: cache-composer - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: | - ./vendor/ - key: cache-composer-3 - - - name: Setup cache environment for PHP Extensions - id: php-extensions-cache - uses: https://github.com/shivammathur/cache-extensions@v1 - with: - php-version: ${{ matrix.php-version }} - extensions: dom, iconv, json, libxml, zip - key: php-extensions-cache-v1 - - - name: Cache PHP extensions - uses: https://code.forgejo.org/actions/cache@v4 - with: - path: ${{ steps.php-extensions-cache.outputs.dir }} - key: ${{ steps.php-extensions-cache.outputs.key }} - restore-keys: ${{ steps.php-extensions-cache.outputs.key }} - - - name: Setup PHP - uses: https://github.com/shivammathur/setup-php@v2 - with: - php-version: ${{ matrix.php-version }} - extensions: dom, iconv, json, libxml, zip - coverage: none - tools: composer, cs2pr - env: - runner: self-hosted - GITHUB_TOKEN: ${{ secrets.COMPOSER_TOKEN }} - - - name: Install Composer dependencies for PHP - if: steps.cache-composer.outputs.cache-hit != 'true' - uses: ramsey/composer-install@v3 - env: - COMPOSER_AUTH: '{"github-oauth": {"github.com": "${{ secrets.COMPOSER_TOKEN }}"}}' - - - name: Install and cache mysqladmin needed to initialize the test database - uses: https://github.com/awalsh128/cache-apt-pkgs-action@latest - with: - packages: mysql-client - version: 1.0 - - - name: Setup Test Environment - if: steps.cache-wordpress.outputs.cache-hit != 'true' - run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wordpress-version }} false false false false - - - name: Initialize WordPress test database - if: steps.cache-wordpress.outputs.cache-hit != 'false' - run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1 ${{ matrix.wordpress-version }} false true true true - - - name: Run General Tests - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for The Events Calendar - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=the_events_calendar - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for VS Event List - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=vs_event_list - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for GatherPress - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=gatherpress - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for Events Manager - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=events_manager - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for WP Event Manager - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=wp_event_manager - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for Eventin (WP Event Solution) - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=eventin - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for Modern Events Calendar Lite - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=modern_events_calendar_lite - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for EventPrime - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=eventprime - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for Event Organiser - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=event_organiser - env: - PHP_VERSION: ${{ matrix.php-version }} - - - name: Run Integration tests for EventON – Events Calendar - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=eventon - env: - PHP_VERSION: ${{ matrix.php-version }} diff --git a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/release.yml b/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/release.yml deleted file mode 100644 index 78d84211..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/.forgejo/workflows/release.yml +++ /dev/null @@ -1,17 +0,0 @@ -on: - push: - tags: - - '^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?$' - -jobs: - upload-release: - runs-on: ubuntu-latest - steps: - - uses: https://code.forgejo.org/actions/checkout@v4 - - - uses: https://code.forgejo.org/actions/forgejo-release@v2 - with: - direction: upload - url: https://codeberg.org - release-notes: ${{ TAG }} - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/wp-content/plugins/event-bridge-for-activitypub/.gitattributes b/wp-content/plugins/event-bridge-for-activitypub/.gitattributes deleted file mode 100644 index f5aa0a25..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/.gitattributes +++ /dev/null @@ -1,26 +0,0 @@ -.distignore export-ignore -.forgejo export-ignore -.gitattributes export-ignore -.gitignore export-ignore -.wordpress-org export-ignore -.wp-env.json export-ignore -bin export-ignore -CODE_OF_CONDUCT.md export-ignore -composer.json export-ignore -composer.lock export-ignore -docker-compose.yml export-ignore -Dockerfile export-ignore -docs export-ignore -FEDERATION.md export-ignore -Gruntfile.js export-ignore -node_modules export-ignore -package.json export-ignore -package-lock.json export-ignore -phpcs.xml export-ignore -phpstan.neon export-ignore -phpstan.neon.dist export-ignore -phpunit.xml export-ignore -README.md export-ignore -src export-ignore -tests export-ignore -vendor export-ignore diff --git a/wp-content/plugins/event-bridge-for-activitypub/.wp-env.test.json b/wp-content/plugins/event-bridge-for-activitypub/.wp-env.test.json new file mode 100644 index 00000000..08f56d64 --- /dev/null +++ b/wp-content/plugins/event-bridge-for-activitypub/.wp-env.test.json @@ -0,0 +1,27 @@ +{ + "core": null, + "plugins": [ + "https://downloads.wordpress.org/plugin/activitypub.8.3.0.zip", + "https://downloads.wordpress.org/plugin/the-events-calendar.6.16.2.zip", + "https://downloads.wordpress.org/plugin/very-simple-event-list.20.0.zip", + "https://downloads.wordpress.org/plugin/gatherpress.0.33.3.zip", + "https://downloads.wordpress.org/plugin/eventprime-event-calendar-management.4.3.4.0.zip", + "https://downloads.wordpress.org/plugin/events-manager.7.2.3.1.zip", + "https://downloads.wordpress.org/plugin/wp-event-solution.4.1.13.zip", + "https://downloads.wordpress.org/plugin/event-organiser.3.12.8.zip", + "https://downloads.wordpress.org/plugin/eventon-lite.2.5.4.zip", + "https://codeberg.org/Event-Federation/modern-events-calendar-lite/releases/download/v7.27.0/modern-events-calendar-lite.zip", + "https://downloads.wordpress.org/plugin/spiffy-calendar.5.0.11.zip", + "wpeventmanager/wp-event-manager#3.3.5", + "https://downloads.wordpress.org/plugin/plugin-check.1.9.0.zip", + "." + ], + "testsEnvironment": true, + "config": { + "WP_DEBUG": true, + "WP_DEBUG_LOG": true + }, + "lifecycleScripts": { + "afterStart": "wp-env run cli wp plugin deactivate --all --exclude=activitypub,event-bridge-for-activitypub" + } +} diff --git a/wp-content/plugins/event-bridge-for-activitypub/CHANGELOG.md b/wp-content/plugins/event-bridge-for-activitypub/CHANGELOG.md index d87b1e66..c97f4858 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/CHANGELOG.md +++ b/wp-content/plugins/event-bridge-for-activitypub/CHANGELOG.md @@ -5,6 +5,94 @@ 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). +## [1.3.0] - 2026-05-24 + +### Added + +* Basic support for Spiffy Calendar Plugin +* Support for WordPress 7 + +### Changed + +* Requires ActivityPub plugin 8.+ + +### Fixed + +* The events calendar integration: remote cached organizers not being public. + +## [1.2.4] - 2026-05-17 + +### Added + +* Flag plugin compatible with WordPress 6.9 + +## [1.2.3] - 2026-05-17 + +### Added + +* ActivityPub `Place` transformer for GatherPress + +### Fixed + +* Improve timezone detection for Eventin +* GatherPress place name not uses venue name + +### Changed + +* Time formatting for EventPrime +* Time formatting for VS Event List +* Test up to ActivityPub plugin 8.2.1 + +## [1.2.2] - 2025-11-21 + +### Fixed + +* Validate event-tag info Events Manager to prevent fatal error +* timezone issues for Modern Events Calendar Lite + +## [1.2.1] - 2025-11-13 + +### Fixed + +* Incoming remote events getting federated + +### Added + +* Hotfix for Mobilizon group behavior to detect correct event source + +## [1.2.0] - 2025-11-12 + +### Added + +* New filter hook for incoming events +* Store longitude and latitude information for incoming The Events Calendar events + +### Changed + +* Update to new method how actor JSON is stored +* Dependency: now requires PHP 8.1+ +* Dependency: now requires the WordPress ActivityPub plugin 7.5+ + +### Fixed + +* Time offset for outgoing GatherPress events +* Time offset for importing events with The Events Calendar + +## [1.1.1] - 2025-06-17 + +### Added + +* Compatibility with ActivityPub plugin 6.0+ + +### Changed + +* Improved scheduling of sending event posts + +### Fixed + +* Datetime timezone offset for incoming events when using The Events Calendar +* Accessibility issues in Admin UI + ## [1.1.0] - 2025-04-12 ### Added diff --git a/wp-content/plugins/event-bridge-for-activitypub/event-bridge-for-activitypub.php b/wp-content/plugins/event-bridge-for-activitypub/event-bridge-for-activitypub.php index 179cbd7e..678909a5 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/event-bridge-for-activitypub.php +++ b/wp-content/plugins/event-bridge-for-activitypub/event-bridge-for-activitypub.php @@ -3,16 +3,16 @@ * Plugin Name: Event Bridge for ActivityPub * Description: Integrating popular event plugins with the ActivityPub plugin. The development of this plugin was funded through the NGI0 Entrust Fund, a fund established by NLnet. * Plugin URI: https://event-federation.eu/ - * Version: 1.1.0 + * Version: 1.3.0 * Author: André Menrath * Author URI: https://graz.social/@linos * Text Domain: event-bridge-for-activitypub * License: AGPL-3.0-or-later * License URI: https://www.gnu.org/licenses/agpl-3.0.html - * Requires PHP: 7.4 + * Requires PHP: 8.1 * Requires Plugins: activitypub * - * Requires at least ActivityPub plugin with version >= 5.6.1. ActivityPub plugin tested up to: 5.7.0. + * Requires at least ActivityPub plugin with version >= 7.5.0. ActivityPub plugin tested up to: 8.3.0. * * @package Event_Bridge_For_ActivityPub * @license AGPL-3.0-or-later @@ -27,7 +27,7 @@ define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION', current( get_file_data( __FILE__, array( 'Version' ), 'plugin' ) ) ); define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_DOMAIN', 'event-bridge-for-activitypub' ); -define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION', '5.6.1' ); +define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION', '8.1.0' ); define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_SUMMARY_TEMPLATE', "[ap_start_time]\n[ap_end_time]\n[ap_location]\n\n[ap_content]" ); define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_DEFAULT_SUMMARY_TYPE', 'preset' ); diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/class-handler.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/class-handler.php index 3081c01d..a165686c 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/class-handler.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/class-handler.php @@ -10,7 +10,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Handler\Accept; use Event_Bridge_For_ActivityPub\ActivityPub\Handler\Update; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/collection/class-event-sources.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/collection/class-event-sources.php index 9edd3634..c71d6ebd 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/collection/class-event-sources.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/collection/class-event-sources.php @@ -21,14 +21,15 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Collection; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Model\Blog; +use Activitypub\Tombstone; use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source; use WP_Error; +use WP_Post; use WP_Query; -use function Activitypub\is_tombstone; use function Activitypub\get_remote_metadata_by_actor; /** @@ -49,7 +50,7 @@ class Event_Sources { /** * The custom post type. */ - const POST_TYPE = 'ap_event_source'; + public const POST_TYPE = 'ap_event_source'; /** * Init. @@ -173,10 +174,10 @@ class Event_Sources { * * @return Event_Source|WP_Error|null The Followed (WP_Post array) or an WP_Error. */ - public static function add_event_source( $actor ) { + public static function add_event_source( string $actor ) { $meta = get_remote_metadata_by_actor( $actor ); - if ( is_tombstone( $meta ) ) { + if ( Tombstone::exists_in_error( $meta ) ) { return $meta; } @@ -211,7 +212,7 @@ class Event_Sources { * @param string $followed_id The ActivityPub ID of the followed actor. * @return string The `Follow` ID. */ - public static function compose_follow_id( $follower_id, $followed_id ) { + public static function compose_follow_id( string $follower_id, string $followed_id ) { return $follower_id . '#follow-' . \preg_replace( '~^https?://~', '', $followed_id ); } @@ -231,14 +232,14 @@ class Event_Sources { * @param string|int $attachment_id The numeric post ID of the attachment. * @return bool */ - public static function is_attachment_featured_image( $attachment_id ): bool { + public static function is_attachment_featured_image( string|int $attachment_id ): bool { if ( ! is_numeric( $attachment_id ) ) { return false; } - // Query posts with the given attachment ID as their featured image. $args = array( 'post_type' => 'any', + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( array( 'key' => '_thumbnail_id', @@ -261,8 +262,10 @@ class Event_Sources { * @param int $event_source_post_id The WordPress Post ID of the event source. * @return void */ - public static function delete_events_by_event_source( $event_source_post_id ): void { + public static function delete_events_by_event_source( int $event_source_post_id ): void { global $wpdb; + + // phpcs:disable WordPress.DB.DirectDatabaseQuery $results = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s", @@ -305,7 +308,7 @@ class Event_Sources { * * @return void Post data on success, false or null on failure. */ - public static function remove_event_source( $event_source_post_id ): void { + public static function remove_event_source( int|string $event_source_post_id ): void { $event_source = Event_Source::get_by_id( $event_source_post_id ); if ( ! $event_source ) { @@ -320,7 +323,7 @@ class Event_Sources { $post = \get_post( $event_source->get__id() ); $post->post_status = 'draft'; - if ( $post instanceof \WP_Post ) { + if ( $post instanceof WP_Post ) { $post = \get_object_vars( $post ); $post = \wp_slash( $post ); $post = \wp_update_post( $post ); @@ -358,9 +361,9 @@ class Event_Sources { /** * Get the Event Sources along with a total count for pagination purposes. * - * @param int $number Maximum number of results to return. - * @param int $page Page number. - * @param array $args The WP_Query arguments. + * @param int $number Maximum number of results to return. + * @param int|null $page Page number. + * @param array $args The WP_Query arguments. * * @return array { * Data about the event sources. @@ -369,7 +372,7 @@ class Event_Sources { * @type int $total Total number of followers. * } */ - public static function get_event_sources_with_count( $number = -1, $page = null, $args = array() ): array { + public static function get_event_sources_with_count( int $number = -1, int|null $page = null, array $args = array() ): array { $defaults = array( 'post_type' => self::POST_TYPE, 'posts_per_page' => $number, @@ -396,12 +399,12 @@ class Event_Sources { /** * Queue a hook to run async. * - * @param string $hook The hook name. - * @param array $args The arguments to pass to the hook. - * @param string $unqueue_hook Optional a hook to unschedule before queuing. - * @return void|bool|WP_Error Whether the hook was queued. + * @param string $hook The hook name. + * @param array $args The arguments to pass to the hook. + * @param string $unqueue_hook Optional a hook to unschedule before queuing. + * @return bool|WP_Error Whether the hook was queued. */ - public static function queue( $hook, $args, $unqueue_hook = null ) { + public static function queue( string $hook, array $args, $unqueue_hook = null ): bool|WP_Error { if ( $unqueue_hook ) { $hook_timestamp = \wp_next_scheduled( $unqueue_hook, $args ); if ( $hook_timestamp ) { @@ -410,7 +413,7 @@ class Event_Sources { } if ( \wp_next_scheduled( $hook, $args ) ) { - return; + return false; } return \wp_schedule_single_event( \time(), $hook, $args ); @@ -419,11 +422,11 @@ class Event_Sources { /** * Prepare to follow an ActivityPub actor via a scheduled event. * - * @param string $actor The ActivityPub actor. + * @param string $actor The ActivityPub actor. * - * @return bool Whether the event was queued. + * @return bool Whether the event was queued. */ - public static function queue_follow_actor( $actor ): bool { + public static function queue_follow_actor( string $actor ): bool { $queued = self::queue( 'event_bridge_for_activitypub_follow', array( $actor ), @@ -435,7 +438,7 @@ class Event_Sources { } // Following this actor has already been queued. - if ( null === $queued ) { + if ( false === $queued ) { return true; } @@ -447,11 +450,11 @@ class Event_Sources { * * @param string $actor_id The ID/URL of the Actor. */ - public static function activitypub_follow_actor( $actor_id ) { + public static function activitypub_follow_actor( string $actor_id ): void { $actor = Event_Source::get_by_id( $actor_id ); if ( ! $actor ) { - return $actor; + return; } $inbox = $actor->get_shared_inbox(); @@ -461,8 +464,7 @@ class Event_Sources { $activity = new \Activitypub\Activity\Activity(); $activity->set_type( 'Follow' ); - $activity->set_to( null ); - $activity->set_cc( null ); + $activity->set_to( array( $to ) ); $activity->set_actor( $from_actor->get_id() ); $activity->set_object( $to ); $activity->set_id( self::compose_follow_id( $from_actor->get_id(), $to ) ); @@ -475,9 +477,9 @@ class Event_Sources { * * @param string $actor The ActivityPub actor ID. * - * @return bool|void|WP_Error Whether the event was queued. + * @return bool|WP_Error Whether the event was queued. */ - public static function queue_unfollow_actor( $actor ) { + public static function queue_unfollow_actor( string $actor ): bool|WP_Error { $queued = self::queue( 'event_bridge_for_activitypub_unfollow', array( $actor ), @@ -489,7 +491,7 @@ class Event_Sources { } // Following this actor has already been queued. - if ( null === $queued ) { + if ( false === $queued ) { return true; } @@ -502,7 +504,7 @@ class Event_Sources { * @param string $actor The ActivityPub ID of the actor to unfollow. * @return void */ - public static function activitypub_unfollow_actor( $actor ): void { + public static function activitypub_unfollow_actor( string $actor ): void { $actor = Event_Source::get_by_id( $actor ); if ( ! $actor ) { @@ -520,8 +522,7 @@ class Event_Sources { $activity = new \Activitypub\Activity\Activity(); $activity->set_type( 'Undo' ); - $activity->set_to( null ); - $activity->set_cc( null ); + $activity->set_to( array( $to ) ); $activity->set_actor( $from_actor->get_id() ); $activity->set_object( array( diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-accept.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-accept.php index ab7b63f1..4b03d1f8 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-accept.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-accept.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Collection\Actors; use Activitypub\Model\Blog; @@ -37,10 +37,10 @@ class Accept { /** * Handle incoming "Accept" activities. * - * @param array $activity The activity-object. - * @param int $user_id The id of the local blog-user. + * @param array $activity The activity-object. + * @param int|int[] $user_id The id of the local blog-user. */ - public static function handle_accept( $activity, $user_id ): void { + public static function handle_accept( array $activity, int|array $user_id ): void { // We only process activities that are target to the blog actor. if ( Actors::BLOG_USER_ID !== $user_id ) { return; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-create.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-create.php index 74ff5438..a343796b 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-create.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-create.php @@ -8,7 +8,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Collection\Actors; use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source; @@ -36,10 +36,10 @@ class Create { /** * Handle incoming "Create" activities. * - * @param array $activity The activity-object. - * @param int $user_id The id of the local blog-user. + * @param array $activity The activity-object. + * @param int|int[] $user_id The id of the local blog-user. */ - public static function handle_create( $activity, $user_id ): void { + public static function handle_create( array $activity, int|array $user_id ): void { // We only process activities that are target to the blog actor. if ( Actors::BLOG_USER_ID !== $user_id ) { return; @@ -56,7 +56,7 @@ class Create { } // Check that we are actually following/or have a pending follow request this actor. - $event_source_post_id = Event_Source::get_post_id_by_activitypub_id( $activity['actor'] ); + $event_source_post_id = self::determine_event_source( $activity ); if ( ! $event_source_post_id ) { return; } @@ -65,6 +65,11 @@ class Create { return; } + // Apply custom filters whether an Event should be ignored. + if ( \apply_filters( 'event_bridge_for_activitypub_ignore_incoming_event', false, $activity['object'], $event_source_post_id ) ) { + return; + } + $transmogrifier = Setup::get_transmogrifier(); if ( ! $transmogrifier ) { @@ -73,4 +78,36 @@ class Create { $transmogrifier::save( $activity['object'], $event_source_post_id ); } + + /** + * Lookup the post ID of the event source for a given ActivityPub activity. + * + * First tries the actor of the activity. For Mobilizon-like groups, falls back + * to the attributedTo field if it has the same host as the actor. + * + * @param array $activity The ActivityPub activity as associative array. + * @return int|false Post ID of the event source, or false if none found. + */ + public static function determine_event_source( $activity ): int|false { + $event_source_post_id = Event_Source::get_post_id_by_activitypub_id( $activity['actor'] ); + + if ( $event_source_post_id ) { + return $event_source_post_id; + } + + // Fallback for Mobilizon groups, where a member of the group sends them. + if ( ! isset( $activity['object']['attributedTo'] ) ) { + return false; + } + + // We only trust this, when the attributedTo of the event object and the actor of the activity have the same hostname. + $actor_host = \wp_parse_url( $activity['actor'], PHP_URL_HOST ); + $attributed_to_host = \wp_parse_url( $activity['object']['attributedTo'], PHP_URL_HOST ); + + if ( $actor_host === $attributed_to_host ) { + return Event_Source::get_post_id_by_activitypub_id( $activity['object']['attributedTo'] ); + } + + return false; + } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-delete.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-delete.php index 1fcf526a..5d08af7e 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-delete.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-delete.php @@ -8,7 +8,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Collection\Actors; use Event_Bridge_For_ActivityPub\Event_Sources; @@ -35,10 +35,10 @@ class Delete { /** * Handle "Follow" requests. * - * @param array $activity The activity-object. - * @param int $user_id The id of the local blog-user. + * @param array $activity The activity-object. + * @param int|int[] $user_id The id of the local blog-user. */ - public static function handle_delete( $activity, $user_id ): void { + public static function handle_delete( array $activity, int|array $user_id ): void { // We only process activities that are target to the application user. if ( Actors::BLOG_USER_ID !== $user_id ) { return; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-join.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-join.php deleted file mode 100644 index d4023d38..00000000 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-join.php +++ /dev/null @@ -1,159 +0,0 @@ -get_actor_object()->get_id(), // Gets the WordPress user that "owns" the object by ActivityPub means. - $activity['id'], - Actor::init_from_array( $actor ) - ); - } - - /** - * Send "Ignore" response. - * - * @param string $actor The actors ActivityPub ID which sends the response. - * @param string $ignored The ID of the Activity that gets ignored. - * @param Actor|mixed $to The target actor. - */ - public static function send_ignore_response( $actor, $ignored, $to ) { - // Get actor object that owns the object that was targeted by the ignored activity. - $actor = Actors::get_by_resource( $actor ); - - if ( \is_wp_error( $to ) || \is_wp_error( $actor ) ) { - return; - } - - // Get inbox. - $inbox = $to->get_inbox(); - - if ( ! $inbox ) { - return; - } - - // Send "Ignore" activity. - $activity = new Activity(); - $activity->set_type( 'Ignore' ); - $activity->set_object( \esc_url_raw( $ignored ) ); - $activity->set_actor( $actor->get_id() ); - $activity->set_to( $to->get_id() ); - $activity->set_id( $actor->get_id() . '#ignore-' . \preg_replace( '~^https?://~', '', $ignored ) ); - $activity->set_sensitive( null ); - - // @phpstan-ignore-next-line - Http::post( $inbox, $activity->to_json(), $actor->get__id() ); - } - - /** - * Get the WordPress Post ID by the ActivityPub ID. - * - * @param string $activitypub_id The ActivityPub objects ID. - * @return int The WordPress post ID. - */ - private static function get_post_id_by_activitypub_id( $activitypub_id ) { - // Parse the URL and extract its components. - $parsed_url = wp_parse_url( $activitypub_id ); - $home_url = \trailingslashit( \home_url() ); - - // Ensure the base URL matches the home URL. - if ( \trailingslashit( "{$parsed_url['scheme']}://{$parsed_url['host']}" ) !== $home_url ) { - return 0; - } - - // Check for a valid query string and parse it. - if ( isset( $parsed_url['query'] ) ) { - parse_str( $parsed_url['query'], $query_vars ); - - // Ensure the only parameter is 'p'. - if ( count( $query_vars ) === 1 && isset( $query_vars['p'] ) ) { - return intval( $query_vars['p'] ); // Return the post ID. - } - } - - // Fallback: legacy ActivityPub plugin (before version 3.0.0) used pretty permalinks as `id`. - return \url_to_postid( $activitypub_id ); - } -} diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-undo.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-undo.php index c2ad5aaa..5859492a 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-undo.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-undo.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Collection\Actors; use Event_Bridge_For_ActivityPub\Event_Sources; @@ -35,10 +35,10 @@ class Undo { /** * Handle incoming "Undo" activities. * - * @param array $activity The activity-object. - * @param int $user_id The id of the local blog-user. + * @param array $activity The activity-object. + * @param int|int[] $user_id The id of the local blog-user. */ - public static function handle_undo( $activity, $user_id ): void { + public static function handle_undo( array $activity, int|array $user_id ): void { // We only process activities that are target to the blog actor. if ( Actors::BLOG_USER_ID !== $user_id ) { return; @@ -53,6 +53,7 @@ class Undo { global $wpdb; + // phpcs:disable WordPress.DB.DirectDatabaseQuery $results = $wpdb->get_results( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %s", diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-update.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-update.php index 1281a95c..03a572ed 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-update.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/handler/class-update.php @@ -8,14 +8,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore - -use Activitypub\Collection\Actors; -use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source; -use Event_Bridge_For_ActivityPub\Event_Sources; -use Event_Bridge_For_ActivityPub\Setup; - -use function Activitypub\is_activity_public; +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Handle Update requests. @@ -36,41 +29,11 @@ class Update { /** * Handle incoming "Update" activities.. * - * @param array $activity The activity-object. - * @param int $user_id The id of the local blog-user. + * @param array $activity The activity-object. + * @param int|int[] $user_id The id of the local blog-user. */ - public static function handle_update( $activity, $user_id ): void { - // We only process activities that are target to the application user. - if ( Actors::BLOG_USER_ID !== $user_id ) { - return; - } - - // Check if Activity is public or not. - if ( ! is_activity_public( $activity ) ) { - return; - } - - // Check if an object is set and it is an object of type `Event`. - if ( ! isset( $activity['object']['type'] ) || 'Event' !== $activity['object']['type'] ) { - return; - } - - // Check that we are actually following/or have a pending follow request this actor. - $event_source_post_id = Event_Source::get_post_id_by_activitypub_id( $activity['actor'] ); - if ( ! $event_source_post_id ) { - return; - } - - if ( Event_Sources::is_time_passed( $activity['object']['startTime'] ) ) { - return; - } - - $transmogrifier = Setup::get_transmogrifier(); - - if ( ! $transmogrifier ) { - return; - } - - $transmogrifier::save( $activity['object'], $event_source_post_id ); + public static function handle_update( array $activity, int|array $user_id ): void { + // We handle updates the same as we handle creates for now (specification though says we should ignore it). + Create::handle_create( $activity, $user_id ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/model/class-event-source.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/model/class-event-source.php index eb380c42..719d0aa7 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/model/class-event-source.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/model/class-event-source.php @@ -13,7 +13,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Model; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Actor; use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources; @@ -46,7 +46,7 @@ use WP_Post; * @method array get_endpoints() */ class Event_Source extends Actor { - const ACTIVITYPUB_USER_HANDLE_REGEXP = '(?:([A-Za-z0-9_.-]+)@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))'; + public const ACTIVITYPUB_USER_HANDLE_REGEXP = '(?:([A-Za-z0-9_.-]+)@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))'; /** * The WordPress Post ID which stores the event source. @@ -133,7 +133,7 @@ class Event_Source extends Actor { * @param string $activitypub_actor_id The ActivityPub actor ID. * @return int|false The Event Sources Post ID, if a WordPress Post representing it is found, false otherwise. */ - public static function get_post_id_by_activitypub_id( $activitypub_actor_id ) { + public static function get_post_id_by_activitypub_id( string $activitypub_actor_id ) { $event_sources = Event_Sources::get_event_sources(); return array_search( $activitypub_actor_id, $event_sources, true ); @@ -145,7 +145,7 @@ class Event_Source extends Actor { * @param int|string $event_source_id The ActivityPub actor ID as string or the Post ID as int of the Event Source. * @return ?Event_Source The Event Sources if it exists, false otherwise. */ - public static function get_by_id( $event_source_id ): ?Event_Source { + public static function get_by_id( int|string $event_source_id ): ?Event_Source { $post_id = is_integer( $event_source_id ) ? $event_source_id : self::get_post_id_by_activitypub_id( $event_source_id ); if ( ! $post_id ) { @@ -172,15 +172,21 @@ class Event_Source extends Actor { /** * Convert a Custom-Post-Type input to an \Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source. * - * @param \WP_Post $post The post object. + * @param WP_Post $post The post object. * @return ?Event_Source */ - public static function init_from_cpt( $post ): ?Event_Source { + public static function init_from_cpt( WP_Post $post ): ?Event_Source { if ( Event_Sources::POST_TYPE !== $post->post_type ) { return null; } - $actor_json = \get_post_meta( $post->ID, '_activitypub_actor_json', true ); - $object = static::init_from_json( $actor_json ); + + if ( empty( $post->post_content ) ) { + $actor_json = \get_post_meta( $post->ID, '_activitypub_actor_json', true ); + } else { + $actor_json = $post->post_content; + } + + $object = static::init_from_json( $actor_json ); if ( \is_wp_error( $object ) ) { return null; @@ -202,10 +208,6 @@ class Event_Source extends Actor { ); } - if ( ! $object instanceof Event_Source ) { // To make phpstan happy. - return null; - } - return $object; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/object/class-event-fep-8a8e.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/object/class-event-fep-8a8e.php new file mode 100644 index 00000000..43fc8db6 --- /dev/null +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/object/class-event-fep-8a8e.php @@ -0,0 +1,101 @@ += 0.0f, <= 100.0f] + */ + protected $accuracy; + + /** + * Indicates the altitude of a place. The measurement unit is indicated using the unit's property. + * If unit is not specified, the default is assumed to be "m" indicating meters. + * + * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-altitude + * @var float xsd:float + */ + protected $altitude; + + /** + * The latitude of a place. + * + * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-latitude + * @var float xsd:float + */ + protected $latitude; + + /** + * The longitude of a place. + * + * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-longitude + * @var float xsd:float + */ + protected $longitude; + + /** + * The radius from the given latitude and longitude for a Place. + * + * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-radius + * @var float + */ + protected $radius; + + /** + * Specifies the measurement units for the `radius` and `altitude` properties. + * + * @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-units + * @var string + */ + protected $units; + + /** + * The address of the place. + * + * @see https://schema.org/PostalAddress + * @var array|string + */ + protected $address; + + /** + * External URL/Website of the place/venue. + * + * @see https://schema.org/sameAs + * @var string + */ + protected $same_as; + + /** + * Telephone number of the place. + * + * @see https://schema.org/telephone + * @var string + */ + protected $telephone; +} diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/scheduler/class-event.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/scheduler/class-event.php index 668abc39..d8648548 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/scheduler/class-event.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/scheduler/class-event.php @@ -19,7 +19,7 @@ class Event { * Initialize the class, registering WordPress hooks. */ public static function init() { - \add_action( 'transition_post_status', array( self::class, 'maybe_schedule_event_post_activity' ), 50, 3 ); + \add_action( 'wp_after_insert_post', array( self::class, 'maybe_schedule_event_post_activity' ), 50, 4 ); \add_action( 'event_bridge_for_activitypub_add_event_post_to_outbox', array( self::class, 'add_event_post_to_outbox' ), 10, 3 ); \add_filter( 'activitypub_is_post_disabled', array( self::class, 'is_post_disabled_for_the_activitypub_plugin' ), 50, 2 ); } @@ -44,13 +44,14 @@ class Event { } /** - * Schedule Activities. + * Handle post updates and determine the appropriate Activity type. * - * @param string $new_status New post status. - * @param string $old_status Old post status. - * @param \WP_Post $post Post object. + * @param int $post_id Post ID. + * @param \WP_Post $post Post object. + * @param bool $update Whether this is an existing post being updated. + * @param null|\WP_Post $post_before Post object before the update. */ - public static function maybe_schedule_event_post_activity( $new_status, $old_status, $post ): void { + public static function maybe_schedule_event_post_activity( $post_id, $post, $update, $post_before ) { if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) { return; } @@ -63,9 +64,17 @@ class Event { return; } + // Bail on bulk edits, unless post author or post status changed. + if ( isset( $_REQUEST['bulk_edit'] ) && -1 === (int) $_REQUEST['post_author'] && -1 === (int) $_REQUEST['_status'] ) { // phpcs:ignore WordPress + return; + } + + $new_status = get_post_status( $post ); + $old_status = $post_before ? get_post_status( $post_before ) : null; + switch ( $new_status ) { case 'publish': - $type = ( 'publish' === $old_status ) ? 'Update' : 'Create'; + $type = $update ? 'Update' : 'Create'; break; case 'draft': diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event-organiser.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event-organiser.php index 4407c54f..5cc6688c 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event-organiser.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event-organiser.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as Base_Event_Transformer; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event.php index 09468e20..1fb66182 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-event.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Event as Event_Object; use Activitypub\Activity\Extended_Object\Place; @@ -38,6 +38,20 @@ abstract class Event extends Post { */ protected $wp_taxonomy; + /** + * A valid timezone string. + * + * @var ?string + */ + protected $timezone_string = null; + + /** + * Bool that stores whether timezone is indeed not known = null. + * + * @var bool + */ + protected $no_valid_timezone_known = false; + /** * Returns the ActivityStreams 2.0 Object-Type for an Event. * @@ -188,7 +202,7 @@ abstract class Event extends Post { * @param ?string $time The time which needs to be formatted. */ protected static function format_time( $time ) { - if ( is_null( $time ) ) { + if ( null === $time ) { return ''; } $start_datetime = new DateTime( $time ); @@ -433,7 +447,6 @@ abstract class Event extends Post { // Fill in the shortcodes. \setup_postdata( $this->item ); - Shortcodes::register(); $summary = \do_shortcode( $summary ); \wp_reset_postdata(); @@ -491,19 +504,20 @@ abstract class Event extends Post { */ public function get_formatted_address( $include_location_name = false, $args = array() ) { $location = $this->get_location(); + Shortcodes::register(); if ( $location instanceof Place ) { - $location_name = $location->get_name(); - $foramted_address = self::format_address( $location->get_address(), $args ); + $location_name = $location->get_name(); + $formatted_address = self::format_address( $location->get_address(), $args ); - $loaction_parts = array(); + $location_parts = array(); if ( $location_name ) { $location_parts[] = $location_name; } - if ( $foramted_address ) { - $location_parts[] = $foramted_address; + if ( $formatted_address ) { + $location_parts[] = $formatted_address; } if ( ! empty( $location_parts ) ) { @@ -531,16 +545,76 @@ abstract class Event extends Post { } /** - * By default set the timezone of the WordPress site. + * Get the timezone of the event if known. + * + * By default gets the timezone of the WordPress site. + * This is not to be overwritten by the event transformers. Instead override get_timezone_string. + * This function does also cache and sanitize the timezone string. + * + * @return string|null The timezone string of the event. Or no null if timezone information. + */ + final public function get_timezone(): ?string { + // Return cached timezone, if a valid one is known. + if ( $this->timezone_string ) { + return $this->timezone_string; + } + + // Return cached failure. + if ( $this->no_valid_timezone_known ) { + return null; + } + + // Step 1: Get timezone string. + $timezone_string = $this->get_timezone_string(); + + // Step 2: Fallback to site default if child class override returned null or empty string. + if ( ! $timezone_string ) { + $timezone_string = $this->get_site_timezone_string(); + } + + // Step 3: Reject non-strings early. + if ( ! \is_string( $timezone_string ) ) { + $this->no_valid_timezone_known = true; + return null; + } + + // Step 4: Validate against known timezone identifiers. + $valid_timezone_strings = \DateTimeZone::listIdentifiers(); + + if ( \in_array( $timezone_string, $valid_timezone_strings, true ) ) { + // Cache and return valid timezone identifier string. + $this->timezone_string = $timezone_string; + return $this->timezone_string; + } + + // Cache failure. + $this->no_valid_timezone_known = true; + return null; + } + + /** + * Get the timezone string of the event. Will be validated later. * * This is likely to be overwritten by the actual transformer. * - * @return string The timezone string of the site. + * @return mixed */ - public function get_timezone(): string { + protected function get_timezone_string(): mixed { + return $this->get_site_timezone_string(); + } + + /** + * Non-overridable fallback method for timezone. + * + * Often in WordPress timezone string might be a UTC offset like "+01:00". But this will be sanitized be later in get_timezone(). + * + * @return string + */ + final protected function get_site_timezone_string(): string { return \wp_timezone_string(); } + /** * Remove the permalink shortcode from a WordPress template. * diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventin.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventin.php index fd518845..6d01b302 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventin.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventin.php @@ -11,7 +11,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event; @@ -51,20 +51,20 @@ final class Eventin extends Event { * Get the end time from the event object. */ public function get_start_time(): string { - return \gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $this->event_model->get_start_datetime() ) ); + return $this->event_model->get_start_datetime( 'Y-m-d\TH:i:sP' ); } /** * Get the end time from the event object. */ public function get_end_time(): string { - return \gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $this->event_model->get_end_datetime() ) ); + return $this->event_model->get_end_datetime( 'Y-m-d\TH:i:sP' ); } /** * Get the timezone of the event. */ - public function get_timezone(): string { + public function get_timezone_string(): string { return $this->event_model->get_timezone(); } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventon.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventon.php index c005e1aa..0ccd82be 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventon.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventon.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as Event_Transformer; @@ -20,6 +20,8 @@ use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\EventOn as EventO * * This transformer tries a different principle: The setters are chainable. * + * @link https://docs.myeventon.com/documentations/event-post-meta-variables/ + * * @since 1.0.0 */ final class EventOn extends Event_Transformer { @@ -102,8 +104,8 @@ final class EventOn extends Event_Transformer { * Get the end time from the events metadata. */ public function get_end_time(): ?string { - $end_time = \get_post_meta( $this->item->ID, '_unix_end_ev', true ); - $timezone = \get_post_meta( $this->item->ID, '_evo_tz', true ); + $end_time = \get_post_meta( $this->item->ID, 'evcal_erow', true ); + $timezone = \get_post_meta( $this->item->ID, 'evo_event_timezone', true ); $timezone = $timezone ? new \DateTimeZone( $timezone ) : null; if ( is_null( $end_time ) || empty( $end_time ) ) { @@ -117,18 +119,16 @@ final class EventOn extends Event_Transformer { * * @return string */ - public function get_timezone(): string { - $timezone = \get_post_meta( $this->item->ID, '_evo_tz', true ); - - return $timezone ?? \wp_timezone_string(); + public function get_timezone_string(): string { + return \get_post_meta( $this->item->ID, 'evo_event_timezone', true ); } /** * Get the end time from the events metadata. */ public function get_start_time(): string { - $start_time = \get_post_meta( $this->item->ID, '_unix_start_ev', true ); - $timezone = \get_post_meta( $this->item->ID, '_evo_tz', true ); + $start_time = \get_post_meta( $this->item->ID, 'evcal_srow', true ); + $timezone = \get_post_meta( $this->item->ID, 'evo_event_timezone', true ); $timezone = $timezone ? new \DateTimeZone( $timezone ) : null; return \wp_date( 'Y-m-d\TH:i:sP', (int) $start_time, $timezone ); diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventprime.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventprime.php index b3008f69..1d642ef8 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventprime.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-eventprime.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as Base_Event_Transformer; @@ -27,7 +27,7 @@ final class EventPrime extends Base_Event_Transformer { public function get_end_time(): ?string { $timestamp = \get_post_meta( $this->wp_object->ID, 'em_end_date', true ); if ( $timestamp ) { - return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp ); + return \wp_date( 'Y-m-d\TH:i:sP', $timestamp ); } else { return null; } @@ -39,7 +39,7 @@ final class EventPrime extends Base_Event_Transformer { public function get_start_time(): string { $timestamp = \get_post_meta( $this->wp_object->ID, 'em_start_date', true ); if ( $timestamp ) { - return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp ); + return \wp_date( 'Y-m-d\TH:i:sP', $timestamp ); } else { return ''; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-events-manager.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-events-manager.php index f61f50a6..a8a74938 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-events-manager.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-events-manager.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as Event_Transformer; @@ -66,11 +66,7 @@ final class Events_Manager extends Event_Transformer { */ public function get_location() { if ( $this->is_online() ) { - if ( property_exists( $this->em_event->event_location, 'data' ) ) { - $event_location = $this->em_event->event_location->data; - } else { - $event_location = array(); - } + $event_location = $this->em_event->event_location->data; $event_link_url = isset( $event_location['url'] ) ? $event_location['url'] : null; $event_link_text = isset( $event_location['text'] ) ? $event_location['text'] : esc_html__( 'Link', 'event-bridge-for-activitypub' ); @@ -103,29 +99,26 @@ final class Events_Manager extends Event_Transformer { } /** - * Get the end time from the events metadata. + * Get the start time of the event. */ - public function get_end_time(): ?string { - return null; + public function get_start_time(): string { + return $this->em_event->start()->format( 'Y-m-d\TH:i:sP' ); } /** - * Get the end time from the events metadata. + * Get the end time of the event. */ - 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; + public function get_end_time(): string { + return $this->em_event->end()->format( 'Y-m-d\TH:i:sP' ); + } - // Create a DateTime object with the given date, time, and timezone. - $datetime = new DateTime( $date_string . ' ' . $time_string, new DateTimeZone( $timezone_string ) ); - - // Set the timezone for proper formatting. - $datetime->setTimezone( new DateTimeZone( 'UTC' ) ); - - // Format the DateTime object as 'Y-m-d\TH:i:s\Z'. - $formatted_date = $datetime->format( 'Y-m-d\TH:i:s\Z' ); - return $formatted_date; + /** + * Get the timezone. Events calendar also supports "UTC-offset timezones", ActivityPub federation does not. + * + * @return string + */ + public function get_timezone_string(): string { + return $this->em_event->get_timezone()->getName(); } /** @@ -170,12 +163,7 @@ final class Events_Manager extends Event_Transformer { */ private function get_event_link_attachment(): ?array { if ( $this->is_online() ) { - if ( property_exists( $this->em_event->event_location, 'data' ) ) { - $event_location = $this->em_event->event_location->data; - } else { - $event_location = array(); - } - + $event_location = $this->em_event->event_location->data; $event_link_url = isset( $event_location['url'] ) ? $event_location['url'] : null; $event_link_text = isset( $event_location['text'] ) ? $event_location['text'] : __( 'Link', 'event-bridge-for-activitypub' ); @@ -224,16 +212,23 @@ final class Events_Manager extends Event_Transformer { $post_tags = \wp_get_post_terms( $this->item->ID, 'event-tags' ); - if ( $post_tags ) { - foreach ( $post_tags as $post_tag ) { - $tag = array( + if ( \is_wp_error( $post_tags ) ) { + return $tags; + } + + foreach ( $post_tags as $post_tag ) { + // @phpstan-ignore-next-line + if ( $post_tag instanceof \WP_Term ) { + $tag = array( 'type' => 'Hashtag', 'href' => \esc_url( \get_tag_link( $post_tag->term_id ) ), 'name' => esc_hashtag( $post_tag->name ), ); + $tags[] = $tag; } } + return $tags; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-gatherpress.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-gatherpress.php index 9b4f49f7..75dfd0d0 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-gatherpress.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-gatherpress.php @@ -1,28 +1,34 @@ gp_venue = $this->gp_event->get_venue_information(); } + /** + * Return the correct type of an Event. + * + * @return string + */ + public function get_type(): string { + return 'Event'; + } + /** * Get the event location. * - * @return ?Place The place objector null if not place set. + * @return Place|array|null A Place object or VirtualLocation. */ - public function get_location(): ?Place { - $address = $this->gp_venue['full_address']; - if ( $address ) { - $place = new Place(); - $place->set_type( 'Place' ); - $place->set_name( $address ); - $place->set_address( $address ); - return $place; + public function get_location(): mixed { + $event_link = $this->gp_event->maybe_get_online_event_link(); + if ( $event_link ) { + return array( + 'type' => 'VirtualLocation', + 'url' => $event_link, + ); + } + + $term = current( (array) get_the_terms( $this->gp_event->event, Venue::TAXONOMY ) ); + + if ( ! empty( $term ) && is_a( $term, 'WP_Term' ) ) { + $venue_post = Venue::get_instance()->get_venue_post_from_term_slug( $term->slug ); + + if ( ! $venue_post ) { + return null; + } } else { return null; } + + $venue_transformer = new Venue_Transformer( $venue_post ); + $full_location_object = false; + $location = $venue_transformer->to_object( $full_location_object ); + return $location; } /** * Get the end time from the event object. */ public 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:sP' ); } /** * Get the end time from the event object. */ public function get_start_time(): string { - return $this->gp_event->get_datetime_start( 'Y-m-d\TH:i:s\Z' ); - } - - /** - * Get the event link from the events metadata. - */ - private function get_event_link(): array { - - $event_link = get_post_meta( $this->item->ID, 'event-link', true ); - if ( $event_link ) { - return array( - 'type' => 'Link', - 'name' => 'Website', - 'href' => \esc_url( $event_link ), - 'mediaType' => 'text/html', - ); - } - - return array(); - } - - /** - * Overrides/extends the get_attachments function to also add the event Link. - */ - protected function get_attachment(): array { - $attachments = parent::get_attachment(); - if ( count( $attachments ) ) { - $attachments[0]['type'] = 'Document'; - $attachments[0]['name'] = 'Banner'; - } - $event_link = $this->get_event_link(); - if ( $event_link ) { - $attachments[] = $this->get_event_link(); - } - return $attachments; + return $this->gp_event->get_datetime_start( 'Y-m-d\TH:i:sP' ); } /** @@ -130,27 +122,44 @@ final class GatherPress extends Event { return ''; // Skip rendering this block. } - return $block_content; // Return the content for other blocks. + return str_replace( '

', '', $block_content ); // Return the content for other blocks. } /** - * Apply the filter for preventing the rendering off gatherpress blocks just in time. + * Transform to an the Event object. * - * @return Event_Object + * @return Base_Object|WP_Error */ - public function to_object(): Event_Object { + /** + * Transform to an the Event object. + * + * @return Base_Object|WP_Error + */ + public function to_object(): Base_Object|WP_Error { + // Apply the filter for preventing the rendering off gatherpress blocks just in time. add_filter( 'render_block', array( self::class, 'filter_gatherpress_blocks' ), 10, 2 ); - $activitypub_object = parent::to_object(); - remove_filter( 'render_block', array( self::class, 'filter_gatherpress_blocks' ) ); - return $activitypub_object; - } - /** - * Determine whether the event is online. - * - * @return bool - */ - public function get_is_online(): bool { - return $this->gp_event->maybe_get_online_event_link() ? true : false; + // Transform all properties via getter functions. + $object = new Event_FEP_8a8e(); + $object = $this->transform_object_properties( $object ); + + if ( \is_wp_error( $object ) ) { + return $object; + } + + $this->set_audience( $object ); + + remove_filter( 'render_block', array( self::class, 'filter_gatherpress_blocks' ) ); + + // Maybe modify object for content warning. + $content_warning = get_content_warning( $this->item ); + if ( ! empty( $content_warning ) ) { + $object->set_sensitive( true ); + $object->set_summary( $content_warning ); + $object->set_summary_map( null ); + $object->set_dcterms( array( 'subject' => $content_warning ) ); + } + + return $object; } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-modern-events-calendar-lite.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-modern-events-calendar-lite.php index 48011a65..0da29e5b 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-modern-events-calendar-lite.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-modern-events-calendar-lite.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event; @@ -67,7 +67,10 @@ final class Modern_Events_Calendar_Lite extends Event { * @return string */ public function get_start_time(): string { - return \gmdate( 'Y-m-d\TH:i:s\Z', $this->mec_event->get_datetime()['start']['timestamp'] ); + $datetime = $this->mec_event->get_datetime()['start']['datetime']; + $timezone = $this->get_timezone() ? new \DateTimeZone( $this->get_timezone() ) : null; + $start_time = new \DateTime( $datetime, $timezone ); + return $start_time->format( 'Y-m-d\TH:i:sP' ); } /** @@ -76,7 +79,10 @@ final class Modern_Events_Calendar_Lite extends Event { * @return string */ public function get_end_time(): string { - return \gmdate( 'Y-m-d\TH:i:s\Z', $this->mec_event->get_datetime()['end']['timestamp'] ); + $datetime = $this->mec_event->get_datetime()['end']['datetime']; + $timezone = $this->get_timezone() ? new \DateTimeZone( $this->get_timezone() ) : null; + $end_time = new \DateTime( $datetime, $timezone ); + return $end_time->format( 'Y-m-d\TH:i:sP' ); } /** @@ -113,15 +119,11 @@ final class Modern_Events_Calendar_Lite extends Event { } /** - * Get the location. + * Get the timezone string of the current event. + * + * @return mixed */ - public function get_timezone(): string { - $timezone = get_post_meta( $this->item->ID, 'mec_timezone', true ); - - if ( 'global' === $timezone ) { - return parent::get_timezone(); - } - - return $timezone; + public function get_timezone_string(): mixed { + return \get_post_meta( $this->item->ID, 'mec_timezone', true ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-spiffy-calendar.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-spiffy-calendar.php new file mode 100644 index 00000000..9030e739 --- /dev/null +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-spiffy-calendar.php @@ -0,0 +1,140 @@ +item->ID, '_spiffy_event_begin', true ); + $start_time = \get_post_meta( $this->item->ID, '_spiffy_event_begin_time', true ); + + $start_datetime = $this->get_datetime_from_fuzzy_input( $start_date, $start_time ); + + return $start_datetime->format( 'Y-m-d\TH:i:sP' ); + } + + /** + * Get the end time from the event object. + */ + public function get_end_time(): string { + $end_date = \get_post_meta( $this->item->ID, '_spiffy_event_end', true ); + $end_time = \get_post_meta( $this->item->ID, '_spiffy_event_end_time', true ); + + $end_datetime = $this->get_datetime_from_fuzzy_input( $end_date, $end_time ); + + return $end_datetime->format( 'Y-m-d\TH:i:sP' ); + } + + /** + * Get the location. + * + * @return ?Place + */ + public function get_location(): ?Place { + $location = \get_post_meta( $this->item->ID, '_spiffy_event_location', true ); + + if ( ! $location ) { + return null; + } + + $place = new Place(); + $place->set_address( $location ); + $place->set_name( $location ); + return $place; + } + + /** + * Overrides/extends the get_attachments function to also add the event Link. + * + * @return array + */ + protected function get_attachment(): array { + $attachments = parent::get_attachment(); + if ( \count( $attachments ) ) { + $attachments[0]['type'] = 'Document'; + $attachments[0]['name'] = 'Banner'; + } + $event_link = $this->get_event_link(); + if ( $event_link ) { + $attachments[] = $event_link; + } + return $attachments; + } + + /** + * Get the event link from the events metadata. + * + * @return array|null Associated array of an ActivityStreams Link object with the event link. + */ + private function get_event_link(): ?array { + $event_link = \get_post_meta( $this->item->ID, '_spiffy_event_link', true ); + if ( $event_link ) { + return array( + 'type' => 'Link', + 'name' => __( 'Event Link', 'event-bridge-for-activitypub' ), + 'href' => \esc_url( $event_link ), + 'mediaType' => 'text/html', + ); + } + return null; + } + + /** + * Generate the best datetime object of the fuzzy human made data Spiffy Calendar provides. + * + * @param string $date The date as 2026-05-18 string. + * @param string $time Fuzzy time like 14:00, 2pm, 2 PM, noon, midnight, etc. + * @return DateTimeImmutable + */ + private function get_datetime_from_fuzzy_input( string $date = '', string $time = '' ): DateTimeImmutable { + $timezone = new DateTimeZone( $this->get_timezone_string() ); + + // Normalize fuzzy human time. + $time = trim( strtolower( $time ) ); + + $map = array( + __( 'noon', 'event-bridge-for-activitypub' ) => '12:00', + __( 'midday', 'event-bridge-for-activitypub' ) => '12:00', + __( 'midnight', 'event-bridge-for-activitypub' ) => '00:00', + __( 'morning', 'event-bridge-for-activitypub' ) => '09:00', + __( 'afternoon', 'event-bridge-for-activitypub' ) => '15:00', + __( 'evening', 'event-bridge-for-activitypub' ) => '19:00', + ); + + $time = $map[ $time ] ?? $time; + + $input = trim( "$date $time" ); + + try { + $datetime = new DateTimeImmutable( $input, $timezone ); + } catch ( \Throwable $e ) { + $datetime = new DateTimeImmutable( "$date 00:00", $timezone ); + } + + return $datetime; + } +} diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-the-events-calendar.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-the-events-calendar.php index 61cb979e..29480433 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-the-events-calendar.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-the-events-calendar.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Event as Event_Object; use Activitypub\Activity\Extended_Object\Place; @@ -81,7 +81,7 @@ final class The_Events_Calendar extends Event { */ public function get_end_time(): string { $utc_time = get_post_meta( $this->tribe_event->ID, '_EventEndDateUTC', true ); - $timezone = new \DateTimeZone( $this->get_timezone() ); + $timezone = new \DateTimeZone( $this->get_timezone_string() ); $time = new \DateTime( $utc_time ); $time->setTimezone( $timezone ); return $time->format( 'Y-m-d\TH:i:sP' ); @@ -92,7 +92,7 @@ final class The_Events_Calendar extends Event { */ public function get_start_time(): string { $utc_time = get_post_meta( $this->tribe_event->ID, '_EventStartDateUTC', true ); - $timezone = new \DateTimeZone( $this->get_timezone() ); + $timezone = new \DateTimeZone( $this->get_timezone_string() ); $time = new \DateTime( $utc_time ); $time->setTimezone( $timezone ); return $time->format( 'Y-m-d\TH:i:sP' ); @@ -101,17 +101,11 @@ final class The_Events_Calendar extends Event { /** * Get the timezone of the event. * - * @return string The timezone string of the site. + * @return string The timezone string of the event. */ - public function get_timezone(): string { + public function get_timezone_string(): string { // @phpstan-ignore-next-line - $timezone = $this->tribe_event->timezone; - - if ( ! $timezone || ! is_string( $timezone ) ) { - return parent::get_timezone(); - } - - return $timezone; + return (string) $this->tribe_event->timezone; } /** @@ -144,8 +138,10 @@ final class The_Events_Calendar extends Event { /** * Check if the event is an online event. + * + * @return false */ - public function get_is_online(): bool { + public function get_is_online() { return false; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-vs-event-list.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-vs-event-list.php index 1ea96415..cd793041 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-vs-event-list.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-vs-event-list.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as Event_Transformer; @@ -52,7 +52,7 @@ final class VS_Event_List extends Event_Transformer { if ( is_null( $end_time ) || empty( $end_time ) || 'no' === $end_time ) { return null; } - return \gmdate( 'Y-m-d\TH:i:s\Z', (int) $end_time ); + return \wp_date( 'Y-m-d\TH:i:sP', (int) $end_time ); } /** @@ -60,7 +60,7 @@ final class VS_Event_List extends Event_Transformer { */ public function get_start_time(): string { $start_time = \get_post_meta( $this->item->ID, 'event-start-date', true ); - return \gmdate( 'Y-m-d\TH:i:s\Z', (int) $start_time ); + return \wp_date( 'Y-m-d\TH:i:sP', (int) $start_time ); } /** diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-wp-event-manager.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-wp-event-manager.php index eda001e5..7da0f16f 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-wp-event-manager.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/event/class-wp-event-manager.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as Event_Transformer; @@ -30,7 +30,7 @@ final class WP_Event_Manager extends Event_Transformer { * @return bool */ protected function get_is_online(): bool { - $is_online_text = get_post_meta( $this->item->ID, '_event_online', true ); + $is_online_text = \get_post_meta( $this->item->ID, '_event_online', true ); $is_online = false; // Radio buttons. if ( 'yes' === $is_online_text ) { @@ -49,7 +49,7 @@ final class WP_Event_Manager extends Event_Transformer { * @return ?Place The Place. */ public function get_location(): ?Place { - $location_name = get_post_meta( $this->item->ID, '_event_location', true ); + $location_name = \get_post_meta( $this->item->ID, '_event_location', true ); if ( $location_name ) { $location = new Place(); @@ -68,11 +68,12 @@ final class WP_Event_Manager extends Event_Transformer { * @return ?string The events end-datetime if is set, null otherwise. */ public function get_end_time(): ?string { - $end_date = get_post_meta( $this->item->ID, '_event_end_date', true ); + $end_date = \get_post_meta( $this->item->ID, '_event_end_date', true ); if ( ! $end_date ) { return null; } - $timezone = new DateTimeZone( $this->get_timezone() ); + + $timezone = $this->get_timezone() ? new DateTimeZone( $this->get_timezone() ) : null; if ( is_numeric( $end_date ) ) { $end_date = '@' . $end_date; @@ -86,22 +87,19 @@ final class WP_Event_Manager extends Event_Transformer { /** * Get timezone. * - * @return string + * @return mixed */ - public function get_timezone(): string { - $time_zone = get_post_meta( $this->item->ID, '_event_timezone', true ); - if ( $time_zone ) { - return $time_zone; - } - return parent::get_timezone(); + public function get_timezone_string(): mixed { + return \get_post_meta( $this->item->ID, '_event_timezone', true ); } /** * Get the end time from the events metadata. */ public function get_start_time(): string { - $start_date = get_post_meta( $this->item->ID, '_event_start_date', true ); - $timezone = new DateTimeZone( $this->get_timezone() ); + $start_date = \get_post_meta( $this->item->ID, '_event_start_date', true ); + + $timezone = $this->get_timezone() ? new DateTimeZone( $this->get_timezone() ) : null; if ( is_numeric( $start_date ) ) { $start_date = '@' . $start_date; @@ -118,7 +116,7 @@ final class WP_Event_Manager extends Event_Transformer { * @return ?array */ private function get_event_link_attachment(): ?array { - $event_link_url = get_post_meta( $this->item->ID, '_event_video_url', true ); + $event_link_url = \get_post_meta( $this->item->ID, '_event_video_url', true ); if ( str_starts_with( $event_link_url, 'http' ) ) { return array( diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-post-place.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-post-place.php index 355af17f..511b48aa 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-post-place.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-post-place.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place as Place_Object; use Activitypub\Transformer\Post; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-term-place.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-term-place.php index 2a70b88a..703758f6 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-term-place.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-base-term-place.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place as Place_Object; use Activitypub\Transformer\Base; @@ -128,7 +128,7 @@ abstract class Base_Term_Place extends Base { /** * Don't set sensitive per default. * - * @return null + * @return null|bool */ public function get_sensitive() { return null; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-event-organiser.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-event-organiser.php index f9fa4050..adfdaf6e 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-event-organiser.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-event-organiser.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Class for the ActivityPub transformer of the venues of The Events Calendar to `as:Place`. diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventon.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventon.php index e71cc55c..7092945c 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventon.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventon.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Place as Place_Object; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventprime.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventprime.php index f78964cd..668b6681 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventprime.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-eventprime.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Class for the ActivityPub transformer of the venues of The Events Calendar to `as:Place`. diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-events-manager.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-events-manager.php index 21b381e2..dad8fcad 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-events-manager.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-events-manager.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\Base_Post_Place; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-gatherpress.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-gatherpress.php new file mode 100644 index 00000000..acd2f5bd --- /dev/null +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-gatherpress.php @@ -0,0 +1,152 @@ +venue_meta = json_decode( get_post_meta( $this->item->ID, 'gatherpress_venue_information', true ) ); + } + + /** + * Return the correct type of an Event. + * + * @return string + */ + public function get_type(): string { + return 'Place'; + } + + /** + * Get the event location. + * + * @return string The name of the venue. + */ + public function get_name(): string { + return $this->item->post_title; + } + + /** + * The full address of the venue. + * + * @return string|null + */ + public function get_address(): ?string { + return $this->venue_meta->fullAddress ?? null; + } + + /** + * Latitude of the venue. + * + * @return float|null + */ + public function get_latitude(): ?float { + return $this->venue_meta->latitude ?? null; + } + + /** + * Longitude of the venue. + * + * @return float|null + */ + public function get_longitude(): ?float { + return $this->venue_meta->longitude ?? null; + } + + /** + * The telephone number of the venue. + * + * @return string|null + */ + public function get_telephone(): ?string { + return $this->venue_meta->phone_number ?? null; + } + + /** + * The website of the venue. + * + * @return string|null + */ + public function get_same_as(): ?string { + return $this->venue_meta->website ?? null; + } + + /** + * Generic function that converts an WordPress location object to an ActivityPub-Place object. + * + * @param bool $full_object bool Return an object with all properties set, or a minimal one as used within an `as:Event`s location. + * @return Place|\WP_Error + */ + public function to_object( $full_object = true ): Base_Object|WP_Error { + $activitypub_object = new Place(); + $activitypub_object = $this->transform_object_properties( $activitypub_object ); + + if ( \is_wp_error( $activitypub_object ) ) { + return $activitypub_object; + } + + if ( ! empty( $activitypub_object->get_content() ) ) { + $activitypub_object->set_content_map( + array( + $this->get_locale() => $this->get_content(), + ) + ); + } + + $updated = \strtotime( $this->item->post_modified_gmt ); + + $activitypub_object->set_updated( \gmdate( 'Y-m-d\TH:i:s\Z', $updated ) ); + + if ( $full_object ) { + $published = \strtotime( $this->item->post_date_gmt ); + + $activitypub_object->set_published( \gmdate( 'Y-m-d\TH:i:s\Z', $published ) ); + + $activitypub_object->set_to( + array( + 'https://www.w3.org/ns/activitystreams#Public', + $this->get_actor_object()->get_followers(), + ) + ); + } + + // @phpstan-ignore-next-line + return $activitypub_object; + } +} diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-the-events-calendar.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-the-events-calendar.php index 5632bcc0..92219e63 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-the-events-calendar.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transformer/place/class-the-events-calendar.php @@ -9,7 +9,7 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\Base_Post_Place; @@ -60,4 +60,22 @@ final class The_Events_Calendar extends Base_Post_Place { return $postal_address; } + + /** + * Get the latitude of the place. + * + * @return ?float The latitude if it is known. + */ + public function get_latitude() { + return tribe_get_coordinates( $this->item->ID )['lat'] ?? null; + } + + /** + * Get the longitude of the place. + * + * @return ?float The longitude if it is known. + */ + public function get_longitude() { + return tribe_get_coordinates( $this->item->ID )['lng'] ?? null; + } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-base.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-base.php index 00a5c031..f1b2244b 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-base.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-base.php @@ -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 ) ); diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-gatherpress.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-gatherpress.php index 47aafe79..b9979d00 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-gatherpress.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-gatherpress.php @@ -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; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-the-events-calendar.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-the-events-calendar.php index d36f448b..aed1863e 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-the-events-calendar.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-the-events-calendar.php @@ -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; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-vs-event-list.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-vs-event-list.php index bb738b37..0c7fc5da 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-vs-event-list.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/class-vs-event-list.php @@ -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; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-sanitizer.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-sanitizer.php index aae19039..b4bb043e 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-sanitizer.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-sanitizer.php @@ -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'] ) ); } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-event-repository.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-event-repository.php index a4f1f846..818e8b39 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-event-repository.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-event-repository.php @@ -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. diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-organizer-repository.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-organizer-repository.php index 03720bfe..becb5da2 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-organizer-repository.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-organizer-repository.php @@ -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. diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-venue-repository.php b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-venue-repository.php index 5b842c24..47d0e11d 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-venue-repository.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/activitypub/transmogrifier/helper/class-the-events-calendar-venue-repository.php @@ -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. * diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-event-plugin-admin-notices.php b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-event-plugin-admin-notices.php index 1b23768f..c7ccd2b8 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-event-plugin-admin-notices.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-event-plugin-admin-notices.php @@ -12,7 +12,7 @@ namespace Event_Bridge_For_ActivityPub\Admin; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration; @@ -49,7 +49,7 @@ class Event_Plugin_Admin_Notices { * @return bool */ private function event_post_type_is_not_activitypub_enabled(): bool { - return ! in_array( $this->event_plugin::get_post_type(), get_option( 'activitypub_support_post_types', array() ), true ); + return ! \in_array( $this->event_plugin::get_post_type(), get_option( 'activitypub_support_post_types', array() ), true ); } /** @@ -79,7 +79,7 @@ class Event_Plugin_Admin_Notices { return; } $activitypub_plugin_data = get_plugin_data( ACTIVITYPUB_PLUGIN_FILE ); - $notice = sprintf( + $notice = \sprintf( /* translators: 1: the name of the event plugin a admin notice is shown. 2: The name of the ActivityPub plugin. */ _x( 'You have installed the %1$s plugin, but the event post type of the plugin %2$s is not enabled in the %1$s settings.', diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-general-admin-notices.php b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-general-admin-notices.php index 6a5302f0..5e7fb343 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-general-admin-notices.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-general-admin-notices.php @@ -12,7 +12,7 @@ namespace Event_Bridge_For_ActivityPub\Admin; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Class responsible for general admin notices. @@ -52,7 +52,7 @@ class General_Admin_Notices { * @return string */ public static function get_admin_notice_activitypub_plugin_not_enabled(): string { - return sprintf( + return \sprintf( /* translators: 1: An URL that points to the ActivityPub plugin. */ _x( 'For the Event Bridge for ActivityPub to work, you will need to install and activate the ActivityPub plugin.', @@ -69,7 +69,7 @@ class General_Admin_Notices { * @return string */ public static function get_admin_notice_activitypub_plugin_version_too_old(): string { - return sprintf( + return \sprintf( /* translators: 1: The name of the ActivityPub plugin. 2: The minimum required version number of the ActivityPub plugin. */ _x( 'Please upgrade your ActivityPub plugin. At least version %2$s is required for the Event Bridge for ActivityPub to work.', diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-health-check.php b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-health-check.php index ecf4652d..87ac98b2 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-health-check.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-health-check.php @@ -8,7 +8,7 @@ namespace Event_Bridge_For_ActivityPub\Admin; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Transformer\Factory as Transformer_Factory; use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration; @@ -90,10 +90,6 @@ class Health_Check { * @return bool True if the check passed. */ public static function test_if_event_transformer_is_used( $event_plugin ): bool { - if ( ! Setup::get_instance()->is_activitypub_plugin_active() ) { - return false; - } - // Get a (random) event post. $event_posts = self::get_most_recent_event_posts( $event_plugin->get_post_type(), 1 ); @@ -121,10 +117,6 @@ class Health_Check { * @return \WP_Post[] Array of event posts, or false if none are found. */ public static function get_most_recent_event_posts( $event_post_type = null, $number_of_posts = 5 ): array { - if ( ! Setup::get_instance()->is_activitypub_plugin_active() ) { - return array(); - } - if ( ! $event_post_type ) { $active_event_plugins = Setup::get_instance()->get_active_event_plugins(); $active_event_plugin = reset( $active_event_plugins ); @@ -141,6 +133,7 @@ class Health_Check { 'order' => 'DESC', 'include' => array(), 'exclude' => array(), + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( 'relation' => 'OR', array( diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-settings-page.php b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-settings-page.php index 0b58c39b..f7e352d7 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-settings-page.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-settings-page.php @@ -12,7 +12,7 @@ namespace Event_Bridge_For_ActivityPub\Admin; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Webfinger; use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source; @@ -69,7 +69,7 @@ class Settings_Page { * @return void */ public static function maybe_add_event_source() { - if ( ! isset( $_POST['event_bridge_for_activitypub_add_event_source'] ) ) { + if ( ! \array_key_exists( '_wpnonce', $_REQUEST ) ) { return; } @@ -78,11 +78,15 @@ class Settings_Page { return; } + if ( ! isset( $_POST['event_bridge_for_activitypub_add_event_source'] ) ) { + return; + } + if ( ! \current_user_can( 'manage_options' ) ) { return; } - $event_source = \sanitize_text_field( $_POST['event_bridge_for_activitypub_add_event_source'] ); + $event_source = \sanitize_text_field( \wp_unslash( $_POST['event_bridge_for_activitypub_add_event_source'] ) ); $actor_url = false; $url = \wp_parse_url( $event_source ); @@ -203,13 +207,13 @@ class Settings_Page { private static function get_event_terms( $event_plugin ): array { $taxonomy = $event_plugin::get_event_category_taxonomy(); if ( $taxonomy ) { - $event_terms = get_terms( + $event_terms = \get_terms( array( 'taxonomy' => $taxonomy, 'hide_empty' => true, ) ); - return ! is_wp_error( $event_terms ) ? $event_terms : array(); + return ! \is_wp_error( $event_terms ) ? $event_terms : array(); } else { return array(); } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-user-interface.php b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-user-interface.php index 9d673a2e..cb0a6210 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-user-interface.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/admin/class-user-interface.php @@ -9,10 +9,11 @@ namespace Event_Bridge_For_ActivityPub\Admin; -// Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +use WP_Post; + +// Exit if accessed directly. +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore -use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source; use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Sources_Collection; use Event_Bridge_For_ActivityPub\Event_Sources; @@ -39,7 +40,7 @@ class User_Interface { * @param array $columns The current columns. * @return array */ - public static function add_origin_column( $columns ) { + public static function add_origin_column( array $columns ) { // Add a new column after the title column. $columns['activitypub_origin'] = __( 'ActivityPub origin', 'event-bridge-for-activitypub' ); return $columns; @@ -48,12 +49,12 @@ class User_Interface { /** * Add a "⁂ Preview" link to the row actions. * - * @param array $actions The existing actions. - * @param \WP_Post $post The post object. + * @param array $actions The existing actions. + * @param WP_Post $post The post object. * * @return array The modified actions. */ - public static function row_actions( $actions, $post ): array { + public static function row_actions( array $actions, WP_Post $post ): array { // check if the post is enabled for ActivityPub. if ( ! Event_Sources::is_cached_external_post( $post ) ) { return $actions; @@ -67,7 +68,7 @@ class User_Interface { $url = \get_post_meta( $parent->ID, '_activitypub_actor_id', true ); } - $actions['view_origin'] = sprintf( + $actions['view_origin'] = \sprintf( '⁂ %s', \esc_url( $url ), \esc_html__( 'Open original page', 'event-bridge-for-activitypub' ) @@ -79,14 +80,14 @@ class User_Interface { /** * Modify the user capabilities so that nobody can edit external events. * - * @param array $caps Concerned user's capabilities. - * @param mixed $cap Required primitive capabilities for the requested capability. - * @param array $user_id The WordPress user ID. - * @param array $args Additional args. + * @param string[] $caps Concerned user's capabilities. + * @param string $cap Required primitive capabilities for the requested capability. + * @param int $user_id The WordPress user ID. + * @param array $args Additional args. * * @return array */ - public static function disable_editing_for_external_events( $caps, $cap, $user_id, $args ) { + public static function disable_editing_for_external_events( array $caps, string $cap, int $user_id, array $args ) { if ( 'edit_post' === $cap && isset( $args[0] ) ) { $post_id = $args[0]; $post = get_post( $post_id ); diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-autoloader.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-autoloader.php index 40f99cdf..27f7de61 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-autoloader.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-autoloader.php @@ -14,7 +14,7 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Class Autoloader. @@ -37,7 +37,7 @@ class Autoloader { $base_dir = EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/includes/'; $base = 'Event_Bridge_For_ActivityPub\\'; - if ( strncmp( $full_class, $base, strlen( $base ) ) === 0 ) { + if ( strncmp( $full_class, $base, \strlen( $base ) ) === 0 ) { $maybe_uppercase = str_replace( $base, '', $full_class ); $class = strtolower( $maybe_uppercase ); // All classes should be capitalized. If this is instead looking for a lowercase method, we ignore that. @@ -58,7 +58,7 @@ class Autoloader { if ( file_exists( $file ) && is_readable( $file ) ) { require_once $file; } else { - \wp_die( sprintf( esc_html( 'Required class not found or not readable: %s' ), esc_html( $full_class ) ) ); + \wp_die( \sprintf( esc_html( 'Required class not found or not readable: %s' ), esc_html( $full_class ) ) ); } } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-debug.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-debug.php index 5e28ec53..54911537 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-debug.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-debug.php @@ -10,7 +10,7 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Debug Class. @@ -24,7 +24,7 @@ class Debug { * Initialize the class, registering WordPress hooks. */ public static function init() { - if ( defined( 'WP_DEBUG_LOG' ) && constant( 'WP_DEBUG_LOG' ) ) { + if ( \defined( 'WP_DEBUG_LOG' ) && constant( 'WP_DEBUG_LOG' ) && ! getenv( 'WP_TESTS_DIR' ) ) { \add_action( 'event_bridge_for_activitypub_write_log', array( self::class, 'write_log' ), 10, 1 ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-event-sources.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-event-sources.php index e9463092..1b822b97 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-event-sources.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-event-sources.php @@ -10,7 +10,7 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Model\Blog; use DateTime; @@ -34,7 +34,7 @@ class Event_Sources { /** * Init. */ - public static function init() { + public static function init(): void { // Register the Event Sources Collection which takes care of managing the event sources. \add_action( 'init', array( Event_Sources_Collection::class, 'init' ) ); @@ -87,7 +87,7 @@ class Event_Sources { * * @return void */ - public static function register_post_meta() { + public static function register_post_meta(): void { $setup = Setup::get_instance(); foreach ( $setup->get_active_event_plugins() as $event_plugin_integration ) { @@ -116,7 +116,7 @@ class Event_Sources { * @param string $post_type The post type to register the meta for. * @return void */ - private static function register_post_meta_event_bridge_for_activitypub_event_source( $post_type ) { + private static function register_post_meta_event_bridge_for_activitypub_event_source( string $post_type ): void { \register_post_meta( $post_type, '_event_bridge_for_activitypub_event_source', @@ -132,9 +132,9 @@ class Event_Sources { * Get the Application actor via FEP-2677. * * @param string $domain The domain without scheme. - * @return bool|string The URL/ID of the application actor, false if not found. + * @return string|false The URL/ID of the application actor, false if not found. */ - public static function get_application_actor( $domain ) { + public static function get_application_actor( string $domain ): string|false { $result = wp_remote_get( 'https://' . $domain . '/.well-known/nodeinfo' ); if ( is_wp_error( $result ) ) { @@ -146,11 +146,11 @@ class Event_Sources { $nodeinfo = json_decode( $body, true ); // Check if 'links' exists and is an array. - if ( isset( $nodeinfo['links'] ) && is_array( $nodeinfo['links'] ) ) { + if ( isset( $nodeinfo['links'] ) && \is_array( $nodeinfo['links'] ) ) { foreach ( $nodeinfo['links'] as $link ) { // Check if this link matches the application actor rel. if ( isset( $link['rel'] ) && 'https://www.w3.org/ns/activitystreams#Application' === $link['rel'] ) { - if ( is_string( $link['href'] ) ) { + if ( \is_string( $link['href'] ) ) { return $link['href']; } break; @@ -172,7 +172,7 @@ class Event_Sources { * @param WP_Post $post The WordPress post object. * @return bool False if the post is not disabled for federation via ActivityPub. */ - public static function is_post_disabled_for_activitypub( $disabled, $post = null ): bool { + public static function is_post_disabled_for_activitypub( bool $disabled, WP_Post $post ): bool { if ( $disabled ) { return $disabled; } @@ -185,7 +185,7 @@ class Event_Sources { * @param WP_Post|int $post The WordPress post object or post ID. * @return bool */ - public static function is_cached_external_post( $post ): bool { + public static function is_cached_external_post( WP_Post|int $post ): bool { $post_id = $post instanceof WP_Post ? $post->ID : $post; if ( \get_post_meta( $post_id, '_event_bridge_for_activitypub_event_source', true ) ) { @@ -196,13 +196,13 @@ class Event_Sources { } /** - * Add the ActivityPub template for EventPrime. + * Maybe redirect cached external events to origin. * * @param string $template The path to the template object. * @return string The new path to the JSON template. */ - public static function redirect_activitypub_requests_for_cached_external_events( $template ) { - if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { + public static function redirect_activitypub_requests_for_cached_external_events( string $template ) { + if ( \defined( 'REST_REQUEST' ) && REST_REQUEST ) { return $template; } @@ -259,7 +259,7 @@ class Event_Sources { * * @return array The array of following urls. */ - public static function add_event_sources_to_follow_collection( $follow_list, $user ): array { + public static function add_event_sources_to_follow_collection( array $follow_list, mixed $user ): array { if ( ! $user instanceof Blog ) { return $follow_list; } @@ -274,7 +274,7 @@ class Event_Sources { * * @return array A list with all unique hosts of all Event Sources' ActivityPub IDs. */ - public static function get_event_sources_hosts() { + public static function get_event_sources_hosts(): array { $hosts = get_transient( 'event_bridge_for_activitypub_event_sources_hosts' ); if ( $hosts ) { @@ -304,7 +304,7 @@ class Event_Sources { * @param array $hosts The hosts before the filter. * @return array */ - public static function add_event_sources_hosts_to_allowed_redirect_hosts( $hosts ) { + public static function add_event_sources_hosts_to_allowed_redirect_hosts( array $hosts ): array { $event_sources_hosts = self::get_event_sources_hosts(); return array_merge( $hosts, $event_sources_hosts ); } @@ -313,18 +313,18 @@ class Event_Sources { * Mark incoming accept activities as valid. * * @param bool $valid The validation state. - * @param string $param The object parameter. + * @param mixed $param The object parameter. * @param WP_REST_Request $request The request object. * * @return bool|WP_Error The validation state: true if valid, false if not. */ - public static function validate_activity( $valid, $param, $request ) { + public static function validate_activity( bool $valid, mixed $param, WP_REST_Request $request ) { if ( $valid ) { return $valid; } $json_params = $request->get_json_params(); - if ( isset( $json_params['object']['type'] ) && in_array( $json_params['object']['type'], array( 'Accept', 'Undo' ), true ) ) { + if ( isset( $json_params['object']['type'] ) && \in_array( $json_params['object']['type'], array( 'Accept', 'Undo' ), true ) ) { return true; } @@ -335,12 +335,12 @@ class Event_Sources { * Validate the event object. * * @param bool $valid The validation state. - * @param string $param The object parameter. + * @param mixed $param The object parameter. * @param WP_REST_Request $request The request object. * * @return bool|WP_Error The validation state: true if valid, false if not. */ - public static function validate_event_object( $valid, $param, $request ) { + public static function validate_event_object( bool $valid, mixed $param, WP_REST_Request $request ): bool|WP_Error { $json_params = $request->get_json_params(); // Check if we should continue with the validation. @@ -379,7 +379,7 @@ class Event_Sources { * @param string ...$urls List of URLs to compare. * @return bool True if all URLs have the same host, false otherwise. */ - public static function same_host( ...$urls ) { + public static function same_host( string ...$urls ): bool { if ( empty( $urls ) ) { return false; // No URLs given, can't compare hosts. } @@ -412,8 +412,8 @@ class Event_Sources { * @param mixed $event_object The (event) object as an associative array. * @return bool True if the object is an valid ActivityPub Event, false if not. */ - public static function is_valid_activitypub_event_object( $event_object ): bool { - if ( ! is_array( $event_object ) ) { + public static function is_valid_activitypub_event_object( mixed $event_object ): bool { + if ( ! \is_array( $event_object ) ) { return false; } @@ -446,7 +446,7 @@ class Event_Sources { * @param string $id The ID to validate. * @return bool */ - public static function is_valid_activitypub_id( $id ) { + public static function is_valid_activitypub_id( string $id ): bool { return \sanitize_url( $id ) ? true : false; } @@ -469,7 +469,7 @@ class Event_Sources { * @param string|DateTime $time The ActivityPub like time string or DateTime object. * @return bool */ - public static function is_time_passed( $time ) { + public static function is_time_passed( string|DateTime $time ): bool { if ( ! $time instanceof DateTime ) { // Create a DateTime object from the ActivityPub time string. $time = new DateTime( $time, new DateTimeZone( 'UTC' ) ); @@ -488,7 +488,7 @@ class Event_Sources { * @param array $event_object The ActivityPub Event as an associative array. * @return bool */ - public static function is_ongoing_or_future_event( $event_object ) { + public static function is_ongoing_or_future_event( array $event_object ): bool { if ( isset( $event_object['endTime'] ) ) { $time = $event_object['endTime']; } else { @@ -504,9 +504,9 @@ class Event_Sources { * @param string $actor_id The actor ID. * @return bool True if the ActivityPub actor ID is followed, false otherwise. */ - public static function actor_is_event_source( $actor_id ) { + public static function actor_is_event_source( string $actor_id ): bool { $event_sources = Event_Sources_Collection::get_event_sources(); - if ( in_array( $actor_id, $event_sources, true ) ) { + if ( \in_array( $actor_id, $event_sources, true ) ) { return true; } return false; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-outbox-parser.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-outbox-parser.php index f970383e..4557e967 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-outbox-parser.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-outbox-parser.php @@ -13,7 +13,7 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Http; use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source; @@ -31,7 +31,7 @@ class Outbox_Parser { /** * Maximum number of events to backfill per actor. */ - const MAX_EVENTS_TO_IMPORT = 20; + public const MAX_EVENTS_TO_IMPORT = 20; /** * Init actions. @@ -48,7 +48,7 @@ class Outbox_Parser { * @param int $event_source_post_id The Post ID of Event Source we want to backfill the events for. * @return void */ - public static function backfill_events( $event_source_post_id ): void { + public static function backfill_events( int $event_source_post_id ): void { $event_source = Event_Source::get_by_id( $event_source_post_id ); if ( ! $event_source ) { @@ -72,12 +72,7 @@ class Outbox_Parser { * @param int $event_source_post_id The Post ID of the Event Source that owns the outbox. * @return void */ - public static function import_events_from_outbox( $url, $event_source_post_id ) { - $setup = Setup::get_instance(); - if ( ! $setup->is_activitypub_plugin_active() ) { - return; - } - + public static function import_events_from_outbox( string $url, int $event_source_post_id ): void { $outbox = self::fetch_outbox( $url ); if ( ! $outbox ) { @@ -91,7 +86,7 @@ class Outbox_Parser { } // Process orderedItems if they exist (non-paginated outbox). - if ( isset( $outbox['orderedItems'] ) && is_array( $outbox['orderedItems'] ) ) { + if ( isset( $outbox['orderedItems'] ) && \is_array( $outbox['orderedItems'] ) ) { $current_count += self::import_events_from_items( $outbox['orderedItems'], $event_source_post_id, @@ -120,11 +115,11 @@ class Outbox_Parser { * @param array $activity The Activity as associative array. * @return bool */ - private static function is_create_or_update_activity( $activity ) { + private static function is_create_or_update_activity( array $activity ): bool { if ( ! isset( $activity['type'] ) ) { return false; } - if ( in_array( $activity['type'], array( 'Update', 'Create' ), true ) ) { + if ( \in_array( $activity['type'], array( 'Update', 'Create' ), true ) ) { return true; } return false; @@ -137,12 +132,12 @@ class Outbox_Parser { * @param int $max_items The maximum number of items to parse. * @return array Parsed events from the collection. */ - private static function parse_outbox_items_for_events( $items, $max_items ) { + private static function parse_outbox_items_for_events( array $items, int $max_items ): array { $parsed_events = array(); foreach ( $items as $activity ) { // Abort if we have exceeded the maximal events to return. - if ( $max_items > 0 && count( $parsed_events ) >= $max_items ) { + if ( $max_items > 0 && \count( $parsed_events ) >= $max_items ) { break; } @@ -179,7 +174,7 @@ class Outbox_Parser { * @param int $limit The limit of how many events to save locally. * @return int The number of saved events (at least attempted). */ - private static function import_events_from_items( $items, $event_source_post_id, $limit = -1 ): int { + private static function import_events_from_items( array $items, int $event_source_post_id, int $limit = -1 ): int { $events = self::parse_outbox_items_for_events( $items, $limit ); $transmogrifier = Setup::get_transmogrifier(); @@ -209,7 +204,7 @@ class Outbox_Parser { * @param int $delay The delay of the current time in seconds. * @return bool */ - private static function queue_importing_from_outbox( $url, $event_source_post_id, $delay = 10 ): bool { + private static function queue_importing_from_outbox( string $url, int $event_source_post_id, int $delay = 10 ): bool { $hook = 'event_bridge_for_activitypub_import_events_from_outbox'; $args = array( $url, $event_source_post_id ); @@ -237,7 +232,7 @@ class Outbox_Parser { * @param int $count The new count of imported events. * @return void */ - private static function update_import_count( $event_source_post_id, $count ) { + private static function update_import_count( int $event_source_post_id, int $count ): void { \update_post_meta( $event_source_post_id, '_event_bridge_for_activitypub_event_count', $count ); } @@ -247,7 +242,7 @@ class Outbox_Parser { * @param string $url The URL of the outbox. * @return array|null The decoded outbox data, or null if fetching fails. */ - private static function fetch_outbox( $url ) { + private static function fetch_outbox( string $url ): ?array { $response = Http::get( $url ); if ( \is_wp_error( $response ) ) { @@ -266,9 +261,9 @@ class Outbox_Parser { * @param array $outbox The outbox data. * @return string|null The pagination URL, or null if not found. */ - private static function get_pagination_url( $outbox ) { + private static function get_pagination_url( array $outbox ): ?string { // If we are on a collection page simply use the next key. - if ( 'OrderedCollectionPage' === $outbox['type'] && ! empty( $outbox['next'] ) && is_string( $outbox['next'] ) ) { + if ( 'OrderedCollectionPage' === $outbox['type'] && ! empty( $outbox['next'] ) && \is_string( $outbox['next'] ) ) { return $outbox['next']; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-preview.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-preview.php index 637947bf..dc347120 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-preview.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-preview.php @@ -10,7 +10,7 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Class for initializing the custom ActivityPub preview(s). @@ -31,7 +31,7 @@ class Preview { public static function maybe_apply_event_preview_template() { $event_post_types = Setup::get_instance()->get_active_event_plugins_post_types(); - if ( in_array( \get_post_type(), $event_post_types, true ) ) { + if ( \in_array( \get_post_type(), $event_post_types, true ) ) { return EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/templates/event-preview.php'; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-reminder.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-reminder.php index 67153ebe..9ef5db78 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-reminder.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-reminder.php @@ -12,7 +12,7 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Transformer\Factory as Transformer_Factory; use Event_Bridge_For_ActivityPub\Setup; @@ -21,7 +21,7 @@ use DateTime; use WP_Post; use function ActivityPub\add_to_outbox; -use function Activitypub\is_user_disabled; +use function Activitypub\user_can_activitypub; /** * Adds automatic announcing or sending of reminders before the events start time. @@ -71,7 +71,7 @@ class Reminder { // Check for our supported post types. $current_screen = \get_current_screen(); $event_post_types = Setup::get_instance()->get_active_event_plugins_post_types(); - if ( ! $current_screen || ! in_array( $current_screen->post_type, $event_post_types, true ) ) { + if ( ! $current_screen || ! \in_array( $current_screen->post_type, $event_post_types, true ) ) { return; } $asset_data = include EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'build/reminder/plugin.asset.php'; @@ -91,11 +91,11 @@ class Reminder { /** * Schedule Activities. * - * @param string $new_status New post status. - * @param string $old_status Old post status. - * @param ?WP_Post $post Post object. + * @param string $new_status New post status. + * @param string $old_status Old post status. + * @param WP_Post|null $post Post object. */ - public static function maybe_schedule_event_reminder( $new_status, $old_status, $post ): void { + public static function maybe_schedule_event_reminder( string $new_status, string $old_status, WP_Post|null $post ): void { if ( ! $post instanceof WP_Post ) { return; } @@ -170,7 +170,7 @@ class Reminder { * * @param int $post_id The WordPress post ID of the event post. */ - public static function send_event_reminder( $post_id ) { + public static function send_event_reminder( int $post_id ): void { $post = \get_post( $post_id ); $transformer = Transformer_Factory::get_transformer( $post ); @@ -182,7 +182,7 @@ class Reminder { $actor = $transformer->get_actor_object(); $user_id = $actor->get__id(); - if ( $user_id > 0 && is_user_disabled( $user_id ) ) { + if ( $user_id > 0 && ! user_can_activitypub( $user_id ) ) { return; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-settings.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-settings.php index e4dca80d..f60af6b8 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-settings.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-settings.php @@ -14,7 +14,7 @@ namespace Event_Bridge_For_ActivityPub; use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\Integrations\Feature_Event_Sources; @@ -26,14 +26,14 @@ use Event_Bridge_For_ActivityPub\Integrations\Feature_Event_Sources; * @since 1.0.0 */ class Settings { - const SETTINGS_SLUG = 'event-bridge-for-activitypub'; + public const SETTINGS_SLUG = 'event-bridge-for-activitypub'; /** * The default ActivityPub event category. * * @var string */ - const DEFAULT_EVENT_CATEGORY = 'MEETING'; + private const DEFAULT_EVENT_CATEGORY = 'MEETING'; /** * Register the settings for the Event Bridge for ActivityPub plugin. @@ -168,10 +168,11 @@ class Settings { /** * Do not allow the event sources feature to get deactivated, when event sources are still followed. * - * @param mixed $value The optios value. + * @param mixed $value The options value. + * @return bool */ - public static function sanitize_event_sources_feature_active( $value ) { - $count = count( Event_Sources::get_event_sources() ); + public static function sanitize_event_sources_feature_active( mixed $value ): bool { + $count = \count( Event_Sources::get_event_sources() ); $value = (bool) $value; @@ -198,7 +199,7 @@ class Settings { * @return string */ public static function sanitize_event_plugin_integration_used_for_event_sources( $event_plugin_integration ): string { - if ( ! is_string( $event_plugin_integration ) ) { + if ( ! \is_string( $event_plugin_integration ) ) { return ''; } $setup = Setup::get_instance(); @@ -207,10 +208,10 @@ class Settings { $valid_options = array(); foreach ( $active_event_plugins as $active_event_plugin ) { if ( $active_event_plugin instanceof Feature_Event_Sources ) { - $valid_options[] = get_class( $active_event_plugin ); + $valid_options[] = \get_class( $active_event_plugin ); } } - if ( in_array( $event_plugin_integration, $valid_options, true ) ) { + if ( \in_array( $event_plugin_integration, $valid_options, true ) ) { return $event_plugin_integration; } return Setup::get_default_integration_class_name_used_for_event_sources_feature(); @@ -220,8 +221,9 @@ class Settings { * Sanitize the target ActivityPub Event category. * * @param string $event_category The ActivityPUb event category. + * @return string */ - public static function sanitize_mapped_event_category( $event_category ): string { + public static function sanitize_mapped_event_category( string $event_category ): string { return self::is_allowed_event_category( $event_category ) ? $event_category : self::DEFAULT_EVENT_CATEGORY; } @@ -231,10 +233,9 @@ class Settings { * Currently only the default event categories are allowed to be target of a mapping. * * @param array $event_category_mappings The settings value. - * * @return array An array that contains only valid mapping pairs. */ - public static function sanitize_event_category_mappings( $event_category_mappings ): array { + public static function sanitize_event_category_mappings( array $event_category_mappings ): array { if ( empty( $event_category_mappings ) ) { return array(); } @@ -253,9 +254,9 @@ class Settings { * * @return bool True if allowed, false otherwise. */ - private static function is_allowed_event_category( $event_category ): bool { + private static function is_allowed_event_category( string $event_category ): bool { require_once EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . '/includes/event-categories.php'; $allowed_event_categories = array_keys( EVENT_BRIDGE_FOR_ACTIVITYPUB_EVENT_CATEGORIES ); - return in_array( $event_category, $allowed_event_categories, true ); + return \in_array( $event_category, $allowed_event_categories, true ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/class-setup.php b/wp-content/plugins/event-bridge-for-activitypub/includes/class-setup.php index 8f9ffe02..fad91e8e 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/class-setup.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/class-setup.php @@ -13,10 +13,9 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Sources_Collection; -use Event_Bridge_For_ActivityPub\ActivityPub\Handler\Join as Join_Handler; use Event_Bridge_For_ActivityPub\ActivityPub\Scheduler\Event as Event_Scheduler; use Event_Bridge_For_ActivityPub\Admin\Event_Plugin_Admin_Notices; use Event_Bridge_For_ActivityPub\Admin\General_Admin_Notices; @@ -25,10 +24,14 @@ use Event_Bridge_For_ActivityPub\Admin\Settings_Page; use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration; use Event_Bridge_For_ActivityPub\Integrations\Feature_Event_Sources; use Event_Bridge_For_ActivityPub\Reminder; +use WP_Comment; +use WP_Post; +use WP_Post_Type; +use WP_User; +use WP_Term; use function Activitypub\is_user_type_disabled; -// @phpstan-ignore-next-line require_once ABSPATH . 'wp-admin/includes/plugin.php'; /** @@ -39,13 +42,6 @@ require_once ABSPATH . 'wp-admin/includes/plugin.php'; * @since 1.0.0 */ class Setup { - /** - * Keep the information whether the ActivityPub plugin is active. - * - * @var boolean - */ - protected $activitypub_plugin_is_active = false; - /** * Keep the current version of the current ActivityPub plugin. * @@ -68,9 +64,8 @@ class Setup { * @since 1.0.0 */ protected function __construct() { - // Detect the presence/active-status and version of the ActivityPub plugin. - $this->activitypub_plugin_is_active = defined( 'ACTIVITYPUB_PLUGIN_VERSION' ) || \is_plugin_active( 'activitypub/activitypub.php' ); - $this->activitypub_plugin_version = self::get_activitypub_plugin_version(); + // Detect the version of the ActivityPub plugin. + $this->activitypub_plugin_version = self::get_activitypub_plugin_version(); // Register main action that load the Event Bridge For ActivityPub. \add_action( 'plugins_loaded', array( $this, 'setup_hooks' ) ); @@ -101,22 +96,13 @@ class Setup { return self::$instance; } - /** - * Getter function for whether the ActivityPub plugin is active. - * - * @return bool True when the ActivityPub plugin is active. - */ - public function is_activitypub_plugin_active(): bool { - return $this->activitypub_plugin_is_active; - } - /** * Get the current version of the ActivityPub plugin. * * @return string The semantic Version. */ private static function get_activitypub_plugin_version(): string { - if ( defined( 'ACTIVITYPUB_PLUGIN_VERSION' ) ) { + if ( \defined( 'ACTIVITYPUB_PLUGIN_VERSION' ) ) { return constant( 'ACTIVITYPUB_PLUGIN_VERSION' ); } return '0.0.0'; @@ -178,6 +164,7 @@ class Setup { \Event_Bridge_For_ActivityPub\Integrations\Event_Organiser::class, \Event_Bridge_For_ActivityPub\Integrations\EventPrime::class, \Event_Bridge_For_ActivityPub\Integrations\EventOn::class, + \Event_Bridge_For_ActivityPub\Integrations\Spiffy_Calendar::class, ); /** @@ -186,9 +173,6 @@ class Setup { * @return void */ public function redetect_active_event_plugins(): void { - if ( ! $this->activitypub_plugin_is_active ) { - return; - } \delete_transient( 'event_bridge_for_activitypub_active_event_plugins' ); $this->detect_active_event_plugins(); @@ -200,11 +184,6 @@ class Setup { * @return array List of supported event plugins as keys from the SUPPORTED_EVENT_PLUGINS const. */ public function detect_active_event_plugins(): array { - // Detection will fail in case the ActivityPub plugin is not active. - if ( ! $this->activitypub_plugin_is_active ) { - return array(); - } - $active_event_plugins = \get_transient( 'event_bridge_for_activitypub_active_event_plugins' ); if ( $active_event_plugins ) { @@ -213,7 +192,6 @@ class Setup { } if ( ! function_exists( 'get_plugins' ) ) { - // @phpstan-ignore-next-line require_once ABSPATH . 'wp-admin/includes/plugin.php'; } @@ -289,7 +267,7 @@ class Setup { ); // 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 ) { + if ( empty( $this->active_event_plugins ) ) { self::shut_down(); return; } @@ -312,9 +290,6 @@ class Setup { // Register the event reminders. \add_action( 'init', array( Reminder::class, 'init' ) ); - // Initialize the handling of "Join" activities. - Join_Handler::init(); - // If the Event-Sources feature is enabled and all requirements are met, initialize it. if ( ! is_user_type_disabled( 'blog' ) && \get_option( 'event_bridge_for_activitypub_event_sources_active' ) ) { Event_Sources::init(); @@ -340,7 +315,7 @@ class Setup { * @return void */ private function register_plugin_specific_hooks(): void { - if ( array_key_exists( \Event_Bridge_For_ActivityPub\Integrations\EventPrime::get_relative_plugin_file(), $this->active_event_plugins ) ) { + if ( \array_key_exists( \Event_Bridge_For_ActivityPub\Integrations\EventPrime::get_relative_plugin_file(), $this->active_event_plugins ) ) { \Event_Bridge_For_ActivityPub\Integrations\EventPrime::init(); } } @@ -403,12 +378,6 @@ class Setup { foreach ( $this->active_event_plugins as $event_plugin ) { new Event_Plugin_Admin_Notices( $event_plugin ); } - // Check if any general admin notices are needed and add actions to insert the needed admin notices. - if ( ! $this->activitypub_plugin_is_active ) { - // The ActivityPub plugin is not active. - \add_action( 'admin_notices', array( General_Admin_Notices::class, 'activitypub_plugin_not_enabled' ), 10, 0 ); - return; - } if ( ! version_compare( $this->activitypub_plugin_version, EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION, '>=' ) ) { // The ActivityPub plugin is too old. \add_action( 'admin_notices', array( General_Admin_Notices::class, 'activitypub_plugin_version_too_old' ), 10, 0 ); @@ -429,7 +398,7 @@ class Setup { * * @return \Activitypub\Transformer\Base|null|\WP_Error */ - public function register_activitypub_transformer( $transformer, $data, $object_class ) { + public function register_activitypub_transformer( $transformer, mixed $data, string $object_class ) { // If the current WordPress object is not a post (e.g., a WP_Comment), don't change the transformer. if ( 'WP_Post' === $object_class ) { // Get the transformer for a specific event plugins event or location post type. @@ -506,7 +475,7 @@ class Setup { // If someone installs this plugin, we simply enable ActivityPub support for all currently active event post types. $activitypub_supported_post_types = get_option( 'activitypub_support_post_types', array() ); foreach ( $this->active_event_plugins as $event_plugin ) { - if ( ! in_array( $event_plugin->get_post_type(), $activitypub_supported_post_types, true ) ) { + if ( ! \in_array( $event_plugin->get_post_type(), $activitypub_supported_post_types, true ) ) { $activitypub_supported_post_types[] = $event_plugin->get_post_type(); add_post_type_support( $event_plugin->get_post_type(), 'activitypub' ); } @@ -525,17 +494,6 @@ class Setup { */ public function activate(): void { $this->redetect_active_event_plugins(); - // Don't allow plugin activation, when the ActivityPub plugin is not activated yet. - if ( ! $this->activitypub_plugin_is_active ) { - \deactivate_plugins( plugin_basename( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE ) ); - $notice = General_Admin_Notices::get_admin_notice_activitypub_plugin_not_enabled(); - \wp_die( - // @phpstan-ignore-next-line - wp_kses( $notice, General_Admin_Notices::ALLOWED_HTML ), - 'Plugin dependency check', - array( 'back_link' => true ), - ); - } if ( empty( $this->active_event_plugins ) ) { \deactivate_plugins( plugin_basename( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_FILE ) ); @@ -552,7 +510,7 @@ class Setup { } /** - * Maybe (depending on active event plugins) make it possible to querly event terms by `?term_id=`. + * Maybe (depending on active event plugins) make it possible to query event terms by `?term_id=`. * * @return void */ @@ -579,7 +537,7 @@ class Setup { * * @return array The query variables. */ - public static function add_term_query_var( $vars ) { + public static function add_term_query_var( array $vars ): array { $vars[] = 'term_id'; return $vars; @@ -588,9 +546,9 @@ class Setup { /** * Filters the queried object. * - * @param \WP_Term|\WP_Post_Type|\WP_Post|\WP_User|\WP_Comment|null $queried_object The queried object. + * @param WP_Term|WP_Post_Type|WP_Post|WP_User|WP_Comment|null $queried_object The queried object. */ - public function maybe_detect_event_plugins_location_term( $queried_object ) { + public function maybe_detect_event_plugins_location_term( mixed $queried_object ) { if ( $queried_object ) { return $queried_object; } @@ -601,7 +559,7 @@ class Setup { $queried_object = \get_term( $term_id ); } - if ( $queried_object instanceof \WP_Term && $this->is_place_taxonomy_of_active_event_plugin( $queried_object->taxonomy ) ) { + if ( $queried_object instanceof WP_Term && $this->is_place_taxonomy_of_active_event_plugin( $queried_object->taxonomy ) ) { return $queried_object; } @@ -614,7 +572,7 @@ class Setup { * @param string $taxonomy The taxonomy. * @return boolean */ - private function is_place_taxonomy_of_active_event_plugin( $taxonomy ): bool { + private function is_place_taxonomy_of_active_event_plugin( string $taxonomy ): bool { foreach ( $this->active_event_plugins as $event_plugin ) { if ( $event_plugin::get_place_taxonomy() === $taxonomy ) { return true; @@ -684,7 +642,7 @@ class Setup { $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 get_class( $event_plugin_integration ); + return \get_class( $event_plugin_integration ); } } return ''; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/event-categories.php b/wp-content/plugins/event-bridge-for-activitypub/includes/event-categories.php index 71232e74..465b2d37 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/event-categories.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/event-categories.php @@ -10,7 +10,7 @@ namespace Event_Bridge_For_ActivityPub; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore define( 'EVENT_BRIDGE_FOR_ACTIVITYPUB_EVENT_CATEGORIES', diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-organiser.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-organiser.php index 7f1b0909..2c7aa9e6 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-organiser.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-organiser.php @@ -13,11 +13,13 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Query; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event_Organiser as Event_Organiser_Transformer; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\Event_Organiser as Event_Organiser_Place_Transformer; +use WP_Post; +use WP_Term; /** * Event Organiser. @@ -79,17 +81,21 @@ final class Event_Organiser extends Event_Plugin_Integration { * @param \WP_Post $post The WordPress post object of the Event. * @return Event_Organiser_Transformer */ - public static function get_activitypub_event_transformer( $post ): Event_Organiser_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): Event_Organiser_Transformer { return new Event_Organiser_Transformer( $post, self::get_event_category_taxonomy() ); } /** * Returns the ActivityPub transformer for a Event_Organiser event venue which is stored in a taxonomy. * - * @param \WP_Term $term The WordPress Term/Taxonomy of the venue. + * @param WP_Post|WP_Term $term The WordPress Term/Taxonomy of the venue. * @return Event_Organiser_Place_Transformer */ - public static function get_activitypub_place_transformer( $term ): Event_Organiser_Place_Transformer { + public static function get_activitypub_place_transformer( WP_Post|WP_Term $term ): ?Event_Organiser_Place_Transformer { + if ( $term instanceof WP_Post ) { + return null; + } + if ( Query::get_instance()->is_activitypub_request() && defined( 'EVENT_ORGANISER_DIR' ) ) { $class_path = constant( EVENT_ORGANISER_DIR ) . 'includes/class-eo-theme-compatability.php'; diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-plugin-integration.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-plugin-integration.php index 9f73a67c..5de7ada8 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-plugin-integration.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-event-plugin-integration.php @@ -12,12 +12,13 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Event as ActivityPub_Event_Transformer; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\Base_Post_Place; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\Base_Term_Place; use WP_Post; +use WP_Term; require_once EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'includes/integrations/interface-feature-event-sources.php'; @@ -56,7 +57,7 @@ abstract class Event_Plugin_Integration { * @param WP_Post $post The WordPress post object of the Event. * @return ActivityPub_Event_Transformer */ - abstract public static function get_activitypub_event_transformer( $post ): ActivityPub_Event_Transformer; + abstract public static function get_activitypub_event_transformer( WP_Post $post ): ActivityPub_Event_Transformer; /** * In case an event plugin uses a custom post type for the locations/venues return it here. @@ -79,10 +80,10 @@ abstract class Event_Plugin_Integration { /** * Returns the Activitypub transformer for places of the event plugins location post type. * - * @param WP_Post $post The WordPress post object of the Event. + * @param WP_Post|WP_Term $data The WordPress post object of the Event. * @return Base_Post_Place|Base_Term_Place|null */ - public static function get_activitypub_place_transformer( $post ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter + public static function get_activitypub_place_transformer( WP_Post|WP_Term $data ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter return null; } @@ -108,7 +109,7 @@ abstract class Event_Plugin_Integration { * Get the plugins name from the main plugin-file's top-level-file-comment. */ public static function get_plugin_name(): string { - $all_plugins = array_merge( get_plugins(), get_mu_plugins() ); + $all_plugins = array_merge( \get_plugins(), \get_mu_plugins() ); if ( isset( $all_plugins[ static::get_relative_plugin_file() ]['Name'] ) ) { return $all_plugins[ static::get_relative_plugin_file() ]['Name']; } else { @@ -121,11 +122,11 @@ abstract class Event_Plugin_Integration { */ public static function is_plugin_page(): bool { // Get the current page. - $screen = get_current_screen(); + $screen = \get_current_screen(); // 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 = in_array( $screen->id, static::get_settings_pages(), true ); + $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/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventin.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventin.php index 3624ec81..e5458721 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventin.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventin.php @@ -13,9 +13,10 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Eventin as Eventin_Transformer; +use WP_Post; /** * Eventin. @@ -65,10 +66,10 @@ final class Eventin extends Event_Plugin_Integration { /** * Returns the ActivityPub transformer for a Eventin event post. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post $post The WordPress post object of the Event. * @return Eventin_Transformer */ - public static function get_activitypub_event_transformer( $post ): Eventin_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): Eventin_Transformer { return new Eventin_Transformer( $post, self::get_event_category_taxonomy() ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventon.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventon.php index 5e105e2b..1652137e 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventon.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventon.php @@ -13,10 +13,12 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\EventOn as EventOn_Event_Transformer; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\EventOn as EventOn_Location_Transformer; +use WP_Post; +use WP_Term; /** * EventON – Events Calendar @@ -66,10 +68,10 @@ final class EventOn extends Event_Plugin_Integration { /** * Returns the ActivityPub transformer for a VS_Event_List event post. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post $post The WordPress post object of the Event. * @return EventOn_Event_Transformer */ - public static function get_activitypub_event_transformer( $post ): EventOn_Event_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): EventOn_Event_Transformer { return new EventOn_Event_Transformer( $post, self::get_event_category_taxonomy() ); } @@ -85,10 +87,10 @@ final class EventOn extends Event_Plugin_Integration { /** * Returns the ActivityPub transformer for a Event_Organiser event venue which is stored in a taxonomy. * - * @param \WP_Term $term The WordPress Term/Taxonomy of the venue. + * @param WP_Post|WP_Term $term The WordPress Term/Taxonomy of the venue. * @return EventOn_Location_Transformer */ - public static function get_activitypub_place_transformer( $term ): EventOn_Location_Transformer { - return new EventOn_Location_Transformer( $term ); + public static function get_activitypub_place_transformer( WP_Post|WP_Term $term ): ?EventOn_Location_Transformer { + return $term instanceof WP_Term ? new EventOn_Location_Transformer( $term ) : null; } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventprime.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventprime.php index 427ccdc7..94756ae7 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventprime.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-eventprime.php @@ -12,11 +12,12 @@ namespace Event_Bridge_For_ActivityPub\Integrations; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\EventPrime as EventPrime_Event_Transformer; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\EventPrime as EventPrime_Place_Transformer; use Eventprime_Basic_Functions; +use WP_Post; use function Activitypub\is_activitypub_request; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * This class defines which information is necessary for the EventPrime event plugin. @@ -72,10 +73,10 @@ final class EventPrime extends Event_Plugin_Integration { /** * Returns the ActivityPub transformer. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post $post The WordPress post object of the Event. * @return EventPrime_Event_Transformer */ - public static function get_activitypub_event_transformer( $post ): EventPrime_Event_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): EventPrime_Event_Transformer { return new EventPrime_Event_Transformer( $post, self::get_event_category_taxonomy() ); } @@ -150,7 +151,7 @@ final class EventPrime extends Event_Plugin_Integration { * @return bool|int The post ID, or term ID if found, false otherwise. */ private static function get_object_id( $type = 'event' ) { - if ( ! in_array( $type, array( 'venue', 'event' ), true ) ) { + if ( ! \in_array( $type, array( 'venue', 'event' ), true ) ) { return false; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-events-manager.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-events-manager.php index 98bb0a76..c7f0c22c 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-events-manager.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-events-manager.php @@ -13,11 +13,12 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Events_Manager as Events_Manager_Event_Transformer; use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Place\Events_Manager as Events_Manager_Place_Transformer; - +use WP_Post; +use WP_Term; /** * Events Manager. @@ -43,7 +44,7 @@ final class Events_Manager extends Event_Plugin_Integration { * @return string */ public static function get_post_type(): string { - return defined( 'EM_POST_TYPE_EVENT' ) ? constant( 'EM_POST_TYPE_EVENT' ) : 'event'; + return \defined( 'EM_POST_TYPE_EVENT' ) ? constant( 'EM_POST_TYPE_EVENT' ) : 'event'; } /** @@ -52,17 +53,17 @@ final class Events_Manager extends Event_Plugin_Integration { * @return string */ public static function get_place_post_type(): string { - return defined( 'EM_POST_TYPE_LOCATION' ) ? constant( 'EM_POST_TYPE_LOCATION' ) : 'location'; + return \defined( 'EM_POST_TYPE_LOCATION' ) ? constant( 'EM_POST_TYPE_LOCATION' ) : 'location'; } /** * Returns the Activitypub transformer for places of the event plugins location post type. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post|WP_Term $post The WordPress post object of the Event. * @return Events_Manager_Place_Transformer */ - public static function get_activitypub_place_transformer( $post ): Events_Manager_Place_Transformer { - return new Events_Manager_Place_Transformer( $post ); + public static function get_activitypub_place_transformer( WP_Post|WP_Term $post ): ?Events_Manager_Place_Transformer { + return $post instanceof WP_Post ? new Events_Manager_Place_Transformer( $post ) : null; } /** @@ -80,16 +81,16 @@ final class Events_Manager extends Event_Plugin_Integration { * @return string */ public static function get_event_category_taxonomy(): string { - return defined( 'EM_TAXONOMY_CATEGORY' ) ? constant( 'EM_TAXONOMY_CATEGORY' ) : 'event-categories'; + return \defined( 'EM_TAXONOMY_CATEGORY' ) ? constant( 'EM_TAXONOMY_CATEGORY' ) : 'event-categories'; } /** * Returns the ActivityPub transformer for a Events_Manager event post. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post $post The WordPress post object of the Event. * @return Events_Manager_Event_Transformer */ - public static function get_activitypub_event_transformer( $post ): Events_Manager_Event_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): Events_Manager_Event_Transformer { return new Events_Manager_Event_Transformer( $post, self::get_event_category_taxonomy() ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-gatherpress.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-gatherpress.php index 807fe19a..0485fbc3 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-gatherpress.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-gatherpress.php @@ -13,10 +13,11 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\GatherPress as GatherPress_Transformer; use Event_Bridge_For_ActivityPub\ActivityPub\Transmogrifier\GatherPress as GatherPress_Transmogrifier; +use WP_Post; /** * GatherPress. @@ -66,10 +67,10 @@ final class GatherPress extends Event_Plugin_Integration implements Feature_Even /** * Returns the ActivityPub transformer for a GatherPress event post. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post $post The WordPress post object of the Event. * @return GatherPress_Transformer */ - public static function get_activitypub_event_transformer( $post ): GatherPress_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): GatherPress_Transformer { return new GatherPress_Transformer( $post, self::get_event_category_taxonomy() ); } @@ -80,6 +81,15 @@ final class GatherPress extends Event_Plugin_Integration implements Feature_Even return GatherPress_Transmogrifier::class; } + /** + * GatherPress uses a taxonomy to store venues. + * + * @return string + */ + public static function get_place_taxonomy() { + return '_gatherpress_venue'; + } + /** * Get a list of Post IDs of events that have ended. * @@ -87,11 +97,12 @@ final class GatherPress extends Event_Plugin_Integration implements Feature_Even * * @return array */ - public static function get_cached_remote_events( $ends_before_time ): array { + public static function get_cached_remote_events( int $ends_before_time ): array { global $wpdb; $ends_before_time_string = gmdate( 'Y-m-d H:i:s', $ends_before_time ); + // phpcs:disable WordPress.DB.DirectDatabaseQuery $results = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT {$wpdb->prefix}posts.ID diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-modern-events-calendar-lite.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-modern-events-calendar-lite.php index 01f1384e..71284c4b 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-modern-events-calendar-lite.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-modern-events-calendar-lite.php @@ -13,9 +13,10 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\Modern_Events_Calendar_Lite as Modern_Events_Calendar_Lite_Transformer; +use WP_Post; /** * Modern Events Calendar (Lite) @@ -66,10 +67,10 @@ final class Modern_Events_Calendar_Lite extends Event_Plugin_Integration { /** * Returns the ActivityPub transformer for a Modern_Events_Calendar_Lite event post. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post $post The WordPress post object of the Event. * @return Modern_Events_Calendar_Lite_Transformer */ - public static function get_activitypub_event_transformer( $post ): Modern_Events_Calendar_Lite_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): Modern_Events_Calendar_Lite_Transformer { return new Modern_Events_Calendar_Lite_Transformer( $post, self::get_event_category_taxonomy() ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-spiffy-calendar.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-spiffy-calendar.php new file mode 100644 index 00000000..60825f43 --- /dev/null +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-spiffy-calendar.php @@ -0,0 +1,81 @@ + */ - public static function get_cached_remote_events( $ends_before_time ): array { + public static function get_cached_remote_events( int $ends_before_time ): array { $args = array( 'post_type' => 'event', 'posts_per_page' => -1, 'fields' => 'ids', + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'meta_query' => array( 'relation' => 'AND', array( diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-wp-event-manager.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-wp-event-manager.php index 668e4822..6e628727 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-wp-event-manager.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/class-wp-event-manager.php @@ -13,9 +13,10 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\ActivityPub\Transformer\Event\WP_Event_Manager as WP_Event_Manager_Transformer; +use WP_Post; /** * Interface for a supported event plugin. @@ -64,10 +65,10 @@ final class WP_Event_Manager extends Event_Plugin_Integration { /** * Returns the ActivityPub transformer for a WP_Event_Manager event post. * - * @param \WP_Post $post The WordPress post object of the Event. + * @param WP_Post $post The WordPress post object of the Event. * @return WP_Event_Manager_Transformer */ - public static function get_activitypub_event_transformer( $post ): WP_Event_Manager_Transformer { + public static function get_activitypub_event_transformer( WP_Post $post ): WP_Event_Manager_Transformer { return new WP_Event_Manager_Transformer( $post, self::get_event_category_taxonomy() ); } } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/interface-feature-event-sources.php b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/interface-feature-event-sources.php index 05e1ca46..ff38251c 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/interface-feature-event-sources.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/integrations/interface-feature-event-sources.php @@ -14,7 +14,7 @@ namespace Event_Bridge_For_ActivityPub\Integrations; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /** * Interface for an event plugin integration that supports the Event Sources feature. @@ -38,5 +38,5 @@ interface Feature_Event_Sources { * * @return int[] List of post IDs for events that match the criteria. */ - public static function get_cached_remote_events( $ends_before_time ): array; + public static function get_cached_remote_events( int $ends_before_time ): array; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/includes/table/class-event-sources.php b/wp-content/plugins/event-bridge-for-activitypub/includes/table/class-event-sources.php index bfeb8ec5..13adb965 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/includes/table/class-event-sources.php +++ b/wp-content/plugins/event-bridge-for-activitypub/includes/table/class-event-sources.php @@ -13,14 +13,13 @@ namespace Event_Bridge_For_ActivityPub\Table; // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore -use WP_List_Table; use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Sources_Collection; use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source; +use WP_List_Table; if ( ! \class_exists( '\WP_List_Table' ) ) { - // @phpstan-ignore-next-line require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; } @@ -118,7 +117,7 @@ class Event_Sources extends WP_List_Table { foreach ( $event_sources['actors'] as $event_source_post_id => $event_source_activitypub_id ) { $event_source = Event_Source::get_by_id( (int) $event_source_post_id ); - if ( ! $event_source || ! in_array( $event_source->get_status(), array( 'publish', 'pending' ), true ) ) { + if ( ! $event_source || ! \in_array( $event_source->get_status(), array( 'publish', 'pending' ), true ) ) { continue; } @@ -155,7 +154,7 @@ class Event_Sources extends WP_List_Table { * @return string */ public function column_default( $item, $column_name ) { - if ( ! array_key_exists( $column_name, $item ) ) { + if ( ! \array_key_exists( $column_name, $item ) ) { return __( 'None', 'event-bridge-for-activitypub' ); } return $item[ $column_name ]; @@ -167,8 +166,8 @@ class Event_Sources extends WP_List_Table { * @param array $item Item. * @return string */ - public function column_icon( $item ): string { - return sprintf( + public function column_icon( array $item ): string { + return \sprintf( '', $item['icon'] ); @@ -181,7 +180,7 @@ class Event_Sources extends WP_List_Table { * @return string */ public function column_url( $item ): string { - return sprintf( + return \sprintf( '%s', esc_url( $item['url'] ), $item['url'] @@ -195,7 +194,7 @@ class Event_Sources extends WP_List_Table { * @return string */ public function column_cb( $item ): string { - return sprintf( '', esc_attr( $item['identifier'] ) ); + return \sprintf( '', esc_attr( $item['identifier'] ) ); } /** @@ -204,7 +203,7 @@ class Event_Sources extends WP_List_Table { * @param array $item Item. * @return string */ - public function column_accepted( $item ): string { + public function column_accepted( array $item ): string { if ( $item['accepted'] ) { return esc_html__( 'Accepted', 'event-bridge-for-activitypub' ); } else { diff --git a/wp-content/plugins/event-bridge-for-activitypub/readme.txt b/wp-content/plugins/event-bridge-for-activitypub/readme.txt index 1643b052..919a60e3 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/readme.txt +++ b/wp-content/plugins/event-bridge-for-activitypub/readme.txt @@ -2,9 +2,9 @@ Contributors: andremenrath, pfefferle Tags: events, fediverse, activitypub, calendar Requires at least: 6.5 -Tested up to: 6.8 -Stable tag: 1.1.0 -Requires PHP: 7.4 +Tested up to: 7.0 +Stable tag: 1.3.0 +Requires PHP: 8.1 License: AGPL-3.0-or-later License URI: https://www.gnu.org/licenses/agpl-3.0.html Integrating popular event plugins with the ActivityPub plugin. @@ -53,13 +53,14 @@ Even platforms that don't yet fully support events, like [Mastodon](https://join **Improved Event Discoverability:** Your custom event categories are mapped to a set of default categories used in the Fediverse, helping your events reach a wider audience. This improves the chances that users searching for similar events on other platforms will find yours. -**Event Reminders for Your Followers:** Often, events are planned well in advance. To keep your followers informed right in time, you can set up reminders that are supposed to trigger the events showing up in their timelines right before the event starts. At the moment this reminder is implemented as a self-boost of your original event post. While this feature may behave differently across various platforms, we are working on a more robust solution that will let you schedule dedicated reminder notes that appear in all followers' timelines. +**Event Reminders for Your Followers:** Often, events are planned well in advance. To keep your followers informed right in time, you can set up reminders that are supposed to trigger the events showing up in their timelines right before the event starts. **External Event Sources:** This functionality is only available for a subset of the supported event plugins. It enables your WordPress site to act as a hub for displaying events from other ActivityPub profiles, aggregating them into a cohesive calendar view. == Installation == -This plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/). Additionally, you need to use one of the supported event Plugins. +1. This plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/). +2. Additionally, you need to use one of the supported event Plugins. = Supported Event Plugins = @@ -77,6 +78,7 @@ Basic support (outgoing events): * [Modern Events Calendar Lite](https://webnus.net/modern-events-calendar/) * [Event Organiser](https://wordpress.org/plugins/event-organiser/) * [EventPrime – Events Calendar, Bookings and Tickets](https://wordpress.org/plugins/eventprime-event-calendar-management/) +* [Spiffy Calendar](https://wordpress.org/plugins/spiffy-calendar/) = Configuration = @@ -92,61 +94,63 @@ Yes, this plugin works as an add-on and requires both the ActivityPub plugin and Your events can be followed on platforms that support ActivityPub like [Mobilizon](https://joinmobilizon.org/), [Gancio](https://gancio.org), [Friendica](https://friendi.ca), [Hubzilla](https://hubzilla.org), and [Pleroma](https://pleroma.social/). Even other applications like [Mastodon](https://joinmastodon.org), which don't fully support events yet, will display all important information about the events. -= Why does Mastodon not show any updates? == - -Mastodon does not yet handle updates of `Event` objects. See the related tracking issue [#31114](https://github.com/mastodon/mastodon/issues/31114). - = How much extra work is required to maintain my events across the decentralized Web? = None! Once the plugin is set up, your events are automatically sent to all connected platforms or account that follow you (your Website). Any updates you make to your events are synced without additional effort. -= Can I still use social media to promote my events? = - -Yes, you can still use traditional social media if you wish. However, this plugin helps reduce reliance on commercial platforms by connecting your events to the decentralized Fediverse. - -= Will this plugin work if I don't use the ActivityPub plugin? = - -No, the Event Federation Plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/activitypub/) to deliver your events across decentralized platforms, so it's essential to have it installed and configured. - = My event plugin is not supported, what can I do? = If you know about coding have a look at the documentation of how to add your plugin or open an [issue](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/issues), if we can spare some free hours we might add it. -= What if I experience problems? = - -We're always interested in your feedback. Feel free to reach out to us via [E-Mail](https://event-federation.eu/contact/) or create an [issue](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/issues). - == Acknowledgement == The development of this WordPress plugin was funded through the [NGI0 Entrust](https://NLnet.nl/entrust) Fund, a fund established by [NLnet](https://nlnet.nl) with financial support from the European Commission's [Next Generation Internet](https://ngi.eu) programme, under the aegis of [Communications Networks, Content and Technology](https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en) under grant agreement number 101069594. == Changelog == -= [1.1.0] - 2025-04-12 = += 1.3.0 - 2025-05-22 = -* Added: Basic support for Starter Kits -* Fixed: Uncatched error in following process (issue #145) -* Fixed: Compatibility with ActivityPub plugin version 5.7.0 +* Added: Basic support for Spiffy Calendar Plugin +* Added: Support for WordPress 7 +* Changed: Requires ActivityPub plugin 8.+ +* Fixed: The events calendar integration: remote cached organizers not being public. -= [1.0.0] - 2025-02-11 = += 1.2.4 - 2025-05-17 = -* Added: Support for the EventPrime event plugin -* Added: Event self-announce feature at configurable time before event starts -* Added: Blueprint (Preview via WordPress Playground) -* Added: Event Sources feature: cache and list events from remote ActivityPub profiles on your site -* Added: Custom ActivityPub preview -* Added: Admin setting to enfore sending summary of events as plain text -* Changed: Now depends on ActivityPub plugin version greater than 5.1.0 -* Fixed: The Events Calendar date times when using the Gutenberg editor -* Fixed: Improved admin UI for event-category mapping +* Added: Flag plugin compatible with WordPress 6.9 -= [0.3.5] - 2025-01-03 = += 1.2.3 - 2025-05-17 = -* Fixed: Images of Acknowledgements in Admin UI +* Added: ActivityPub `Place` transformer for GatherPress +* Fixed: Improve timezone detection for Eventin +* Fixed: GatherPress place name not uses venue name +* Changed: Time formatting for EventPrime +* Changed: Time formatting for VS Event List +* Changed: Test up to ActivityPub plugin 8.2.1 -= [0.3.4] - 2024-12-21 = += 1.2.2 - 2025-11-21 = -* Initial release on https://wordpress.org/ +* Fixed: timezone issues for Modern Events Calendar Lite +* Fixed: Validate event-tag info Events Manager to prevent fatal error + += 1.2.1 - 2025-11-13 = + +* Fixed: Incoming remote events getting federated +* Add: Hotfix Mobilizon group behavior to detect correct event source + += 1.2.0 - 2025-11-12 = + +* Added: New filter hook for incoming events +* Added: Store longitude and latitude information for incoming The Events Calendar events +* Changed: Update to new method how actor json is stored +* Changed: Plugin now requires PHP 8.1+ +* Changed: Plugin now requires the WordPress ActivityPub plugin 7.5+ +* Fixed: Time offset for outgoing GatherPress events +* Fixed: Time offset for importing events with The Events Calendar + += Full Changelog = + +[See the CHANGELOG.md](https://codeberg.org/Event-Federation/wordpress-event-bridge-for-activitypub/src/branch/main/CHANGELOG.md) == Contributing == diff --git a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/menu.php b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/menu.php index b4e333fd..25ddda89 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/menu.php +++ b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/menu.php @@ -8,7 +8,7 @@ */ // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore /* @var array $args Template arguments. */ $args = wp_parse_args( diff --git a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/event-sources.php b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/event-sources.php index a0690613..245e85b1 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/event-sources.php +++ b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/event-sources.php @@ -8,7 +8,7 @@ */ // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\Setup; @@ -24,8 +24,6 @@ if ( ! current_user_can( 'manage_options' ) ) { return; } -$activitypub_plugin_is_active = Setup::get_instance()->is_activitypub_plugin_active(); - \get_option( 'event_bridge_for_activitypub_event_sources_active', false ); if ( ! isset( $args ) || ! array_key_exists( 'supports_event_sources', $args ) ) { @@ -38,199 +36,198 @@ $event_sources_active = \get_option( 'event_bridge_for_activitypub_event_sourc $cache_retention_period = \get_option( 'event_bridge_for_activitypub_event_source_cache_retention', DAY_IN_SECONDS ); ?> - -
-
- -
-

-

+ +
+ + +
+

+

+ + + + + + + -
+ + + + > +
- - - - - + + + + + + + + - - - - - - - - - - -
- - - - > -
+ + + +

+
+ + + +

+
- - - -

-
- - - -

-
- -

-

- '; - foreach ( $plugins_supporting_event_sources as $event_plugin ) { - echo '
  • ' . esc_attr( $event_plugin->get_plugin_name() ) . '
  • '; - } - echo ''; - } else { - $activitypub_plugin_data = \get_plugin_data( ACTIVITYPUB_PLUGIN_FILE ); - - $notice = sprintf( - /* translators: 1: The name of the ActivityPub plugin. */ - _x( - 'In order to use this feature your have to enable the Blog-Actor in the the %2$s settings.', - 'admin notice', - 'event-bridge-for-activitypub' - ), - \admin_url( 'options-general.php?page=activitypub&tab=event-bridge-for-activitypub&subpage=settings' ), - \esc_html( $activitypub_plugin_data['Name'] ) - ); - - $allowed_html = array( - 'a' => array( - 'href' => true, - 'title' => true, - ), - ); - echo '

    ' . \wp_kses( $notice, $allowed_html ) . '

    '; } ?> -
    - - -
    -
    -
    - + + +

    +

    + '; + foreach ( $plugins_supporting_event_sources as $event_plugin ) { + echo '
  • ' . esc_attr( $event_plugin->get_plugin_name() ) . '
  • '; + } + echo ''; + } else { + $activitypub_plugin_data = \get_plugin_data( ACTIVITYPUB_PLUGIN_FILE ); + + $notice = sprintf( + /* translators: 1: The name of the ActivityPub plugin. */ + _x( + 'In order to use this feature your have to enable the Blog-Actor in the the %2$s settings.', + 'admin notice', + 'event-bridge-for-activitypub' + ), + \admin_url( 'options-general.php?page=activitypub&tab=event-bridge-for-activitypub&subpage=settings' ), + \esc_html( $activitypub_plugin_data['Name'] ) + ); + + $allowed_html = array( + 'a' => array( + 'href' => true, + 'title' => true, + ), + ); + echo '

    ' . \wp_kses( $notice, $allowed_html ) . '

    '; + } ?> - - -
    - -
    -

    - - - - -
    -
    - - - +
    + + +
    +
    +
    + + + - +
    + +

    + +

    + + +
    +
    +
    + +
    +

    + + + + +
    +
    + + + + prepare_items(); + $table->search_box( 'Search', 'search' ); + $table->display(); + ?> +
    +
    + +
    diff --git a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/settings.php b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/settings.php index 60106358..f53734cb 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/settings.php +++ b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/settings.php @@ -12,7 +12,7 @@ */ // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Activitypub\Activity\Extended_Object\Event; use Event_Bridge_For_ActivityPub\Setup; @@ -25,8 +25,6 @@ use Event_Bridge_For_ActivityPub\Setup; ) ); -$activitypub_plugin_is_active = Setup::get_instance()->is_activitypub_plugin_active(); - if ( ! isset( $args ) || ! array_key_exists( 'event_terms', $args ) ) { return; } diff --git a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/welcome.php b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/welcome.php index c5456cec..3af260ba 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/welcome.php +++ b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/subpages/welcome.php @@ -8,7 +8,7 @@ */ // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\Setup; use Event_Bridge_For_ActivityPub\Admin\General_Admin_Notices; @@ -24,7 +24,6 @@ use Event_Bridge_For_ActivityPub\Admin\Health_Check; ); $active_event_plugins = Setup::get_instance()->get_active_event_plugins(); -$activitypub_plugin_is_active = Setup::get_instance()->is_activitypub_plugin_active(); $event_bridge_for_activitypub_status_ok = true; $example_event_post = Health_Check::get_most_recent_event_posts(); @@ -46,10 +45,7 @@ WP_Filesystem();

    ⚠' . \wp_kses( $notice, General_Admin_Notices::ALLOWED_HTML ) . '

    '; - } elseif ( empty( $active_event_plugins ) ) { + if ( empty( $active_event_plugins ) ) { $notice = General_Admin_Notices::get_admin_notice_no_supported_event_plugin_active(); echo '

    ⚠' . \wp_kses( $notice, General_Admin_Notices::ALLOWED_HTML ) . '

    '; } @@ -239,7 +235,7 @@ WP_Filesystem();

    -

    Logo NLnet: abstract logo of four people seen from above Logo NGI Zero: letterlogo shaped like a tag

    +

    The development of this plugin was funded through the NGI0 Entrust Fund, a fund established by NLnet with financial support from the European Commission's Next Generation Internet programme, under the aegis of DG Communications Networks, Content and Technology under grant agreement No 101069594.

    diff --git a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/tab.php b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/tab.php index 753c1b8a..2f0b9658 100644 --- a/wp-content/plugins/event-bridge-for-activitypub/templates/settings/tab.php +++ b/wp-content/plugins/event-bridge-for-activitypub/templates/settings/tab.php @@ -8,6 +8,6 @@ */ // Exit if accessed directly. -defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore +\defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore \Event_Bridge_For_ActivityPub\Admin\Settings_Page::do_settings_page();