Files
laipower/wp-content/plugins/activitypub/includes/handler/outbox/class-arrive.php

188 lines
5.2 KiB
PHP

<?php
/**
* Outbox Arrive handler file.
*
* @package Activitypub
*/
namespace Activitypub\Handler\Outbox;
use Activitypub\Collection\Posts;
use function Activitypub\add_to_outbox;
use function Activitypub\is_activity_public;
/**
* Handle outgoing Arrive activities.
*
* @since 8.1.0
*/
class Arrive {
/**
* Initialize the class, registering WordPress hooks.
*
* @since 8.1.0
*/
public static function init() {
\add_filter( 'activitypub_outbox_arrive', array( self::class, 'handle_arrive' ), 10, 3 );
}
/**
* Handle outgoing "Arrive" activities from local actors.
*
* Arrive is an intransitive activity (no object) indicating that
* the actor has arrived at a location. Per the ActivityPub spec,
* the server must preserve the original activity type, so this
* handler adds the Arrive directly to the outbox as-is.
*
* As a local side effect, a WordPress post is created so the
* check-in appears on the blog with location geodata.
*
* @since 8.1.0
*
* @param array $data The activity data array.
* @param int $user_id The user ID.
* @param string|null $visibility Content visibility.
*
* @return int|\WP_Error|false The outbox post ID, error, or false.
*/
public static function handle_arrive( $data, $user_id = null, $visibility = null ) {
// Create a blog post for public check-ins so they appear on the site.
if ( is_activity_public( $data ) ) {
$post = self::create_checkin_post( $data, $user_id, $visibility );
if ( ! \is_wp_error( $post ) ) {
$data['url'] = \get_permalink( $post );
}
}
/*
* Add the original Arrive activity to the outbox directly.
* This preserves the intransitive activity type per the
* ActivityPub spec (Section 6) instead of wrapping it in Create.
*/
$outbox_id = add_to_outbox( $data, null, $user_id, $visibility );
if ( ! $outbox_id ) {
return new \WP_Error(
'activitypub_outbox_error',
\__( 'Failed to add Arrive activity to outbox.', 'activitypub' ),
array( 'status' => 500 )
);
}
return $outbox_id;
}
/**
* Create a WordPress post from the Arrive activity.
*
* Creates a blog post with the check-in content and saves
* location geodata so it can be displayed on the site.
*
* @since 8.1.0
*
* @param array $data The activity data.
* @param int $user_id The user ID.
* @param string|null $visibility Content visibility.
*
* @return \WP_Post|\WP_Error The created post or error.
*/
private static function create_checkin_post( $data, $user_id, $visibility ) {
$location = $data['location'] ?? null;
$location_name = self::get_location_name( $location );
$title = $location_name
? sprintf(
/* translators: %s: location name */
\__( 'Checked in at %s', 'activitypub' ),
$location_name
)
: \__( 'Check-in', 'activitypub' );
$activity = array(
'object' => array(
'type' => 'Note',
'name' => $title,
'content' => $data['content'] ?? $data['summary'] ?? '',
),
'to' => $data['to'] ?? array(),
'cc' => $data['cc'] ?? array(),
);
$post = Posts::create( $activity, $user_id, $visibility );
if ( \is_wp_error( $post ) ) {
return $post;
}
self::save_location( $post->ID, $location );
/**
* Fires after an Arrive activity has created a local blog post.
*
* @since 8.1.0
*
* @param int $post_id The created post ID.
* @param array|null $location The location data from the activity.
* @param array $data The activity data.
* @param int $user_id The user ID.
*/
\do_action( 'activitypub_outbox_arrive_sent', $post->ID, $location, $data, $user_id );
return $post;
}
/**
* Save location geodata on a post.
*
* Uses the standard `geo_*` meta keys that the Post transformer
* reads back when converting to ActivityPub Place objects.
*
* @since 8.1.0
*
* @param int $post_id The post ID.
* @param array|null $location The ActivityPub location data.
*/
private static function save_location( $post_id, $location ) {
if ( ! \is_array( $location ) ) {
return;
}
if ( ! empty( $location['name'] ) ) {
\update_post_meta( $post_id, 'geo_address', \sanitize_text_field( $location['name'] ) );
}
if ( isset( $location['latitude'] ) && \is_numeric( $location['latitude'] ) ) {
\update_post_meta( $post_id, 'geo_latitude', (float) $location['latitude'] );
}
if ( isset( $location['longitude'] ) && \is_numeric( $location['longitude'] ) ) {
\update_post_meta( $post_id, 'geo_longitude', (float) $location['longitude'] );
}
if ( ! empty( $location['name'] ) || ( isset( $location['latitude'] ) && isset( $location['longitude'] ) ) ) {
\update_post_meta( $post_id, 'geo_public', '1' );
}
}
/**
* Extract a human-readable name from an ActivityPub location.
*
* @param mixed $location The location data (array or string).
*
* @return string|null The location name or null.
*/
private static function get_location_name( $location ) {
if ( \is_array( $location ) && ! empty( $location['name'] ) ) {
return \sanitize_text_field( $location['name'] );
}
if ( \is_string( $location ) && ! empty( $location ) ) {
return \sanitize_text_field( $location );
}
return null;
}
}