diff --git a/includes/class-hashtag.php b/includes/class-hashtag.php index 1d8ea755..8f441c4b 100644 --- a/includes/class-hashtag.php +++ b/includes/class-hashtag.php @@ -28,29 +28,14 @@ class Hashtag { * @return array the activity object array */ public static function filter_activity_object( $object_array ) { - if ( empty( $object_array['summary'] ) ) { - return $object_array; + if ( ! empty( $object_array['summary'] ) ) { + $object_array['summary'] = self::the_content( $object_array['summary'] ); } - \preg_match_all( '/' . ACTIVITYPUB_HASHTAGS_REGEXP . '/', $object_array['summary'], $matches ); - foreach ( $matches[0] as $match_id => $match ) { - $tag_object = \get_term_by( 'name', $matches[1][ $match_id ], 'post_tag' ); - if ( ! $tag_object ) { - $tag_object = \get_term_by( 'name', $matches[1][ $match_id ], 'category' ); - } - - if ( $tag_object ) { - $link = \get_term_link( $tag_object, 'post_tag' ); - $object_array['tag'][] = [ - 'type' => 'Hashtag', - 'href' => $link, - 'name' => $match, - ]; - } + if ( ! empty( $object_array['content'] ) ) { + $object_array['content'] = self::the_content( $object_array['content'] ); } - $object_array['summary'] = self::the_content( $object_array['summary'] ); - return $object_array; } @@ -63,12 +48,20 @@ class Hashtag { * @return */ public static function insert_post( $id, $post ) { - if ( \preg_match_all( '/' . ACTIVITYPUB_HASHTAGS_REGEXP . '/i', $post->post_content, $match ) ) { - $tags = \implode( ', ', $match[1] ); + $tags = array(); - \wp_add_post_tags( $post->post_parent, $tags ); + if ( \preg_match_all( '/' . ACTIVITYPUB_HASHTAGS_REGEXP . '/i', $post->post_content, $match ) ) { + $tags = array_merge( $tags, $match[1] ); } + if ( \preg_match_all( '/' . ACTIVITYPUB_HASHTAGS_REGEXP . '/i', $post->post_excerpt, $match ) ) { + $tags = array_merge( $tags, $match[1] ); + } + + $tags = \implode( ', ', $tags ); + + \wp_add_post_tags( $post->ID, $tags ); + return $id; } diff --git a/includes/class-link.php b/includes/class-link.php index b8ec6769..378248d2 100644 --- a/includes/class-link.php +++ b/includes/class-link.php @@ -12,6 +12,7 @@ class Link { * Initialize the class, registering WordPress hooks */ public static function init() { + \add_filter( 'activitypub_extra_field_content', array( self::class, 'the_content' ), 10, 1 ); \add_filter( 'activitypub_activity_object_array', array( self::class, 'filter_activity_object' ), 99 ); } @@ -23,11 +24,13 @@ class Link { * @return array the activity object array */ public static function filter_activity_object( $object_array ) { - if ( empty( $object_array['summary'] ) ) { - return $object_array; + if ( ! empty( $object_array['summary'] ) ) { + $object_array['summary'] = self::the_content( $object_array['summary'] ); } - $object_array['summary'] = self::the_content( $object_array['summary'] ); + if ( ! empty( $object_array['content'] ) ) { + $object_array['content'] = self::the_content( $object_array['content'] ); + } return $object_array; } diff --git a/includes/class-mention.php b/includes/class-mention.php index 116ae2dc..1219b326 100644 --- a/includes/class-mention.php +++ b/includes/class-mention.php @@ -19,6 +19,7 @@ class Mention { public static function init() { \add_filter( 'the_content', array( self::class, 'the_content' ), 99, 1 ); \add_filter( 'comment_text', array( self::class, 'the_content' ), 10, 1 ); + \add_filter( 'activitypub_extra_field_content', array( self::class, 'the_content' ), 10, 1 ); \add_filter( 'activitypub_extract_mentions', array( self::class, 'extract_mentions' ), 99, 2 ); \add_filter( 'activitypub_activity_object_array', array( self::class, 'filter_activity_object' ), 99 ); } @@ -32,11 +33,13 @@ class Mention { * @return array the activity object array */ public static function filter_activity_object( $object_array ) { - if ( empty( $object_array['summary'] ) ) { - return $object_array; + if ( ! empty( $object_array['summary'] ) ) { + $object_array['summary'] = self::the_content( $object_array['summary'] ); } - $object_array['summary'] = self::the_content( $object_array['summary'] ); + if ( ! empty( $object_array['content'] ) ) { + $object_array['content'] = self::the_content( $object_array['content'] ); + } return $object_array; } @@ -145,6 +148,6 @@ class Mention { $mentions[ $match ] = $link; } } - return $mentions; + return \array_unique( $mentions ); } } diff --git a/includes/class-shortcodes.php b/includes/class-shortcodes.php index b32b91dd..16be96ab 100644 --- a/includes/class-shortcodes.php +++ b/includes/class-shortcodes.php @@ -2,6 +2,7 @@ namespace Activitypub; use function Activitypub\esc_hashtag; +use function Activitypub\generate_post_summary; class Shortcodes { /** @@ -108,81 +109,7 @@ class Shortcodes { $excerpt_length = ACTIVITYPUB_EXCERPT_LENGTH; } - $excerpt = \get_post_field( 'post_excerpt', $item ); - - if ( 'attachment' === $item->post_type ) { - // get title of attachment with fallback to alt text. - $content = wp_get_attachment_caption( $item->ID ); - if ( empty( $content ) ) { - $content = get_post_meta( $item->ID, '_wp_attachment_image_alt', true ); - } - } elseif ( '' === $excerpt ) { - $content = \get_post_field( 'post_content', $item ); - - // An empty string will make wp_trim_excerpt do stuff we do not want. - if ( '' !== $content ) { - $excerpt = \strip_shortcodes( $content ); - - /** This filter is documented in wp-includes/post-template.php */ - $excerpt = \apply_filters( 'the_content', $excerpt ); - $excerpt = \str_replace( ']]>', ']]>', $excerpt ); - } - } - - // Strip out any remaining tags. - $excerpt = \wp_strip_all_tags( $excerpt ); - - $excerpt_more = \apply_filters( 'activitypub_excerpt_more', ' […]' ); - $excerpt_more_len = strlen( $excerpt_more ); - - // We now have a excerpt, but we need to check it's length, it may be longer than we want for two reasons: - // - // * The user has entered a manual excerpt which is longer that what we want. - // * No manual excerpt exists so we've used the content which might be longer than we want. - // - // Either way, let's trim it up if we need too. Also, don't forget to take into account the more indicator - // as part of the total length. - // - - // Setup a variable to hold the current excerpts length. - $current_excerpt_length = strlen( $excerpt ); - - // Setup a variable to keep track of our target length. - $target_excerpt_length = $excerpt_length - $excerpt_more_len; - - // Setup a variable to keep track of the current max length. - $current_excerpt_max = $target_excerpt_length; - - // This is a loop since we can't calculate word break the string after 'the_excpert' filter has run (we would break - // all kinds of html tags), so we have to cut the excerpt down a bit at a time until we hit our target length. - while ( $current_excerpt_length > $target_excerpt_length && $current_excerpt_max > 0 ) { - // Trim the excerpt based on wordwrap() positioning. - // Note: we're using
as the linebreak just in case there are any newlines existing in the excerpt from the user. - // There won't be any
left after we've run wp_strip_all_tags() in the code above, so they're - // safe to use here. It won't be included in the final excerpt as the substr() will trim it off. - $excerpt = substr( $excerpt, 0, strpos( wordwrap( $excerpt, $current_excerpt_max, '
' ), '
' ) ); - - // If something went wrong, or we're in a language that wordwrap() doesn't understand, - // just chop it off and don't worry about breaking in the middle of a word. - if ( strlen( $excerpt ) > $excerpt_length - $excerpt_more_len ) { - $excerpt = substr( $excerpt, 0, $current_excerpt_max ); - } - - // Add in the more indicator. - $excerpt = $excerpt . $excerpt_more; - - // Run it through the excerpt filter which will add some html tags back in. - $excerpt_filtered = apply_filters( 'the_excerpt', $excerpt ); - - // Now set the current excerpt length to this new filtered length. - $current_excerpt_length = strlen( $excerpt_filtered ); - - // Check to see if we're over the target length. - if ( $current_excerpt_length > $target_excerpt_length ) { - // If so, remove 20 characters from the current max and run the loop again. - $current_excerpt_max = $current_excerpt_max - 20; - } - } + $excerpt = generate_post_summary( $item, $excerpt_length ); return \apply_filters( 'the_excerpt', $excerpt ); } diff --git a/includes/collection/class-extra-fields.php b/includes/collection/class-extra-fields.php index 6b011b69..6e4aad4b 100644 --- a/includes/collection/class-extra-fields.php +++ b/includes/collection/class-extra-fields.php @@ -37,6 +37,13 @@ class Extra_Fields { return apply_filters( 'activitypub_get_actor_extra_fields', $fields, $user_id ); } + /** + * Transforms the Extra Fields (Cutom Post Types) to ActivityPub Actor-Attachments. + * + * @param \WP_Post[] $fields The extra fields. + * + * @return array ActivityPub attachments. + */ public static function fields_to_attachments( $fields ) { $attachments = array(); \add_filter( @@ -50,7 +57,6 @@ class Extra_Fields { foreach ( $fields as $post ) { $content = \get_the_content( null, false, $post ); - $content = Link::the_content( $content, true ); $content = \do_blocks( $content ); $content = \wptexturize( $content ); $content = \wp_filter_content_tags( $content ); @@ -58,6 +64,7 @@ class Extra_Fields { $content = \preg_replace( '@<(script|style)[^>]*?>.*?@si', '', $content ); $content = \strip_shortcodes( $content ); $content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) ); + $content = \apply_filters( 'activitypub_extra_field_content', $content, $post ); $attachments[] = array( 'type' => 'PropertyValue', diff --git a/includes/functions.php b/includes/functions.php index 473d7570..7624ef20 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -1116,3 +1116,62 @@ function enrich_content_data( $content, $regex, $regex_callback ) { return $content_with_links; } + +/** + * Generate a summary of a post. + * + * This function generates a summary of a post by extracting: + * + * 1. The post excerpt if it exists. + * 2. The first part of the post content if it contains the tag. + * 3. An excerpt of the post content if it is longer than the specified length. + * + * @param int|WP_Post $post The post ID or post object. + * @param integer $length The maximum length of the summary. + * Default is 500. It will ne ignored if the post excerpt + * and the content above the tag. + * + * @return string The generated post summary. + */ +function generate_post_summary( $post, $length = 500 ) { + $post = get_post( $post ); + + if ( ! $post ) { + return ''; + } + + $content = \sanitize_post_field( 'post_excerpt', $post->post_excerpt, $post->ID ); + + if ( $content ) { + return \apply_filters( 'the_excerpt', $content ); + } + + $content = \sanitize_post_field( 'post_content', $post->post_content, $post->ID ); + $content_parts = \get_extended( $content ); + + $excerpt_more = \apply_filters( 'activitypub_excerpt_more', '[…]' ); + $length = $length - strlen( $excerpt_more ); + + // Check for the tag. + if ( + ! empty( $content_parts['extended'] ) && + ! empty( $content_parts['main'] ) + ) { + $content = $content_parts['main'] . ' ' . $excerpt_more; + $length = null; + } + + $content = \html_entity_decode( $content ); + $content = \wp_strip_all_tags( $content ); + $content = \trim( $content ); + $content = \preg_replace( '/\R+/m', "\n\n", $content ); + $content = \preg_replace( '/[\r\t]/', '', $content ); + + if ( $length && \strlen( $content ) > $length ) { + $content = \wordwrap( $content, $length, '' ); + $content = \explode( '', $content, 2 ); + $content = $content[0] . ' ' . $excerpt_more; + } + + return \apply_filters( 'the_excerpt', $content ); +} diff --git a/includes/transformer/class-post.php b/includes/transformer/class-post.php index a274dd7c..7a2c7c14 100644 --- a/includes/transformer/class-post.php +++ b/includes/transformer/class-post.php @@ -10,6 +10,7 @@ use Activitypub\Collection\Users; use function Activitypub\esc_hashtag; use function Activitypub\is_single_user; use function Activitypub\get_enclosures; +use function Activitypub\generate_post_summary; use function Activitypub\get_rest_url_by_path; use function Activitypub\site_supports_blocks; @@ -733,24 +734,7 @@ class Post extends Base { return \__( '(This post is being modified)', 'activitypub' ); } - $content = \get_post_field( 'post_content', $this->wp_object->ID ); - $content = \html_entity_decode( $content ); - $content = \wp_strip_all_tags( $content ); - $content = \trim( $content ); - $content = \preg_replace( '/\R+/m', "\n\n", $content ); - $content = \preg_replace( '/[\r\t]/', '', $content ); - - $excerpt_more = \apply_filters( 'activitypub_excerpt_more', '[...]' ); - $length = 500; - $length = $length - strlen( $excerpt_more ); - - if ( \strlen( $content ) > $length ) { - $content = \wordwrap( $content, $length, '' ); - $content = \explode( '', $content, 2 ); - $content = $content[0]; - } - - return $content . ' ' . $excerpt_more; + return generate_post_summary( $this->wp_object ); } /** @@ -849,7 +833,8 @@ class Post extends Base { $template = "[ap_content]\n\n[ap_permalink type=\"html\"]\n\n[ap_hashtags]"; break; default: - $template = \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT ); + // phpcs:ignore Universal.Operators.DisallowShortTernary.Found + $template = \get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT ) ?: ACTIVITYPUB_CUSTOM_POST_CONTENT; break; } @@ -868,7 +853,12 @@ class Post extends Base { * @return array The list of @-Mentions. */ protected function get_mentions() { - return apply_filters( 'activitypub_extract_mentions', array(), $this->wp_object->post_content, $this->wp_object ); + return apply_filters( + 'activitypub_extract_mentions', + array(), + $this->wp_object->post_content . ' ' . $this->wp_object->post_excerpt, + $this->wp_object + ); } /** diff --git a/tests/test-class-activitypub-shortcodes.php b/tests/test-class-activitypub-shortcodes.php index d3e40703..2db2f2bb 100644 --- a/tests/test-class-activitypub-shortcodes.php +++ b/tests/test-class-activitypub-shortcodes.php @@ -89,7 +89,7 @@ class Test_Activitypub_Shortcodes extends WP_UnitTestCase { $content = do_shortcode( $content ); wp_reset_postdata(); - $this->assertEquals( "

Lorem ipsum […]

\n", $content ); + $this->assertEquals( "

Lorem ipsum dolor […]

\n", $content ); Shortcodes::unregister(); } }