Skip to content

Commit

Permalink
Add support for Activitypub JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
obenland committed Dec 19, 2024
1 parent 38e866b commit 3db22d2
Show file tree
Hide file tree
Showing 2 changed files with 234 additions and 5 deletions.
106 changes: 106 additions & 0 deletions assets/css/activitypub-embed.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/**
* ActivityPub embed styles.
*/

.activitypub-embed {
background: #fff;
border: 1px solid #e6e6e6;
border-radius: 12px;
margin: 1em 0;
padding: 0;
max-width: 100%;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

.activitypub-embed-header {
padding: 15px;
display: flex;
align-items: center;
gap: 10px;
}

.activitypub-embed-header img {
width: 48px;
height: 48px;
border-radius: 50%;
}

.activitypub-embed-header-text {
flex-grow: 1;
}

.activitypub-embed-header-text h2 {
color: #000;
font-size: 15px;
font-weight: 600;
margin: 0;
padding: 0;
}

.activitypub-embed-header-text .ap-account {
color: #687684;
font-size: 14px;
text-decoration: none;
}

.activitypub-embed-content {
padding: 0 15px 15px;
}

.activitypub-embed-content .ap-title {
font-size: 23px;
font-weight: 600;
margin: 0 0 10px;
padding: 0;
color: #000;
}

.activitypub-embed-content .ap-subtitle {
font-size: 15px;
color: #000;
margin: 0 0 15px;
}

.activitypub-embed-content .ap-preview {
border: 1px solid #e6e6e6;
border-radius: 8px;
overflow: hidden;
}

.activitypub-embed-content .ap-preview img {
width: 100%;
height: auto;
display: block;
}

.activitypub-embed-content .ap-preview-text {
padding: 15px;
}

.activitypub-embed-meta {
padding: 15px;
border-top: 1px solid #e6e6e6;
color: #687684;
font-size: 13px;
display: flex;
gap: 15px;
}

.activitypub-embed-meta .ap-stat {
display: flex;
align-items: center;
gap: 5px;
}

.activitypub-embed-meta a.ap-stat {
text-decoration: none;
}

.activitypub-embed-meta strong {
font-weight: 600;
color: #000;
}

.activitypub-embed-meta .ap-stat-label {
color: #687684;
}
133 changes: 128 additions & 5 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -1597,15 +1597,138 @@ function is_self_ping( $id ) {
/**
* Get the embed of a URL.
*
* This function supports oEmbed URLs, but it is planned to also
* support ActivityPub in the future.
*
* @todo Add ActivityPub support.
* This function supports both ActivityPub JSON and oEmbed URLs.
* It first tries to fetch ActivityPub JSON, and if that fails,
* falls back to oEmbed.
*
* @param string $url The URL to get the embed of.
*
* @return string|false The embed of the URL or false if not found.
*/
function embed_get( $url ) {
return wp_oembed_get( $url );
if ( ! \get_the_ID() ) {
return false;
}

// Create unique transient keys for both HTTP calls.
$main_transient_key = '_activitypub_embed_' . md5( $url );
$embed = \get_transient( $main_transient_key );

if ( false === $embed ) {
$response = Http::get( $url );
if ( \wp_remote_retrieve_response_code( $response ) === 200 ) {
$embed = \json_decode( \wp_remote_retrieve_body( $response ), true );
\set_transient( $main_transient_key, $embed, DAY_IN_SECONDS );
} else {
return \wp_oembed_get( $url );
}
}

if ( $embed ) {
$author_name = isset( $embed['attributedTo'] ) ? $embed['attributedTo'] : '';
$author_url = $author_name;
$avatar_url = isset( $embed['icon']['url'] ) ? $embed['icon']['url'] : '';

// If we don't have an avatar URL but we have an author URL, try to fetch it.
if ( ! $avatar_url && $author_url ) {
$author_transient_key = '_activitypub_author_' . md5( $author_url );
$author = \get_transient( $author_transient_key );

if ( false === $author ) {
$author_response = Http::get( $author_url );
if ( \wp_remote_retrieve_response_code( $author_response ) === 200 ) {
$author = \json_decode( \wp_remote_retrieve_body( $author_response ), true );
\set_transient( $author_transient_key, $author, DAY_IN_SECONDS );
}
}

if ( $author ) {
if ( isset( $author['icon']['url'] ) ) {
$avatar_url = $author['icon']['url'];
}
if ( isset( $author['name'] ) ) {
$author_name = $author['name'];
}
}
}

$published = isset( $embed['published'] ) ? \gmdate( get_option( 'date_format' ) . ', ' . get_option( 'time_format' ), \strtotime( $embed['published'] ) ) : '';
$title = isset( $embed['name'] ) ? $embed['name'] : '';
$content = isset( $embed['content'] ) ? $embed['content'] : '';
$boosts = isset( $embed['shares']['totalItems'] ) ? (int) $embed['shares']['totalItems'] : 0;
$favorites = isset( $embed['likes']['totalItems'] ) ? (int) $embed['likes']['totalItems'] : 0;

$image = '';
if ( isset( $embed['image']['url'] ) ) {
$image = $embed['image']['url'];
} elseif ( isset( $embed['attachment'] ) ) {
foreach ( $embed['attachment'] as $attachment ) {
if ( isset( $attachment['type'] ) && 'Document' === $attachment['type'] ) {
$image = $attachment['url'];
break;
}
}
}

ob_start();
?>
<div class="activitypub-embed">
<div class="activitypub-embed-header">
<?php if ( $avatar_url ) : ?>
<img src="<?php echo \esc_url( $avatar_url ); ?>" alt="" />
<?php endif; ?>
<div class="activitypub-embed-header-text">
<h2><?php echo \esc_html( $author_name ); ?></h2>
<?php if ( $author_url ) : ?>
<a href="<?php echo \esc_url( $author_url ); ?>" class="ap-account"><?php echo \esc_html( $author_url ); ?></a>
<?php endif; ?>
</div>
</div>

<div class="activitypub-embed-content">
<?php if ( $title ) : ?>
<h3 class="ap-title"><?php echo \esc_html( $title ); ?></h3>
<?php endif; ?>

<?php if ( $content ) : ?>
<div class="ap-subtitle"><?php echo \wp_kses_post( $content ); ?></div>
<?php endif; ?>

<?php if ( $image ) : ?>
<div class="ap-preview">
<img src="<?php echo \esc_url( $image ); ?>" alt="" />
</div>
<?php endif; ?>
</div>

<div class="activitypub-embed-meta">
<?php if ( $published ) : ?>
<a href="<?php echo \esc_url( $url ); ?>" class="ap-stat ap-date"><?php echo \esc_html( $published ); ?></a>
<?php endif; ?>

<span class="ap-stat">
<?php
/* translators: %s: number of boosts */
printf( \esc_html__( '%s boosts', 'activitypub' ), '<strong>' . \esc_html( $boosts ) . '</strong>' );
?>
</span>

<span class="ap-stat">
<?php
/* translators: %s: number of favorites */
printf( \esc_html__( '%s favorites', 'activitypub' ), '<strong>' . \esc_html( $favorites ) . '</strong>' );
?>
</span>
</div>
</div>
<?php
$output = ob_get_clean();

if ( $output ) {
\wp_enqueue_style( 'activitypub-embed', ACTIVITYPUB_PLUGIN_URL . 'assets/css/activitypub-embed.css', array(), ACTIVITYPUB_PLUGIN_VERSION );
return $output;
}
}

return \wp_oembed_get( $url );
}

0 comments on commit 3db22d2

Please sign in to comment.