From 3c68c42e7113c7018ddde49540d3b1dead64d83d Mon Sep 17 00:00:00 2001 From: Jeremy Herve Date: Mon, 12 Aug 2024 19:43:53 +0200 Subject: [PATCH] Publicize: add Fediverse creator meta tag from Mastodon connection (#38809) * Publicize: add Fediverse creator meta tag from Mastodon connection This is a follow-up to #38198, which was partially reverted in #38612. It's an alternative to #38565, to ensure better compatibility with WordPress.com Simple. 1. It takes into account the ActivityPub plugin, and ensure we're not adding a tag when the ActivityPub plugin already adds one. 2. It takes into account that on WordPress.com Simple, `get_services()` may return a `Keyring_Access_Token` object instead of an array. 3. It adds the 2 necessary methods directly to the `functions.opengraph.php` file, since we know it is loaded on the frontend on WordPress.com Simple (see conversation here to find out more: https://github.com/Automattic/jetpack/pull/38565#issuecomment-2277571635 ) * Add missing since parameter --- .../changelog/update-fediverse-og-to-common | 4 + .../publicize/src/class-publicize-base.php | 89 ------------- .../changelog/update-fediverse-og-to-common | 4 + .../plugins/jetpack/functions.opengraph.php | 119 ++++++++++++++++++ 4 files changed, 127 insertions(+), 89 deletions(-) create mode 100644 projects/packages/publicize/changelog/update-fediverse-og-to-common create mode 100644 projects/plugins/jetpack/changelog/update-fediverse-og-to-common diff --git a/projects/packages/publicize/changelog/update-fediverse-og-to-common b/projects/packages/publicize/changelog/update-fediverse-og-to-common new file mode 100644 index 0000000000000..11042cc6382f0 --- /dev/null +++ b/projects/packages/publicize/changelog/update-fediverse-og-to-common @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Open Graph Meta Tags: do not handle Fediverse tags from Publicize package. diff --git a/projects/packages/publicize/src/class-publicize-base.php b/projects/packages/publicize/src/class-publicize-base.php index 278ffe10b9655..2a53803a66339 100644 --- a/projects/packages/publicize/src/class-publicize-base.php +++ b/projects/packages/publicize/src/class-publicize-base.php @@ -2140,95 +2140,6 @@ public function get_dismissed_notices() { public static function can_manage_connection( $connection_data ) { return current_user_can( 'edit_others_posts' ) || get_current_user_id() === (int) $connection_data['user_id']; } - - /** - * Display a Fediverse actor Open Graph tag when the post author has a Mastodon connection. - * - * @see https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/ - * - * @param array $tags Current tags. - * - * @return array - */ - public function add_fediverse_creator_open_graph_tag( $tags ) { - global $post; - - if ( - ! is_singular() - || ! $post instanceof WP_Post - || ! isset( $post->ID ) - || empty( $post->post_author ) - ) { - return $tags; - } - - $post_mastodon_connections = array(); - - // Loop through active connections. - foreach ( (array) $this->get_services( 'connected' ) as $service_name => $connections ) { - if ( 'mastodon' !== $service_name ) { - continue; - } - - // services can have multiple connections. Store them all in our array. - foreach ( $connections as $connection ) { - $connection_id = $this->get_connection_id( $connection ); - $mastodon_handle = $connection['external_display'] ?? ''; - - if ( empty( $mastodon_handle ) ) { - continue; - } - - // Did we skip this connection for this post? - if ( get_post_meta( $post->ID, $this->POST_SKIP_PUBLICIZE . $connection_id, true ) ) { - continue; - } - - $post_mastodon_connections[] = array( - 'user_id' => (int) $connection['user_id'], - 'connection_id' => (int) $connection_id, - 'handle' => $mastodon_handle, - 'global' => $this->is_global_connection( $connection ), - ); - } - } - - // If we have no Mastodon connections, skip. - if ( empty( $post_mastodon_connections ) ) { - return $tags; - } - - /* - * Select a single Mastodon connection to use. - * It should be either the first connection belonging to the post author, - * or the first global connection. - */ - foreach ( $post_mastodon_connections as $mastodon_connection ) { - if ( $post->post_author === $mastodon_connection['user_id'] ) { - $tags['fediverse:creator'] = esc_attr( $mastodon_connection['handle'] ); - break; - } - - if ( $mastodon_connection['global'] ) { - $tags['fediverse:creator'] = esc_attr( $mastodon_connection['handle'] ); - break; - } - } - - return $tags; - } - - /** - * Update the markup for the Open Graph tag to match the expected output for Mastodon - * (name instead of property). - * - * @param string $og_tag A single OG tag. - * - * @return string Result of the OG tag. - */ - public static function filter_fediverse_cards_output( $og_tag ) { - return ( str_contains( $og_tag, 'fediverse:' ) ) ? preg_replace( '/property="([^"]+)"/', 'name="\1"', $og_tag ) : $og_tag; - } } // phpcs:disable Universal.Files.SeparateFunctionsFromOO.Mixed -- TODO: Move these functions to some other file. diff --git a/projects/plugins/jetpack/changelog/update-fediverse-og-to-common b/projects/plugins/jetpack/changelog/update-fediverse-og-to-common new file mode 100644 index 0000000000000..12209968b41b7 --- /dev/null +++ b/projects/plugins/jetpack/changelog/update-fediverse-og-to-common @@ -0,0 +1,4 @@ +Significance: patch +Type: enhancement + +Jetpack Social: display Fediverse creator meta tag when a post has an active Mastodon connection. diff --git a/projects/plugins/jetpack/functions.opengraph.php b/projects/plugins/jetpack/functions.opengraph.php index 04cfe31086b8c..4bed25f99dbcb 100644 --- a/projects/plugins/jetpack/functions.opengraph.php +++ b/projects/plugins/jetpack/functions.opengraph.php @@ -14,6 +14,10 @@ add_action( 'wp_head', 'jetpack_og_tags' ); add_action( 'web_stories_story_head', 'jetpack_og_tags' ); +// Add a Fediverse Open Graph Tag when an author has connected their Mastodon account. +add_filter( 'jetpack_open_graph_tags', 'jetpack_add_fediverse_creator_open_graph_tag', 10, 1 ); +add_filter( 'jetpack_open_graph_output', 'jetpack_filter_fediverse_cards_output', 10, 1 ); + /** * Outputs Open Graph tags generated by Jetpack. */ @@ -533,3 +537,118 @@ function jetpack_og_get_description( $description = '', $data = null ) { return $description; } + +/** + * Display a Fediverse actor Open Graph tag when the post author has a Mastodon connection. + * + * @see https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/ + * + * @since $$next-version$$ + * + * @param array $tags Current tags. + * + * @return array + */ +function jetpack_add_fediverse_creator_open_graph_tag( $tags ) { + /* + * Let's not add any tags when the ActivityPub plugin already adds its own. + * On WordPress.com simple, let's check if the plugin is active. + * On self-hosted, let's just check if the class exists. + */ + $is_activitypub_active = function_exists( 'wpcom_activitypub_is_active' ) + ? wpcom_activitypub_is_active() + : class_exists( '\Activitypub\Integration\Opengraph' ); + + if ( $is_activitypub_active ) { + return $tags; + } + + // We pull the Mastodon connection data from Publicize. + if ( ! function_exists( 'publicize_init' ) ) { + return $tags; + } + $publicize = publicize_init(); + + global $post; + if ( + ! is_singular() + || ! $post instanceof WP_Post + || ! isset( $post->ID ) + || empty( $post->post_author ) + ) { + return $tags; + } + + $post_mastodon_connections = array(); + + // Loop through active connections. + foreach ( (array) $publicize->get_services( 'connected' ) as $service_name => $connections ) { + if ( 'mastodon' !== $service_name ) { + continue; + } + + // services can have multiple connections. Store them all in our array. + foreach ( $connections as $connection ) { + $connection_id = $publicize->get_connection_id( $connection ); + $connection_meta = $publicize->get_connection_meta( $connection ); + + $connection_data = $connection_meta['connection_data'] ?? array(); + $mastodon_handle = $connection_meta['external_display'] ?? ''; + $connection_user_id = $connection_data['user_id'] ?? 0; + + if ( empty( $mastodon_handle ) ) { + continue; + } + + // Did we skip this connection for this post? + if ( get_post_meta( $post->ID, $publicize->POST_SKIP_PUBLICIZE . $connection_id, true ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + continue; + } + + $post_mastodon_connections[] = array( + 'user_id' => (int) $connection_user_id, + 'connection_id' => (int) $connection_id, + 'handle' => $mastodon_handle, + 'global' => 0 === $connection_user_id, + ); + } + } + + // If we have no Mastodon connections, skip. + if ( empty( $post_mastodon_connections ) ) { + return $tags; + } + + /* + * Select a single Mastodon connection to use. + * It should be either the first connection belonging to the post author, + * or the first global connection. + */ + foreach ( $post_mastodon_connections as $mastodon_connection ) { + if ( (int) $post->post_author === $mastodon_connection['user_id'] ) { + $tags['fediverse:creator'] = esc_attr( $mastodon_connection['handle'] ); + break; + } + + if ( $mastodon_connection['global'] ) { + $tags['fediverse:creator'] = esc_attr( $mastodon_connection['handle'] ); + break; + } + } + + return $tags; +} + +/** + * Update the markup for the Open Graph tag to match the expected output for Mastodon + * (name instead of property). + * + * @since $$next-version$$ + * + * @param string $og_tag A single OG tag. + * + * @return string Result of the OG tag. + */ +function jetpack_filter_fediverse_cards_output( $og_tag ) { + return ( str_contains( $og_tag, 'fediverse:' ) ) ? preg_replace( '/property="([^"]+)"/', 'name="\1"', $og_tag ) : $og_tag; +}