id === 'settings_page_activitypub' ) {
$this->user_id = Actors::BLOG_USER_ID;
} else {
$this->user_id = \get_current_user_id();
\add_action( 'admin_notices', array( $this, 'process_admin_notices' ) );
}
parent::__construct(
array(
'singular' => \__( 'Blocked Actor', 'activitypub' ),
'plural' => \__( 'Blocked Actors', 'activitypub' ),
'ajax' => false,
)
);
\add_action( 'load-' . \get_current_screen()->id, array( $this, 'process_action' ), 20 );
}
/**
* Process action.
*
* @return void
*/
public function process_action() {
if ( ! \current_user_can( 'edit_user', $this->user_id ) ) {
return;
}
if ( ! $this->current_action() ) {
return;
}
$redirect_to = \add_query_arg(
array(
'settings-updated' => true, // Tell WordPress to load settings errors transient.
'action' => false, // Remove action parameter to prevent redirect loop.
)
);
switch ( $this->current_action() ) {
case 'delete':
$redirect_to = \remove_query_arg( array( 'follower', 'blocked' ), $redirect_to );
// Handle single actor unblock.
if ( isset( $_GET['follower'], $_GET['_wpnonce'] ) ) {
$actor_id = \absint( $_GET['follower'] );
$nonce = \sanitize_text_field( \wp_unslash( $_GET['_wpnonce'] ) );
if ( \wp_verify_nonce( $nonce, 'delete-follower_' . $actor_id ) ) {
Moderation::remove_user_block( $this->user_id, Moderation::TYPE_ACTOR, $actor_id );
\add_settings_error( 'activitypub', 'actor_unblocked', \__( 'Actor unblocked.', 'activitypub' ), 'success' );
}
}
// Handle bulk actions.
if ( isset( $_REQUEST['blocked'], $_REQUEST['_wpnonce'] ) ) {
$nonce = \sanitize_text_field( \wp_unslash( $_REQUEST['_wpnonce'] ) );
if ( \wp_verify_nonce( $nonce, 'bulk-' . $this->_args['plural'] ) ) {
$blocked = \array_map( 'absint', \wp_unslash( $_REQUEST['blocked'] ) );
foreach ( $blocked as $post_id ) {
Moderation::remove_user_block( $this->user_id, Moderation::TYPE_ACTOR, $post_id );
}
$count = \count( $blocked );
/* translators: %d: Number of actors unblocked. */
$message = \_n( '%d actor unblocked.', '%d actors unblocked.', $count, 'activitypub' );
$message = \sprintf( $message, \number_format_i18n( $count ) );
\add_settings_error( 'activitypub', 'actors_unblocked', $message, 'success' );
}
}
break;
case 'block':
$redirect_to = \remove_query_arg( array( 'resource', 's' ), $redirect_to );
if ( ! isset( $_REQUEST['activitypub-profile'], $_REQUEST['_wpnonce'] ) ) {
return;
}
$nonce = \sanitize_text_field( \wp_unslash( $_REQUEST['_wpnonce'] ) );
if ( ! \wp_verify_nonce( $nonce, 'activitypub-block-nonce' ) ) {
return;
}
$original = \sanitize_text_field( \wp_unslash( $_REQUEST['activitypub-profile'] ) );
$profile = Remote_Actors::normalize_identifier( $original );
if ( ! $profile ) {
/* translators: %s: Account profile that could not be blocked */
\add_settings_error( 'activitypub', 'blocked', \sprintf( \__( 'Unable to block actor “%s”. Please verify the account exists and try again.', 'activitypub' ), \esc_html( $original ) ) );
$redirect_to = \add_query_arg( 'resource', $original, $redirect_to );
break;
}
$result = Moderation::add_user_block( $this->user_id, Moderation::TYPE_ACTOR, $profile );
if ( \is_wp_error( $result ) ) {
/* translators: %s: Account profile that could not be blocked */
\add_settings_error( 'activitypub', 'blocked', \sprintf( \__( 'Unable to block actor “%s”. Please verify the account exists and try again.', 'activitypub' ), \esc_html( $original ) ) );
$redirect_to = \add_query_arg( 'resource', $original, $redirect_to );
} else {
\add_settings_error( 'activitypub', 'blocked', \__( 'Actor blocked.', 'activitypub' ), 'success' );
}
break;
default:
break;
}
\set_transient( 'settings_errors', \get_settings_errors(), 30 ); // 30 seconds.
\wp_safe_redirect( $redirect_to );
exit;
}
/**
* Process admin notices based on query parameters.
*
* @return void
*/
public function process_admin_notices() {
\settings_errors( 'activitypub' );
}
/**
* Prepare items.
*
* @return void
*/
public function prepare_items() {
$page_num = $this->get_pagenum();
$per_page = $this->get_items_per_page( 'activitypub_blocked_actors_per_page' );
$args = array();
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( isset( $_GET['orderby'] ) ) {
$args['orderby'] = \sanitize_text_field( \wp_unslash( $_GET['orderby'] ) );
}
if ( isset( $_GET['order'] ) ) {
$args['order'] = \sanitize_text_field( \wp_unslash( $_GET['order'] ) );
}
if ( isset( $_GET['s'] ) ) {
$args['s'] = $this->normalize_search_term( \wp_unslash( $_GET['s'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
}
$blocked_with_count = Blocked_Actors_Collection::query( $this->user_id, $per_page, $page_num, $args );
$blocked_actor_posts = $blocked_with_count['blocked_actors'];
$counter = $blocked_with_count['total'];
$this->items = array();
$this->set_pagination_args(
array(
'total_items' => (int) $counter,
'total_pages' => (int) \ceil( $counter / $per_page ),
'per_page' => $per_page,
)
);
foreach ( $blocked_actor_posts as $blocked_actor_post ) {
$actor = Remote_Actors::get_actor( $blocked_actor_post );
if ( \is_wp_error( $actor ) ) {
continue;
}
$this->items[] = array(
'id' => $blocked_actor_post->ID,
'icon' => object_to_uri( $actor->get_icon() ?? ACTIVITYPUB_PLUGIN_URL . 'assets/img/mp.jpg' ),
'post_title' => $actor->get_name() ?: $actor->get_preferred_username(),
'username' => $actor->get_preferred_username(),
'url' => object_to_uri( $actor->get_url() ?: $actor->get_id() ),
'webfinger' => $actor->get_webfinger(),
'identifier' => $actor->get_id(),
'modified' => $blocked_actor_post->post_modified_gmt,
);
}
}
/**
* Returns bulk actions.
*
* @return array
*/
public function get_bulk_actions() {
return array(
'delete' => \__( 'Unblock', 'activitypub' ),
);
}
/**
* Column checkbox.
*
* @param array $item Item.
* @return string
*/
public function column_cb( $item ) {
return \sprintf( '', \esc_attr( $item['id'] ) );
}
/**
* Column username.
*
* @param array $item Item.
* @return string
*/
public function column_username( $item ) {
return \sprintf(
' %4$s
',
\esc_url( $item['icon'] ),
\esc_attr( $item['post_title'] ),
\esc_url( $item['url'] ),
\esc_html( $item['username'] )
);
}
/**
* Column WebFinger.
*
* @param array $item Item.
*
* @return string The WebFinger link.
*/
public function column_webfinger( $item ) {
$webfinger = Sanitize::webfinger( $item['webfinger'] );
return \sprintf(
'@%2$s',
\esc_url( $item['url'] ),
\esc_html( $webfinger )
);
}
/**
* Column modified.
*
* @param array $item Item.
* @return string
*/
public function column_modified( $item ) {
$modified = \strtotime( $item['modified'] );
return \sprintf(
'',
\esc_attr( \gmdate( 'c', $modified ) ),
\esc_html( \gmdate( \get_option( 'date_format' ), $modified ) )
);
}
/**
* Message to be displayed when there are no blocked actors.
*
* @return void
*/
public function no_items() {
\esc_html_e( 'No blocked actors found.', 'activitypub' );
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$search = \sanitize_text_field( \wp_unslash( $_GET['s'] ?? '' ) );
if ( empty( $search ) ) {
return;
}
$search = Sanitize::webfinger( $search );
if ( \filter_var( $search, FILTER_VALIDATE_EMAIL ) ) {
return;
}
$search = Webfinger::resolve( $search );
if ( ! \is_wp_error( $search ) && \filter_var( $search, FILTER_VALIDATE_URL ) ) {
$actor = Remote_Actors::fetch_by_uri( $search );
if ( ! \is_wp_error( $actor ) ) {
echo ' ';
\printf(
/* translators: %s: Actor name. */
\esc_html__( 'Would you like to block %s?', 'activitypub' ),
\sprintf(
'%s',
\esc_url( \add_query_arg( 'resource', $search ) ),
\esc_html( $actor->post_title )
)
);
}
}
}
/**
* Single row.
*
* @param array $item Item.
*
* @return void
*/
public function single_row( $item ) {
\printf(
'