modified file enshrined

This commit is contained in:
2024-07-19 19:46:16 +00:00
committed by Gitium
parent 39ec06fbc1
commit 51937c2f57
856 changed files with 3722 additions and 180872 deletions

View File

@ -1,6 +1,7 @@
<?php
namespace Activitypub\Transformer;
use WP_Error;
use WP_Post;
use WP_Comment;
@ -30,9 +31,9 @@ abstract class Base {
*
* @param WP_Post|WP_Comment $wp_object The WordPress object
*
* @return Base_Object
* @return Base
*/
public static function transform( $object ) {
public static function transform( $object ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound
return new static( $object );
}

View File

@ -6,12 +6,13 @@ use WP_Comment_Query;
use Activitypub\Webfinger;
use Activitypub\Comment as Comment_Utils;
use Activitypub\Model\Blog_User;
use Activitypub\Model\Blog;
use Activitypub\Collection\Users;
use Activitypub\Transformer\Base;
use function Activitypub\is_single_user;
use function Activitypub\get_rest_url_by_path;
use function Activitypub\get_comment_ancestors;
/**
* WordPress Comment Transformer
@ -69,7 +70,7 @@ class Comment extends Base {
$this->get_locale() => $this->get_content(),
)
);
$path = sprintf( 'users/%d/followers', intval( $comment->comment_author ) );
$path = sprintf( 'actors/%d/followers', intval( $comment->comment_author ) );
$object->set_to(
array(
@ -90,7 +91,7 @@ class Comment extends Base {
*/
protected function get_attributed_to() {
if ( is_single_user() ) {
$user = new Blog_User();
$user = new Blog();
return $user->get_url();
}
@ -218,6 +219,23 @@ class Comment extends Base {
return apply_filters( 'activitypub_extract_mentions', array(), $this->wp_object->comment_content, $this->wp_object );
}
/**
* Gets the ancestors of the comment, but only the ones that are ActivityPub comments.
*
* @return array The list of ancestors.
*/
protected function get_comment_ancestors() {
$ancestors = get_comment_ancestors( $this->wp_object );
// Now that we have the full tree of ancestors, only return the ones received from the fediverse
return array_filter(
$ancestors,
function ( $comment_id ) {
return \get_comment_meta( $comment_id, 'protocol', true ) === 'activitypub';
}
);
}
/**
* Collect all other Users that participated in this comment-thread
* to send them a notification about the new reply.
@ -232,27 +250,18 @@ class Comment extends Base {
return $mentions;
}
$comment_query = new WP_Comment_Query(
array(
'post_id' => $this->wp_object->comment_post_ID,
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
'meta_query' => array(
array(
'key' => 'protocol',
'value' => 'activitypub',
),
),
)
);
$ancestors = $this->get_comment_ancestors();
if ( ! $ancestors ) {
return $mentions;
}
if ( $comment_query->comments ) {
foreach ( $comment_query->comments as $comment ) {
if ( ! empty( $comment->comment_author_url ) ) {
$acct = Webfinger::uri_to_acct( $comment->comment_author_url );
if ( $acct && ! is_wp_error( $acct ) ) {
$acct = str_replace( 'acct:', '@', $acct );
$mentions[ $acct ] = $comment->comment_author_url;
}
foreach ( $ancestors as $comment_id ) {
$comment = \get_comment( $comment_id );
if ( $comment && ! empty( $comment->comment_author_url ) ) {
$acct = Webfinger::uri_to_acct( $comment->comment_author_url );
if ( $acct && ! is_wp_error( $acct ) ) {
$acct = str_replace( 'acct:', '@', $acct );
$mentions[ $acct ] = $comment->comment_author_url;
}
}
}

View File

@ -11,7 +11,11 @@ use Activitypub\Transformer\Attachment;
* Transformer Factory
*/
class Factory {
public static function get_transformer( $object ) {
/**
* @param mixed $object The object to transform
* @return \Activitypub\Transformer|\WP_Error The transformer to use, or an error.
*/
public static function get_transformer( $object ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.objectFound
if ( ! \is_object( $object ) ) {
return new WP_Error( 'invalid_object', __( 'Invalid object', 'activitypub' ) );
}
@ -41,9 +45,9 @@ class Factory {
* return $transformer;
* }, 10, 3 );
*
* @param Activitypub\Transformer\Base $transformer The transformer to use.
* @param mixed $object The object to transform.
* @param string $object_class The class of the object to transform.
* @param Base $transformer The transformer to use.
* @param mixed $object The object to transform.
* @param string $object_class The class of the object to transform.
*
* @return mixed The transformer to use.
*/

View File

@ -3,13 +3,13 @@ namespace Activitypub\Transformer;
use WP_Post;
use Activitypub\Shortcodes;
use Activitypub\Model\Blog_User;
use Activitypub\Model\Blog;
use Activitypub\Transformer\Base;
use Activitypub\Collection\Users;
use Activitypub\Activity\Base_Object;
use function Activitypub\esc_hashtag;
use function Activitypub\is_single_user;
use function Activitypub\get_enclosures;
use function Activitypub\get_rest_url_by_path;
use function Activitypub\site_supports_blocks;
@ -70,7 +70,7 @@ class Post extends Base {
$this->get_locale() => $this->get_content(),
)
);
$path = sprintf( 'users/%d/followers', intval( $post->post_author ) );
$path = sprintf( 'actors/%d/followers', intval( $post->post_author ) );
$object->set_to(
array(
@ -116,7 +116,7 @@ class Post extends Base {
* @return string The User-URL.
*/
protected function get_attributed_to() {
$blog_user = new Blog_User();
$blog_user = new Blog();
if ( is_single_user() ) {
return $blog_user->get_url();
@ -139,14 +139,34 @@ class Post extends Base {
protected function get_attachment() {
// Once upon a time we only supported images, but we now support audio/video as well.
// We maintain the image-centric naming for backwards compatibility.
$max_media = \intval( \apply_filters( 'activitypub_max_image_attachments', \get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) ) );
$max_media = \intval(
\apply_filters(
'activitypub_max_image_attachments',
\get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS )
)
);
if ( site_supports_blocks() && \has_blocks( $this->wp_object->post_content ) ) {
$media = $this->get_block_attachments( $max_media );
} else {
$media = $this->get_classic_editor_images( $max_media );
$media = array(
'audio' => array(),
'video' => array(),
'image' => array(),
);
$id = $this->wp_object->ID;
// list post thumbnail first if this post has one
if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) {
$media['image'][] = array( 'id' => \get_post_thumbnail_id( $id ) );
}
$media = $this->get_enclosures( $media );
if ( site_supports_blocks() && \has_blocks( $this->wp_object->post_content ) ) {
$media = $this->get_block_attachments( $media, $max_media );
} else {
$media = $this->get_classic_editor_images( $media, $max_media );
}
$media = self::filter_media_by_object_type( $media, \get_post_format( $this->wp_object ), $this->wp_object );
$unique_ids = \array_unique( \array_column( $media, 'id' ) );
$media = \array_intersect_key( $media, $unique_ids );
$media = \array_slice( $media, 0, $max_media );
@ -157,35 +177,21 @@ class Post extends Base {
/**
* Get media attachments from blocks. They will be formatted as ActivityPub attachments, not as WP attachments.
*
* @param int $max_media The maximum number of attachments to return.
* @param array $media The media array grouped by type.
* @param int $max_media The maximum number of attachments to return.
*
* @return array The attachments.
*/
protected function get_block_attachments( $max_media ) {
protected function get_block_attachments( $media, $max_media ) {
// max media can't be negative or zero
if ( $max_media <= 0 ) {
return array();
}
$id = $this->wp_object->ID;
$blocks = \parse_blocks( $this->wp_object->post_content );
$media = self::get_media_from_blocks( $blocks, $media );
$media = array(
'image' => array(),
'audio' => array(),
'video' => array(),
);
// list post thumbnail first if this post has one
if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) {
$media['image'][] = array( 'id' => \get_post_thumbnail_id( $id ) );
}
if ( $max_media > 0 ) {
$blocks = \parse_blocks( $this->wp_object->post_content );
$media = self::get_media_from_blocks( $blocks, $media );
}
return self::filter_media_by_object_type( $media, \get_post_format( $this->wp_object ) );
return $media;
}
/**
@ -202,8 +208,9 @@ class Post extends Base {
if ( $max_images <= 0 ) {
return array();
}
$images = array();
$query = new \WP_Query(
$query = new \WP_Query(
array(
'post_parent' => $this->wp_object->ID,
'post_status' => 'inherit',
@ -214,6 +221,7 @@ class Post extends Base {
'posts_per_page' => $max_images,
)
);
foreach ( $query->get_posts() as $attachment ) {
if ( ! \in_array( $attachment->ID, $images, true ) ) {
$images[] = array( 'id' => $attachment->ID );
@ -249,7 +257,7 @@ class Post extends Base {
// This linter warning is a false positive - we have to
// re-count each time here as we modify $images.
// phpcs:ignore Squiz.PHP.DisallowSizeFunctionsInLoops.Found
while ( $tags->next_tag( 'img' ) && ( \count( $images ) < $max_images ) ) {
while ( $tags->next_tag( 'img' ) && ( \count( $images ) <= $max_images ) ) {
$src = $tags->get_attribute( 'src' );
// If the img source is in our uploads dir, get the
@ -292,34 +300,68 @@ class Post extends Base {
* Get post images from the classic editor.
* Note that audio/video attachments are only supported in the block editor.
*
* @param int $max_images The maximum number of images to return.
* @param array $media The media array grouped by type.
* @param int $max_images The maximum number of images to return.
*
* @return array The attachments.
*/
protected function get_classic_editor_images( $max_images ) {
protected function get_classic_editor_images( $media, $max_images ) {
// max images can't be negative or zero
if ( $max_images <= 0 ) {
return array();
}
$id = $this->wp_object->ID;
$images = array();
// list post thumbnail first if this post has one
if ( \function_exists( 'has_post_thumbnail' ) && \has_post_thumbnail( $id ) ) {
$images[] = \get_post_thumbnail_id( $id );
}
if ( \count( $images ) < $max_images ) {
if ( \count( $media['image'] ) <= $max_images ) {
if ( \class_exists( '\WP_HTML_Tag_Processor' ) ) {
$images = \array_merge( $images, $this->get_classic_editor_image_embeds( $max_images ) );
$media['image'] = \array_merge( $media['image'], $this->get_classic_editor_image_embeds( $max_images ) );
} else {
$images = \array_merge( $images, $this->get_classic_editor_image_attachments( $max_images ) );
$media['image'] = \array_merge( $media['image'], $this->get_classic_editor_image_attachments( $max_images ) );
}
}
return $images;
return $media;
}
/**
* Get enclosures for a post.
*
* @param array $media The media array grouped by type.
*
* @return array The media array extended with enclosures.
*/
public function get_enclosures( $media ) {
$enclosures = get_enclosures( $this->wp_object->ID );
if ( ! $enclosures ) {
return $media;
}
foreach ( $enclosures as $enclosure ) {
// check if URL is an attachment
$attachment_id = \attachment_url_to_postid( $enclosure['url'] );
if ( $attachment_id ) {
$enclosure['id'] = $attachment_id;
$enclosure['url'] = \wp_get_attachment_url( $attachment_id );
$enclosure['mediaType'] = \get_post_mime_type( $attachment_id );
}
$mime_type = $enclosure['mediaType'];
$mime_type_parts = \explode( '/', $mime_type );
switch ( $mime_type_parts[0] ) {
case 'image':
$media['image'][] = $enclosure;
break;
case 'audio':
$media['audio'][] = $enclosure;
break;
case 'video':
$media['video'][] = $enclosure;
break;
}
}
return $media;
}
/**
@ -331,7 +373,6 @@ class Post extends Base {
* @return array The image IDs.
*/
protected static function get_media_from_blocks( $blocks, $media ) {
foreach ( $blocks as $block ) {
// recurse into inner blocks
if ( ! empty( $block['innerBlocks'] ) ) {
@ -397,19 +438,19 @@ class Post extends Base {
/**
* Filter media IDs by object type.
*
* @param array $media The media array grouped by type.
* @param array $type The object type.
* @param array $media The media array grouped by type.
* @param string $type The object type.
*
* @return array The filtered media IDs.
*/
protected static function filter_media_by_object_type( $media, $type ) {
$type = \apply_filters( 'filter_media_by_object_type', \strtolower( $type ) );
protected static function filter_media_by_object_type( $media, $type, $wp_object ) {
$type = \apply_filters( 'filter_media_by_object_type', \strtolower( $type ), $wp_object );
if ( ! empty( $media[ $type ] ) ) {
return $media[ $type ];
}
return array_merge( array(), ...array_values( $media ) );
return array_filter( array_merge( array(), ...array_values( $media ) ) );
}
/**
@ -420,6 +461,10 @@ class Post extends Base {
* @return array The ActivityPub Attachment.
*/
public static function wp_attachment_to_activity_attachment( $media ) {
if ( ! isset( $media['id'] ) ) {
return $media;
}
$id = $media['id'];
$attachment = array();
$mime_type = \get_post_mime_type( $id );
@ -427,14 +472,14 @@ class Post extends Base {
// switching on image/audio/video
switch ( $mime_type_parts[0] ) {
case 'image':
$image_size = 'full';
$image_size = 'large';
/**
* Filter the image URL returned for each post.
*
* @param array|false $thumbnail The image URL, or false if no image is available.
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*/
$thumbnail = apply_filters(
'activitypub_get_image',
@ -488,16 +533,16 @@ class Post extends Base {
* Return details about an image attachment.
*
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*
* @return array|false Array of image data, or boolean false if no image is available.
*/
protected static function get_wordpress_attachment( $id, $image_size = 'full' ) {
protected static function get_wordpress_attachment( $id, $image_size = 'large' ) {
/**
* Hook into the image retrieval process. Before image retrieval.
*
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*/
do_action( 'activitypub_get_image_pre', $id, $image_size );
@ -507,7 +552,7 @@ class Post extends Base {
* Hook into the image retrieval process. After image retrieval.
*
* @param int $id The attachment ID.
* @param string $image_size The image size to retrieve. Set to 'full' by default.
* @param string $image_size The image size to retrieve. Set to 'large' by default.
*/
do_action( 'activitypub_get_image_post', $id, $image_size );
@ -536,7 +581,7 @@ class Post extends Base {
}
// Default to Article.
$object_type = 'Article';
$object_type = 'Note';
$post_format = 'standard';
if ( \get_theme_support( 'post-formats' ) ) {
@ -547,18 +592,12 @@ class Post extends Base {
switch ( $post_type ) {
case 'post':
switch ( $post_format ) {
case 'aside':
case 'status':
case 'quote':
case 'note':
case 'gallery':
case 'image':
case 'video':
case 'audio':
$object_type = 'Note';
case 'standard':
case '':
$object_type = 'Article';
break;
default:
$object_type = 'Article';
$object_type = 'Note';
break;
}
break;
@ -566,7 +605,7 @@ class Post extends Base {
$object_type = 'Page';
break;
default:
$object_type = 'Article';
$object_type = 'Note';
break;
}
@ -593,6 +632,16 @@ class Post extends Base {
return $cc;
}
public function get_audience() {
if ( is_single_user() ) {
return null;
} else {
$blog = new Blog();
return $blog->get_id();
}
}
/**
* Returns a list of Tags, used in the Post.
*
@ -708,6 +757,8 @@ class Post extends Base {
*/
do_action( 'activitypub_before_get_content', $post );
add_filter( 'render_block_core/embed', array( self::class, 'revert_embed_links' ), 10, 2 );
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$post = $this->wp_object;
$content = $this->get_post_content_template();
@ -792,4 +843,21 @@ class Post extends Base {
*/
return apply_filters( 'activitypub_post_locale', $lang, $post_id, $this->wp_object );
}
/**
* Transform Embed blocks to block level link.
*
* Remote servers will simply drop iframe elements, rendering incomplete content.
*
* @see https://www.w3.org/TR/activitypub/#security-sanitizing-content
* @see https://www.w3.org/wiki/ActivityPub/Primer/HTML
*
* @param string $block_content The block content (html)
* @param object $block The block object
*
* @return string A block level link
*/
public static function revert_embed_links( $block_content, $block ) {
return '<p><a href="' . esc_url( $block['attrs']['url'] ) . '">' . $block['attrs']['url'] . '</a></p>';
}
}