updated plugin ActivityPub
version 2.6.1
This commit is contained in:
@ -94,7 +94,7 @@ class Activity_Dispatcher {
|
||||
* @return void
|
||||
*/
|
||||
public static function send_announce( $wp_object, $type ) {
|
||||
if ( ! in_array( $type, array( 'Create', 'Update' ), true ) ) {
|
||||
if ( ! in_array( $type, array( 'Create', 'Update', 'Delete' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,8 @@ class Activitypub {
|
||||
|
||||
\add_action( 'in_plugin_update_message-' . ACTIVITYPUB_PLUGIN_BASENAME, array( self::class, 'plugin_update_message' ) );
|
||||
|
||||
\add_filter( 'activitypub_get_actor_extra_fields', array( self::class, 'default_actor_extra_fields' ), 10, 2 );
|
||||
|
||||
// register several post_types
|
||||
self::register_post_types();
|
||||
}
|
||||
@ -458,13 +460,43 @@ class Activitypub {
|
||||
)
|
||||
);
|
||||
|
||||
\register_post_type(
|
||||
'ap_extrafield',
|
||||
array(
|
||||
'labels' => array(
|
||||
'name' => _x( 'Extra fields', 'post_type plural name', 'activitypub' ),
|
||||
'singular_name' => _x( 'Extra field', 'post_type single name', 'activitypub' ),
|
||||
'add_new' => __( 'Add new', 'activitypub' ),
|
||||
'add_new_item' => __( 'Add new extra field', 'activitypub' ),
|
||||
'new_item' => __( 'New extra field', 'activitypub' ),
|
||||
'edit_item' => __( 'Edit extra field', 'activitypub' ),
|
||||
'view_item' => __( 'View extra field', 'activitypub' ),
|
||||
'all_items' => __( 'All extra fields', 'activitypub' ),
|
||||
),
|
||||
'public' => false,
|
||||
'hierarchical' => false,
|
||||
'query_var' => false,
|
||||
'has_archive' => false,
|
||||
'publicly_queryable' => false,
|
||||
'show_in_menu' => false,
|
||||
'delete_with_user' => true,
|
||||
'can_export' => true,
|
||||
'exclude_from_search' => true,
|
||||
'show_in_rest' => true,
|
||||
'map_meta_cap' => true,
|
||||
'show_ui' => true,
|
||||
'supports' => array( 'title', 'editor' ),
|
||||
)
|
||||
);
|
||||
|
||||
\do_action( 'activitypub_after_register_post_type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the 'activitypub' query variable so WordPress won't mangle it.
|
||||
* Add the 'activitypub' capability to users who can publish posts.
|
||||
*
|
||||
* @param int $user_id User ID.
|
||||
*
|
||||
* @param array $userdata The raw array of data passed to wp_insert_user().
|
||||
*/
|
||||
public static function user_register( $user_id ) {
|
||||
@ -473,4 +505,57 @@ class Activitypub {
|
||||
$user->add_cap( 'activitypub' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add default extra fields to an actor.
|
||||
*
|
||||
* @param array $extra_fields The extra fields.
|
||||
* @param int $user_id The User-ID.
|
||||
*
|
||||
* @return array The extra fields.
|
||||
*/
|
||||
public static function default_actor_extra_fields( $extra_fields, $user_id ) {
|
||||
if ( $extra_fields || ! $user_id ) {
|
||||
return $extra_fields;
|
||||
}
|
||||
|
||||
$already_migrated = \get_user_meta( $user_id, 'activitypub_default_extra_fields', true );
|
||||
|
||||
if ( $already_migrated ) {
|
||||
return $extra_fields;
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
\__( 'Blog', 'activitypub' ) => \home_url( '/' ),
|
||||
\__( 'Profile', 'activitypub' ) => \get_author_posts_url( $user_id ),
|
||||
\__( 'Homepage', 'activitypub' ) => \get_the_author_meta( 'user_url', $user_id ),
|
||||
);
|
||||
|
||||
foreach ( $defaults as $title => $url ) {
|
||||
if ( ! $url ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extra_field = array(
|
||||
'post_type' => 'ap_extrafield',
|
||||
'post_title' => $title,
|
||||
'post_status' => 'publish',
|
||||
'post_author' => $user_id,
|
||||
'post_content' => sprintf(
|
||||
'<!-- wp:paragraph --><p><a rel="me" title="%s" target="_blank" href="%s">%s</a></p><!-- /wp:paragraph -->',
|
||||
\esc_attr( $url ),
|
||||
$url,
|
||||
\wp_parse_url( $url, \PHP_URL_HOST )
|
||||
),
|
||||
'comment_status' => 'closed',
|
||||
);
|
||||
|
||||
$extra_field_id = wp_insert_post( $extra_field );
|
||||
$extra_fields[] = get_post( $extra_field_id );
|
||||
}
|
||||
|
||||
\update_user_meta( $user_id, 'activitypub_default_extra_fields', true );
|
||||
|
||||
return $extra_fields;
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ namespace Activitypub;
|
||||
|
||||
use WP_User_Query;
|
||||
use Activitypub\Model\Blog;
|
||||
use Activitypub\Activitypub;
|
||||
use Activitypub\Collection\Users;
|
||||
|
||||
use function Activitypub\count_followers;
|
||||
use function Activitypub\is_user_disabled;
|
||||
use function Activitypub\was_comment_received;
|
||||
use function Activitypub\is_comment_federatable;
|
||||
use function Activitypub\add_default_actor_extra_fields;
|
||||
|
||||
/**
|
||||
* ActivityPub Admin Class
|
||||
@ -23,16 +25,21 @@ class Admin {
|
||||
\add_action( 'admin_menu', array( self::class, 'admin_menu' ) );
|
||||
\add_action( 'admin_init', array( self::class, 'register_settings' ) );
|
||||
\add_action( 'load-comment.php', array( self::class, 'edit_comment' ) );
|
||||
\add_action( 'load-post.php', array( self::class, 'edit_post' ) );
|
||||
\add_action( 'load-edit.php', array( self::class, 'list_posts' ) );
|
||||
\add_action( 'personal_options_update', array( self::class, 'save_user_description' ) );
|
||||
\add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_scripts' ) );
|
||||
\add_action( 'admin_notices', array( self::class, 'admin_notices' ) );
|
||||
|
||||
\add_filter( 'comment_row_actions', array( self::class, 'comment_row_actions' ), 10, 2 );
|
||||
\add_filter( 'manage_edit-comments_columns', array( static::class, 'manage_comment_columns' ) );
|
||||
\add_filter( 'manage_comments_custom_column', array( static::class, 'manage_comments_custom_column' ), 9, 2 );
|
||||
\add_action( 'manage_comments_custom_column', array( static::class, 'manage_comments_custom_column' ), 9, 2 );
|
||||
|
||||
\add_filter( 'manage_posts_columns', array( static::class, 'manage_post_columns' ), 10, 2 );
|
||||
\add_action( 'manage_posts_custom_column', array( self::class, 'manage_posts_custom_column' ), 10, 2 );
|
||||
|
||||
\add_filter( 'manage_users_columns', array( self::class, 'manage_users_columns' ), 10, 1 );
|
||||
\add_filter( 'manage_users_custom_column', array( self::class, 'manage_users_custom_column' ), 10, 3 );
|
||||
\add_action( 'manage_users_custom_column', array( self::class, 'manage_users_custom_column' ), 10, 3 );
|
||||
\add_filter( 'bulk_actions-users', array( self::class, 'user_bulk_options' ) );
|
||||
\add_filter( 'handle_bulk_actions-users', array( self::class, 'handle_bulk_request' ), 10, 3 );
|
||||
|
||||
@ -62,6 +69,8 @@ class Admin {
|
||||
$followers_list_page = \add_users_page( \__( 'Followers', 'activitypub' ), \__( 'Followers', 'activitypub' ), 'read', 'activitypub-followers-list', array( self::class, 'followers_list_page' ) );
|
||||
|
||||
\add_action( 'load-' . $followers_list_page, array( self::class, 'add_followers_list_help_tab' ) );
|
||||
|
||||
\add_users_page( \__( 'Extra Fields', 'activitypub' ), \__( 'Extra Fields', 'activitypub' ), 'read', esc_url( admin_url( '/edit.php?post_type=ap_extrafield' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
@ -76,6 +85,16 @@ class Admin {
|
||||
$admin_notice = \__( 'You are using the ActivityPub plugin with a permalink structure of "plain". This will prevent ActivityPub from working. Please go to "Settings" / "Permalinks" and choose a permalink structure other than "plain".', 'activitypub' );
|
||||
self::show_admin_notice( $admin_notice, 'error' );
|
||||
}
|
||||
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( isset( $current_screen->id ) && 'edit-ap_extrafield' === $current_screen->id ) {
|
||||
?>
|
||||
<div class="notice" style="margin: 0; background: none; border: none; box-shadow: none; padding: 15px 0 0 0; font-size: 14px;">
|
||||
<?php esc_html_e( 'These are extra fields that are used for your ActivityPub profile. You can use your homepage, social profiles, pronouns, age, anything you want.', 'activitypub' ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,6 +372,68 @@ class Admin {
|
||||
);
|
||||
}
|
||||
|
||||
public static function edit_post() {
|
||||
// Disable the edit_post capability for federated posts.
|
||||
\add_filter(
|
||||
'user_has_cap',
|
||||
function ( $allcaps, $caps, $arg ) {
|
||||
if ( 'edit_post' !== $arg[0] ) {
|
||||
return $allcaps;
|
||||
}
|
||||
|
||||
$post = get_post( $arg[2] );
|
||||
|
||||
if ( 'ap_extrafield' !== $post->post_type ) {
|
||||
return $allcaps;
|
||||
}
|
||||
|
||||
if ( (int) get_current_user_id() !== (int) $post->post_author ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $allcaps;
|
||||
},
|
||||
1,
|
||||
3
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add ActivityPub specific actions/filters to the post list view
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function list_posts() {
|
||||
// Show only the user's extra fields.
|
||||
\add_action(
|
||||
'pre_get_posts',
|
||||
function ( $query ) {
|
||||
if ( $query->get( 'post_type' ) === 'ap_extrafield' ) {
|
||||
$query->set( 'author', get_current_user_id() );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Remove all views for the extra fields.
|
||||
$screen_id = get_current_screen()->id;
|
||||
|
||||
add_filter(
|
||||
"views_{$screen_id}",
|
||||
function ( $views ) {
|
||||
if ( 'ap_extrafield' === get_post_type() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $views;
|
||||
}
|
||||
);
|
||||
|
||||
// Set defaults for new extra fields.
|
||||
if ( 'edit-ap_extrafield' === $screen_id ) {
|
||||
Activitypub::default_actor_extra_fields( array(), get_current_user_id() );
|
||||
}
|
||||
}
|
||||
|
||||
public static function comment_row_actions( $actions, $comment ) {
|
||||
if ( was_comment_received( $comment ) ) {
|
||||
unset( $actions['edit'] );
|
||||
@ -382,12 +463,28 @@ class Admin {
|
||||
* @param array $columns the list of column names
|
||||
*/
|
||||
public static function manage_comment_columns( $columns ) {
|
||||
$columns['comment_type'] = esc_attr__( 'Comment-Type', 'activitypub' );
|
||||
$columns['comment_type'] = esc_attr__( 'Comment-Type', 'activitypub' );
|
||||
$columns['comment_protocol'] = esc_attr__( 'Protocol', 'activitypub' );
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "post_content" as column for Extra-Fields in WP-Admin
|
||||
*
|
||||
* @param array $columns Tthe list of column names.
|
||||
* @param string $post_type The post type.
|
||||
*/
|
||||
public static function manage_post_columns( $columns, $post_type ) {
|
||||
if ( 'ap_extrafield' === $post_type ) {
|
||||
$after_key = 'title';
|
||||
$index = array_search( $after_key, array_keys( $columns ), true );
|
||||
$columns = array_slice( $columns, 0, $index + 1 ) + array( 'extra_field_content' => esc_attr__( 'Content', 'activitypub' ) ) + $columns;
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add "comment-type" and "protocol" as column in WP-Admin
|
||||
*
|
||||
@ -423,9 +520,28 @@ class Admin {
|
||||
}
|
||||
|
||||
if ( \user_can( $user_id, 'activitypub' ) ) {
|
||||
return '✓';
|
||||
return '<span aria-hidden="true">✓</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub enabled for this author', 'activitypub' ) . '</span>';
|
||||
} else {
|
||||
return '✗';
|
||||
return '<span aria-hidden="true">✗</span><span class="screen-reader-text">' . esc_html__( 'ActivityPub disabled for this author', 'activitypub' ) . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a column "extra_field_content" to the post list view
|
||||
*
|
||||
* @param string $column_name The column name.
|
||||
* @param int $post_id The post ID.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function manage_posts_custom_column( $column_name, $post_id ) {
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if ( 'extra_field_content' === $column_name ) {
|
||||
$post = get_post( $post_id );
|
||||
if ( 'ap_extrafield' === $post->post_type ) {
|
||||
echo esc_attr( wp_strip_all_tags( $post->post_content ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,7 +241,7 @@ class Comment {
|
||||
*
|
||||
* @param string $id ActivityPub object ID (usually a URL) to check.
|
||||
*
|
||||
* @return int|boolean Comment ID, or false on failure.
|
||||
* @return \WP_Comment|false Comment object, or false on failure.
|
||||
*/
|
||||
public static function object_id_to_comment( $id ) {
|
||||
$comment_query = new WP_Comment_Query(
|
||||
|
@ -118,7 +118,7 @@ class Migration {
|
||||
|
||||
// schedule the async migration
|
||||
if ( ! \wp_next_scheduled( 'activitypub_migrate', $version_from_db ) ) {
|
||||
\wp_schedule_single_event( \time(), 'activitypub_migrate', $version_from_db );
|
||||
\wp_schedule_single_event( \time(), 'activitypub_migrate', array( $version_from_db ) );
|
||||
}
|
||||
if ( version_compare( $version_from_db, '0.17.0', '<' ) ) {
|
||||
self::migrate_from_0_16();
|
||||
|
@ -117,6 +117,11 @@ class Scheduler {
|
||||
public static function schedule_post_activity( $new_status, $old_status, $post ) {
|
||||
$post = get_post( $post );
|
||||
|
||||
if ( 'ap_extrafield' === $post->post_type ) {
|
||||
self::schedule_profile_update( $post->post_author );
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not send activities if post is password protected.
|
||||
if ( \post_password_required( $post ) ) {
|
||||
return;
|
||||
@ -130,9 +135,16 @@ class Scheduler {
|
||||
|
||||
$type = false;
|
||||
|
||||
if ( 'publish' === $new_status && 'publish' !== $old_status ) {
|
||||
if (
|
||||
'publish' === $new_status &&
|
||||
'publish' !== $old_status
|
||||
) {
|
||||
$type = 'Create';
|
||||
} elseif ( 'publish' === $new_status ) {
|
||||
} elseif (
|
||||
'publish' === $new_status ||
|
||||
( 'draft' === $new_status &&
|
||||
'draft' !== $old_status )
|
||||
) {
|
||||
$type = 'Update';
|
||||
} elseif ( 'trash' === $new_status ) {
|
||||
$type = 'Delete';
|
||||
@ -311,7 +323,9 @@ class Scheduler {
|
||||
|
||||
/**
|
||||
* Theme mods only have a dynamic filter so we fudge it like this.
|
||||
* @param mixed $value
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function blog_user_update( $value = null ) {
|
||||
@ -321,6 +335,7 @@ class Scheduler {
|
||||
|
||||
/**
|
||||
* Send a profile update to all followers. Gets hooked into all relevant options/meta etc.
|
||||
*
|
||||
* @param int $user_id The user ID to update (Could be 0 for Blog-User).
|
||||
*/
|
||||
public static function schedule_profile_update( $user_id ) {
|
||||
|
@ -46,7 +46,10 @@ class Webfinger {
|
||||
return new WP_Error(
|
||||
'webfinger_missing_links',
|
||||
__( 'No valid Link elements found.', 'activitypub' ),
|
||||
$data
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -65,7 +68,10 @@ class Webfinger {
|
||||
return new WP_Error(
|
||||
'webfinger_url_no_activitypub',
|
||||
__( 'The Site supports WebFinger but not ActivityPub', 'activitypub' ),
|
||||
$data
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -103,7 +109,10 @@ class Webfinger {
|
||||
return new WP_Error(
|
||||
'webfinger_url_no_acct',
|
||||
__( 'No acct URI found.', 'activitypub' ),
|
||||
$data
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -117,6 +126,17 @@ class Webfinger {
|
||||
* identifier and host as values
|
||||
*/
|
||||
public static function get_identifier_and_host( $url ) {
|
||||
if ( ! $url ) {
|
||||
return new WP_Error(
|
||||
'webfinger_invalid_identifier',
|
||||
__( 'Invalid Identifier', 'activitypub' ),
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $url,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// remove leading @
|
||||
$url = ltrim( $url, '@' );
|
||||
|
||||
@ -144,7 +164,14 @@ class Webfinger {
|
||||
}
|
||||
|
||||
if ( empty( $host ) ) {
|
||||
return new WP_Error( 'webfinger_invalid_identifier', __( 'Invalid Identifier', 'activitypub' ) );
|
||||
return new WP_Error(
|
||||
'webfinger_invalid_identifier',
|
||||
__( 'Invalid Identifier', 'activitypub' ),
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $url,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return array( $identifier, $host );
|
||||
@ -174,7 +201,7 @@ class Webfinger {
|
||||
return $data;
|
||||
}
|
||||
|
||||
$webfinger_url = 'https://' . $host . '/.well-known/webfinger?resource=' . rawurlencode( $identifier );
|
||||
$webfinger_url = sprintf( 'https://%s/.well-known/webfinger?resource=%s', $host, rawurlencode( $identifier ) );
|
||||
|
||||
$response = wp_safe_remote_get(
|
||||
$webfinger_url,
|
||||
@ -187,7 +214,10 @@ class Webfinger {
|
||||
return new WP_Error(
|
||||
'webfinger_url_not_accessible',
|
||||
__( 'The WebFinger Resource is not accessible.', 'activitypub' ),
|
||||
$webfinger_url
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $webfinger_url,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -215,7 +245,10 @@ class Webfinger {
|
||||
return new WP_Error(
|
||||
'webfinger_missing_links',
|
||||
__( 'No valid Link elements found.', 'activitypub' ),
|
||||
$data
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -228,7 +261,10 @@ class Webfinger {
|
||||
return new WP_Error(
|
||||
'webfinger_missing_remote_follow_endpoint',
|
||||
__( 'No valid Remote-Follow endpoint found.', 'activitypub' ),
|
||||
$data
|
||||
array(
|
||||
'status' => 400,
|
||||
'data' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -54,10 +54,12 @@ class Interactions {
|
||||
return false;
|
||||
}
|
||||
|
||||
$url = object_to_uri( $meta['url'] );
|
||||
|
||||
$commentdata = array(
|
||||
'comment_post_ID' => $comment_post_id,
|
||||
'comment_author' => isset( $meta['name'] ) ? \esc_attr( $meta['name'] ) : \esc_attr( $meta['preferredUsername'] ),
|
||||
'comment_author_url' => \esc_url_raw( $meta['url'] ),
|
||||
'comment_author_url' => \esc_url_raw( $url ),
|
||||
'comment_content' => \addslashes( $activity['object']['content'] ),
|
||||
'comment_type' => 'comment',
|
||||
'comment_author_email' => '',
|
||||
@ -73,7 +75,7 @@ class Interactions {
|
||||
}
|
||||
|
||||
if ( isset( $activity['object']['url'] ) ) {
|
||||
$commentdata['comment_meta']['source_url'] = \esc_url_raw( $activity['object']['url'] );
|
||||
$commentdata['comment_meta']['source_url'] = \esc_url_raw( object_to_uri( $activity['object']['url'] ) );
|
||||
}
|
||||
|
||||
// disable flood control
|
||||
@ -198,7 +200,7 @@ class Interactions {
|
||||
|
||||
// get URL, because $actor seems to be the ID
|
||||
if ( $meta && ! is_wp_error( $meta ) && isset( $meta['url'] ) ) {
|
||||
$actor = $meta['url'];
|
||||
$actor = object_to_uri( $meta['url'] );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
|
@ -8,6 +8,8 @@ use Activitypub\Model\Blog;
|
||||
use Activitypub\Model\Application;
|
||||
|
||||
use function Activitypub\object_to_uri;
|
||||
use function Activitypub\normalize_url;
|
||||
use function Activitypub\normalize_host;
|
||||
use function Activitypub\url_to_authorid;
|
||||
use function Activitypub\is_user_disabled;
|
||||
|
||||
@ -80,12 +82,13 @@ class Users {
|
||||
|
||||
// check for application user.
|
||||
if ( 'application' === $username ) {
|
||||
return self::get_by_id( self::APPLICATION_USER_ID );
|
||||
return new Application();
|
||||
}
|
||||
|
||||
// check for 'activitypub_username' meta
|
||||
$user = new WP_User_Query(
|
||||
array(
|
||||
'count_total' => false,
|
||||
'number' => 1,
|
||||
'hide_empty' => true,
|
||||
'fields' => 'ID',
|
||||
@ -110,6 +113,7 @@ class Users {
|
||||
// check for login or nicename.
|
||||
$user = new WP_User_Query(
|
||||
array(
|
||||
'count_total' => false,
|
||||
'search' => $username,
|
||||
'search_columns' => array( 'user_login', 'user_nicename' ),
|
||||
'number' => 1,
|
||||
@ -180,8 +184,8 @@ class Users {
|
||||
|
||||
// check for http(s)://blog.example.com/
|
||||
if (
|
||||
self::normalize_url( site_url() ) === self::normalize_url( $resource ) ||
|
||||
self::normalize_url( home_url() ) === self::normalize_url( $resource )
|
||||
normalize_url( site_url() ) === normalize_url( $resource ) ||
|
||||
normalize_url( home_url() ) === normalize_url( $resource )
|
||||
) {
|
||||
return self::get_by_id( self::BLOG_USER_ID );
|
||||
}
|
||||
@ -195,8 +199,8 @@ class Users {
|
||||
case 'acct':
|
||||
$resource = \str_replace( 'acct:', '', $resource );
|
||||
$identifier = \substr( $resource, 0, \strrpos( $resource, '@' ) );
|
||||
$host = self::normalize_host( \substr( \strrchr( $resource, '@' ), 1 ) );
|
||||
$blog_host = self::normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
|
||||
$host = normalize_host( \substr( \strrchr( $resource, '@' ), 1 ) );
|
||||
$blog_host = normalize_host( \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) );
|
||||
|
||||
if ( $blog_host !== $host ) {
|
||||
return new WP_Error(
|
||||
@ -251,33 +255,6 @@ class Users {
|
||||
return self::get_by_username( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a host.
|
||||
*
|
||||
* @param string $host The host.
|
||||
*
|
||||
* @return string The normalized host.
|
||||
*/
|
||||
public static function normalize_host( $host ) {
|
||||
return \str_replace( 'www.', '', $host );
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a URL.
|
||||
*
|
||||
* @param string $url The URL.
|
||||
*
|
||||
* @return string The normalized URL.
|
||||
*/
|
||||
public static function normalize_url( $url ) {
|
||||
$url = \untrailingslashit( $url );
|
||||
$url = \str_replace( 'https://', '', $url );
|
||||
$url = \str_replace( 'http://', '', $url );
|
||||
$url = \str_replace( 'www.', '', $url );
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the User collection.
|
||||
*
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
namespace Activitypub;
|
||||
|
||||
use WP_Query;
|
||||
use WP_Error;
|
||||
use Activitypub\Http;
|
||||
use Activitypub\Comment;
|
||||
@ -794,6 +795,7 @@ function is_local_comment( $comment ) {
|
||||
* Mark a WordPress object as federated.
|
||||
*
|
||||
* @param WP_Comment|WP_Post|mixed $wp_object
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function set_wp_object_state( $wp_object, $state ) {
|
||||
@ -808,6 +810,25 @@ function set_wp_object_state( $wp_object, $state ) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the federation state of a WordPress object.
|
||||
*
|
||||
* @param WP_Comment|WP_Post|mixed $wp_object
|
||||
*
|
||||
* @return string|false The state of the object or false if not found.
|
||||
*/
|
||||
function get_wp_object_state( $wp_object ) {
|
||||
$meta_key = 'activitypub_status';
|
||||
|
||||
if ( $wp_object instanceof \WP_Post ) {
|
||||
return \get_post_meta( $wp_object->ID, $meta_key, true );
|
||||
} elseif ( $wp_object instanceof \WP_Comment ) {
|
||||
return \get_comment_meta( $wp_object->comment_ID, $meta_key, true );
|
||||
} else {
|
||||
return \apply_filters( 'activitypub_get_wp_object_state', false, $wp_object );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the description of a post type.
|
||||
*
|
||||
@ -969,3 +990,56 @@ function custom_large_numbers( $formatted, $number, $decimals ) {
|
||||
// Default fallback. We should not get here.
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a URL.
|
||||
*
|
||||
* @param string $url The URL.
|
||||
*
|
||||
* @return string The normalized URL.
|
||||
*/
|
||||
function normalize_url( $url ) {
|
||||
$url = \untrailingslashit( $url );
|
||||
$url = \str_replace( 'https://', '', $url );
|
||||
$url = \str_replace( 'http://', '', $url );
|
||||
$url = \str_replace( 'www.', '', $url );
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a host.
|
||||
*
|
||||
* @param string $host The host.
|
||||
*
|
||||
* @return string The normalized host.
|
||||
*/
|
||||
function normalize_host( $host ) {
|
||||
return \str_replace( 'www.', '', $host );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Extra Fields of an Actor
|
||||
*
|
||||
* @param int $user_id The User-ID.
|
||||
*
|
||||
* @return array The extra fields.
|
||||
*/
|
||||
function get_actor_extra_fields( $user_id ) {
|
||||
$extra_fields = new WP_Query(
|
||||
array(
|
||||
'post_type' => 'ap_extrafield',
|
||||
'nopaging' => true,
|
||||
'status' => 'publish',
|
||||
'author' => $user_id,
|
||||
)
|
||||
);
|
||||
|
||||
if ( $extra_fields->have_posts() ) {
|
||||
$extra_fields = $extra_fields->posts;
|
||||
} else {
|
||||
$extra_fields = array();
|
||||
}
|
||||
|
||||
return apply_filters( 'activitypub_get_actor_extra_fields', $extra_fields, $user_id );
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ class Create {
|
||||
$state = Interactions::add_comment( $array );
|
||||
$reaction = null;
|
||||
|
||||
if ( $state && ! \is_wp_error( $reaction ) ) {
|
||||
if ( $state && ! \is_wp_error( $state ) ) {
|
||||
$reaction = \get_comment( $state );
|
||||
}
|
||||
|
||||
|
@ -197,4 +197,8 @@ class Application extends Actor {
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function get_canonical_url() {
|
||||
return \home_url();
|
||||
}
|
||||
}
|
||||
|
@ -230,7 +230,7 @@ class Blog extends Actor {
|
||||
*
|
||||
* @return array|null The User-Header-Image.
|
||||
*/
|
||||
public function get_header_image() {
|
||||
public function get_image() {
|
||||
if ( \has_header_image() ) {
|
||||
return array(
|
||||
'type' => 'Image',
|
||||
@ -368,4 +368,38 @@ class Blog extends Actor {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend the User-Output with Attachments.
|
||||
*
|
||||
* @return array The extended User-Output.
|
||||
*/
|
||||
public function get_attachment() {
|
||||
$array = array();
|
||||
|
||||
$array[] = array(
|
||||
'type' => 'PropertyValue',
|
||||
'name' => \__( 'Blog', 'activitypub' ),
|
||||
'value' => \html_entity_decode(
|
||||
sprintf(
|
||||
'<a rel="me" title="%s" target="_blank" href="%s">%s</a>',
|
||||
\esc_attr( \home_url( '/' ) ),
|
||||
\esc_url( \home_url( '/' ) ),
|
||||
\wp_parse_url( \home_url( '/' ), \PHP_URL_HOST )
|
||||
),
|
||||
\ENT_QUOTES,
|
||||
'UTF-8'
|
||||
),
|
||||
);
|
||||
|
||||
// Add support for FEP-fb2a, for more information see FEDERATION.md
|
||||
$array[] = array(
|
||||
'type' => 'Link',
|
||||
'name' => \__( 'Blog', 'activitypub' ),
|
||||
'href' => \esc_url( \home_url( '/' ) ),
|
||||
'rel' => array( 'me' ),
|
||||
);
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ namespace Activitypub\Model;
|
||||
|
||||
use WP_Query;
|
||||
use WP_Error;
|
||||
use Activitypub\Migration;
|
||||
use Activitypub\Signature;
|
||||
use Activitypub\Model\Blog;
|
||||
use Activitypub\Activity\Actor;
|
||||
@ -10,6 +11,7 @@ use Activitypub\Collection\Users;
|
||||
|
||||
use function Activitypub\is_user_disabled;
|
||||
use function Activitypub\get_rest_url_by_path;
|
||||
use function Activitypub\get_actor_extra_fields;
|
||||
|
||||
class User extends Actor {
|
||||
/**
|
||||
@ -233,41 +235,74 @@ class User extends Actor {
|
||||
* @return array The extended User-Output.
|
||||
*/
|
||||
public function get_attachment() {
|
||||
$array = array();
|
||||
$extra_fields = get_actor_extra_fields( $this->_id );
|
||||
|
||||
$array[] = array(
|
||||
'type' => 'PropertyValue',
|
||||
'name' => \__( 'Blog', 'activitypub' ),
|
||||
'value' => \html_entity_decode(
|
||||
'<a rel="me" title="' . \esc_attr( \home_url( '/' ) ) . '" target="_blank" href="' . \home_url( '/' ) . '">' . \wp_parse_url( \home_url( '/' ), \PHP_URL_HOST ) . '</a>',
|
||||
\ENT_QUOTES,
|
||||
'UTF-8'
|
||||
),
|
||||
);
|
||||
$attachments = array();
|
||||
|
||||
$array[] = array(
|
||||
'type' => 'PropertyValue',
|
||||
'name' => \__( 'Profile', 'activitypub' ),
|
||||
'value' => \html_entity_decode(
|
||||
'<a rel="me" title="' . \esc_attr( \get_author_posts_url( $this->get__id() ) ) . '" target="_blank" href="' . \get_author_posts_url( $this->get__id() ) . '">' . \wp_parse_url( \get_author_posts_url( $this->get__id() ), \PHP_URL_HOST ) . '</a>',
|
||||
\ENT_QUOTES,
|
||||
'UTF-8'
|
||||
),
|
||||
);
|
||||
foreach ( $extra_fields as $post ) {
|
||||
$content = \get_the_content( null, false, $post );
|
||||
$content = \make_clickable( $content );
|
||||
$content = \do_blocks( $content );
|
||||
$content = \wptexturize( $content );
|
||||
$content = \wp_filter_content_tags( $content );
|
||||
// replace script and style elements
|
||||
$content = \preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $content );
|
||||
$content = \strip_shortcodes( $content );
|
||||
$content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) );
|
||||
|
||||
if ( \get_the_author_meta( 'user_url', $this->get__id() ) ) {
|
||||
$array[] = array(
|
||||
$attachments[] = array(
|
||||
'type' => 'PropertyValue',
|
||||
'name' => \__( 'Website', 'activitypub' ),
|
||||
'name' => \get_the_title( $post ),
|
||||
'value' => \html_entity_decode(
|
||||
'<a rel="me" title="' . \esc_attr( \get_the_author_meta( 'user_url', $this->get__id() ) ) . '" target="_blank" href="' . \get_the_author_meta( 'user_url', $this->get__id() ) . '">' . \wp_parse_url( \get_the_author_meta( 'user_url', $this->get__id() ), \PHP_URL_HOST ) . '</a>',
|
||||
$content,
|
||||
\ENT_QUOTES,
|
||||
'UTF-8'
|
||||
),
|
||||
);
|
||||
|
||||
$link_added = false;
|
||||
|
||||
// Add support for FEP-fb2a, for more information see FEDERATION.md
|
||||
if ( \class_exists( '\WP_HTML_Tag_Processor' ) ) {
|
||||
$tags = new \WP_HTML_Tag_Processor( $content );
|
||||
$tags->next_tag();
|
||||
|
||||
if ( 'P' === $tags->get_tag() ) {
|
||||
$tags->next_tag();
|
||||
}
|
||||
|
||||
if ( 'A' === $tags->get_tag() ) {
|
||||
$tags->set_bookmark( 'link' );
|
||||
if ( ! $tags->next_tag() ) {
|
||||
$tags->seek( 'link' );
|
||||
$attachment = array(
|
||||
'type' => 'Link',
|
||||
'name' => \get_the_title( $post ),
|
||||
'href' => \esc_url( $tags->get_attribute( 'href' ) ),
|
||||
'rel' => explode( ' ', $tags->get_attribute( 'rel' ) ),
|
||||
);
|
||||
|
||||
$link_added = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $link_added ) {
|
||||
$attachment = array(
|
||||
'type' => 'Note',
|
||||
'name' => \get_the_title( $post ),
|
||||
'content' => \html_entity_decode(
|
||||
$content,
|
||||
\ENT_QUOTES,
|
||||
'UTF-8'
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$attachments[] = $attachment;
|
||||
}
|
||||
|
||||
return $array;
|
||||
return $attachments;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,7 +123,7 @@ class Actors {
|
||||
$url = str_replace( '{uri}', $resource, $template );
|
||||
|
||||
return new WP_REST_Response(
|
||||
array( 'url' => $url ),
|
||||
array( 'url' => $url, 'template' => $template ),
|
||||
200
|
||||
);
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ class Comment {
|
||||
public static function register_routes() {
|
||||
\register_rest_route(
|
||||
ACTIVITYPUB_REST_NAMESPACE,
|
||||
'/(users|actors)/(?P<comment_id>\d+)/remote-reply',
|
||||
'/comments/(?P<comment_id>\d+)/remote-reply',
|
||||
array(
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
@ -88,7 +88,7 @@ class Comment {
|
||||
$url = str_replace( '{uri}', $resource, $template );
|
||||
|
||||
return new WP_REST_Response(
|
||||
array( 'url' => $url ),
|
||||
array( 'url' => $url, 'template' => $template ),
|
||||
200
|
||||
);
|
||||
}
|
||||
|
@ -55,10 +55,28 @@ class Webfinger {
|
||||
*/
|
||||
\do_action( 'activitypub_rest_webfinger_pre' );
|
||||
|
||||
$code = 200;
|
||||
|
||||
$resource = $request->get_param( 'resource' );
|
||||
$response = self::get_profile( $resource );
|
||||
|
||||
return new WP_REST_Response( $response, 200 );
|
||||
if ( \is_wp_error( $response ) ) {
|
||||
$code = 400;
|
||||
$error_data = $response->get_error_data();
|
||||
|
||||
if ( isset( $error_data['status'] ) ) {
|
||||
$code = $error_data['status'];
|
||||
}
|
||||
}
|
||||
|
||||
return new WP_REST_Response(
|
||||
$response,
|
||||
$code,
|
||||
array(
|
||||
'Access-Control-Allow-Origin' => '*',
|
||||
'Content-Type' => 'application/jrd+json; charset=' . get_option( 'blog_charset' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -88,7 +106,7 @@ class Webfinger {
|
||||
public static function get_profile( $resource ) {
|
||||
$user = User_Collection::get_by_resource( $resource );
|
||||
|
||||
if ( is_wp_error( $user ) ) {
|
||||
if ( \is_wp_error( $user ) ) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,9 @@ class Post extends Base {
|
||||
|
||||
if ( 'trash' === get_post_status( $post ) ) {
|
||||
$permalink = \get_post_meta( $post->ID, 'activitypub_canonical_url', true );
|
||||
} elseif ( 'draft' === get_post_status( $post ) && get_sample_permalink( $post->ID ) ) {
|
||||
$sample = get_sample_permalink( $post->ID );
|
||||
$permalink = str_replace( array( '%pagename%', '%postname%' ), $sample[1], $sample[0] );
|
||||
} else {
|
||||
$permalink = \get_permalink( $post );
|
||||
}
|
||||
@ -137,6 +140,11 @@ class Post extends Base {
|
||||
* @return array The Attachments.
|
||||
*/
|
||||
protected function get_attachment() {
|
||||
// Remove attachments from drafts.
|
||||
if ( 'draft' === \get_post_status( $this->wp_object ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// 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(
|
||||
@ -692,6 +700,11 @@ class Post extends Base {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove Teaser from drafts.
|
||||
if ( 'draft' === \get_post_status( $this->wp_object ) ) {
|
||||
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 );
|
||||
@ -746,6 +759,11 @@ class Post extends Base {
|
||||
* @return string The content.
|
||||
*/
|
||||
protected function get_content() {
|
||||
// Remove Content from drafts.
|
||||
if ( 'draft' === \get_post_status( $this->wp_object ) ) {
|
||||
return \__( '(This post is being modified)', 'activitypub' );
|
||||
}
|
||||
|
||||
global $post;
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user