PluginProbe
ActivityPub / 7.8.0
ActivityPub v7.8.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / includes / model / class-blog.php

class-blog.php in ActivityPub 7.8.0, at includes/model/class-blog.php

566 lines 11.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Blog model file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Model;
9
10 use Activitypub\Activity\Actor;
11 use Activitypub\Collection\Actors;
12 use Activitypub\Collection\Extra_Fields;
13
14 use function Activitypub\esc_hashtag;
15 use function Activitypub\get_attribution_domains;
16 use function Activitypub\get_rest_url_by_path;
17 use function Activitypub\is_blog_public;
18 use function Activitypub\is_single_user;
19
20 /**
21 * Blog class.
22 *
23 * @method int get__id() Gets the internal user ID for the blog (always returns BLOG_USER_ID).
24 */
25 class Blog extends Actor {
26 /**
27 * The User-ID
28 *
29 * @var int
30 */
31 protected $_id = Actors::BLOG_USER_ID; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
32
33 /**
34 * The generator of the object.
35 *
36 * @see https://www.w3.org/TR/activitypub/#generator
37 * @see https://codeberg.org/fediverse/fep/src/branch/main/fep/844e/fep-844e.md#discovery-through-an-actor
38 *
39 * @var array
40 */
41 protected $generator = array(
42 'type' => 'Application',
43 'implements' => array(
44 array(
45 'href' => 'https://datatracker.ietf.org/doc/html/rfc9421',
46 'name' => 'RFC-9421: HTTP Message Signatures',
47 ),
48 ),
49 );
50
51 /**
52 * Constructor.
53 */
54 public function __construct() {
55 /**
56 * Fires when a model actor is constructed.
57 *
58 * @param Blog $this The Blog model.
59 */
60 \do_action( 'activitypub_construct_model_actor', $this );
61 }
62
63 /**
64 * Whether the User manually approves followers.
65 *
66 * @return false
67 */
68 public function get_manually_approves_followers() {
69 return false;
70 }
71
72 /**
73 * Whether the User is discoverable.
74 *
75 * @return boolean
76 */
77 public function get_discoverable() {
78 return true;
79 }
80
81 /**
82 * Get the User ID.
83 *
84 * @return string The User ID.
85 */
86 public function get_id() {
87 $id = parent::get_id();
88
89 if ( $id ) {
90 return $id;
91 }
92
93 $permalink = \get_option( 'activitypub_use_permalink_as_id_for_blog', false );
94
95 if ( $permalink ) {
96 return \esc_url( \trailingslashit( get_home_url() ) . '@' . $this->get_preferred_username() );
97 }
98
99 return \add_query_arg( 'author', $this->_id, \home_url( '/' ) );
100 }
101
102 /**
103 * Get the type of the object.
104 *
105 * If relay mode is enabled, return "Service".
106 * If the Blog is in "single user" mode, return "Person" instead of "Group".
107 *
108 * @return string The type of the object.
109 */
110 public function get_type() {
111 if ( \get_option( 'activitypub_relay_mode', false ) ) {
112 return 'Service';
113 }
114
115 if ( is_single_user() ) {
116 return 'Person';
117 } else {
118 return 'Group';
119 }
120 }
121
122 /**
123 * Get the Username.
124 *
125 * @return string The Username.
126 */
127 public function get_name() {
128 return \wp_strip_all_tags(
129 \html_entity_decode(
130 \get_bloginfo( 'name' ),
131 \ENT_QUOTES,
132 'UTF-8'
133 )
134 );
135 }
136
137 /**
138 * Get the User description.
139 *
140 * @return string The User description.
141 */
142 public function get_summary() {
143 $summary = \get_option( 'activitypub_blog_description', null );
144
145 if ( ! $summary ) {
146 $summary = \get_bloginfo( 'description' );
147 }
148
149 return \wpautop(
150 \wp_kses(
151 $summary,
152 'default'
153 )
154 );
155 }
156
157 /**
158 * Get the User url.
159 *
160 * @return string The User url.
161 */
162 public function get_url() {
163 return \get_bloginfo( 'url' );
164 }
165
166 /**
167 * Get blog's homepage URL.
168 *
169 * @return string The User-Url.
170 */
171 public function get_alternate_url() {
172 return \esc_url( \trailingslashit( get_home_url() ) );
173 }
174
175 /**
176 * Generate a default Username.
177 *
178 * @return string The auto-generated Username.
179 */
180 public static function get_default_username() {
181 // Check if domain host has a subdomain.
182 $host = \wp_parse_url( \get_home_url(), \PHP_URL_HOST );
183 $host = \preg_replace( '/^www\./i', '', $host );
184
185 /**
186 * Filters the default blog username.
187 *
188 * This filter allows developers to modify the default username that is
189 * generated for the blog, which by default is the site's host name
190 * without the 'www.' prefix.
191 *
192 * @param string $host The default username (site's host name).
193 */
194 return apply_filters( 'activitypub_default_blog_username', $host );
195 }
196
197 /**
198 * Get the preferred Username.
199 *
200 * @return string The Username.
201 */
202 public function get_preferred_username() {
203 $username = \get_option( 'activitypub_blog_identifier' );
204
205 if ( $username ) {
206 return $username;
207 }
208
209 return self::get_default_username();
210 }
211
212 /**
213 * Get the User icon.
214 *
215 * @return string[] The User icon.
216 */
217 public function get_icon() {
218 // Try site_logo, falling back to site_icon, first.
219 $icon_id = get_option( 'site_icon' );
220
221 // Try custom logo second.
222 if ( ! $icon_id ) {
223 $icon_id = get_theme_mod( 'custom_logo' );
224 }
225
226 $icon_url = false;
227
228 if ( $icon_id ) {
229 $icon = wp_get_attachment_image_src( $icon_id, 'full' );
230 if ( $icon ) {
231 $icon_url = $icon[0];
232 }
233 }
234
235 if ( ! $icon_url ) {
236 // Fallback to default icon.
237 $icon_url = plugins_url( '/assets/img/wp-logo.png', ACTIVITYPUB_PLUGIN_FILE );
238 }
239
240 return array(
241 'type' => 'Image',
242 'url' => esc_url( $icon_url ),
243 );
244 }
245
246 /**
247 * Get the User-Header-Image.
248 *
249 * @return string[]|null The User-Header-Image.
250 */
251 public function get_image() {
252 $header_image = get_option( 'activitypub_header_image' );
253 $image_url = null;
254
255 if ( $header_image ) {
256 $image_url = \wp_get_attachment_url( $header_image );
257 }
258
259 if ( ! $image_url && \has_header_image() ) {
260 $image_url = \get_header_image();
261 }
262
263 if ( $image_url ) {
264 return array(
265 'type' => 'Image',
266 'url' => esc_url( $image_url ),
267 );
268 }
269
270 return null;
271 }
272
273 /**
274 * Get the published date.
275 *
276 * @return string The published date.
277 */
278 public function get_published() {
279 $first_post = new \WP_Query(
280 array(
281 'orderby' => 'date',
282 'order' => 'ASC',
283 'number' => 1,
284 )
285 );
286
287 if ( ! empty( $first_post->posts[0] ) ) {
288 $time = \strtotime( $first_post->posts[0]->post_date_gmt );
289 } else {
290 $time = \time();
291 }
292
293 return \gmdate( ACTIVITYPUB_DATE_TIME_RFC3339, $time );
294 }
295
296 /**
297 * Get the canonical URL.
298 *
299 * @return string|null The canonical URL.
300 */
301 public function get_canonical_url() {
302 return \home_url();
303 }
304
305 /**
306 * Get the Moderators endpoint.
307 *
308 * @return string|null The Moderators endpoint.
309 */
310 public function get_moderators() {
311 if ( is_single_user() || 'Group' !== $this->get_type() ) {
312 return null;
313 }
314
315 return get_rest_url_by_path( 'collections/moderators' );
316 }
317
318 /**
319 * Get attributedTo value.
320 *
321 * @return string|null The attributedTo value.
322 */
323 public function get_attributed_to() {
324 if ( is_single_user() || 'Group' !== $this->get_type() ) {
325 return null;
326 }
327
328 return get_rest_url_by_path( 'collections/moderators' );
329 }
330
331 /**
332 * Get the public key information.
333 *
334 * @return string[] The public key.
335 */
336 public function get_public_key() {
337 return array(
338 'id' => $this->get_id() . '#main-key',
339 'owner' => $this->get_id(),
340 'publicKeyPem' => Actors::get_public_key( $this->get__id() ),
341 );
342 }
343
344 /**
345 * Returns whether posting is restricted to mods.
346 *
347 * @return bool|null True if posting is restricted to mods, null if not applicable.
348 */
349 public function get_posting_restricted_to_mods() {
350 if ( 'Group' === $this->get_type() ) {
351 return true;
352 }
353
354 return null;
355 }
356
357 /**
358 * Returns the Inbox-API-Endpoint.
359 *
360 * @return string The Inbox-Endpoint.
361 */
362 public function get_inbox() {
363 return get_rest_url_by_path( sprintf( 'actors/%d/inbox', $this->get__id() ) );
364 }
365
366 /**
367 * Returns the Outbox-API-Endpoint.
368 *
369 * @return string The Outbox-Endpoint.
370 */
371 public function get_outbox() {
372 return get_rest_url_by_path( sprintf( 'actors/%d/outbox', $this->get__id() ) );
373 }
374
375 /**
376 * Returns the Followers-API-Endpoint.
377 *
378 * @return string The Followers-Endpoint.
379 */
380 public function get_followers() {
381 return get_rest_url_by_path( sprintf( 'actors/%d/followers', $this->get__id() ) );
382 }
383
384 /**
385 * Returns the Following-API-Endpoint.
386 *
387 * @return string The Following-Endpoint.
388 */
389 public function get_following() {
390 return get_rest_url_by_path( sprintf( 'actors/%d/following', $this->get__id() ) );
391 }
392
393 /**
394 * Returns endpoints.
395 *
396 * @return string[]|null The endpoints.
397 */
398 public function get_endpoints() {
399 return array(
400 'sharedInbox' => get_rest_url_by_path( 'inbox' ),
401 );
402 }
403
404 /**
405 * Returns a user@domain type of identifier for the user.
406 *
407 * @return string The Webfinger-Identifier.
408 */
409 public function get_webfinger() {
410 return $this->get_preferred_username() . '@' . \wp_parse_url( \home_url(), \PHP_URL_HOST );
411 }
412
413 /**
414 * Returns the Featured-API-Endpoint.
415 *
416 * @return string The Featured-Endpoint.
417 */
418 public function get_featured() {
419 return get_rest_url_by_path( sprintf( 'actors/%d/collections/featured', $this->get__id() ) );
420 }
421
422 /**
423 * Returns the Featured-Tags-API-Endpoint.
424 *
425 * @return string The Featured-Tags-Endpoint.
426 */
427 public function get_featured_tags() {
428 return get_rest_url_by_path( sprintf( 'actors/%d/collections/tags', $this->get__id() ) );
429 }
430
431 /**
432 * Returns whether the site is indexable.
433 *
434 * @return bool Whether the site is indexable.
435 */
436 public function get_indexable() {
437 if ( is_blog_public() ) {
438 return true;
439 } else {
440 return false;
441 }
442 }
443
444 /**
445 * Update the Username.
446 *
447 * @param mixed $value The new value.
448 * @return bool True if the attribute was updated, false otherwise.
449 */
450 public function update_name( $value ) {
451 return \update_option( 'blogname', $value );
452 }
453
454 /**
455 * Update the User description.
456 *
457 * @param mixed $value The new value.
458 * @return bool True if the attribute was updated, false otherwise.
459 */
460 public function update_summary( $value ) {
461 return \update_option( 'blogdescription', $value );
462 }
463
464 /**
465 * Update the User icon.
466 *
467 * @param mixed $value The new value.
468 * @return bool True if the attribute was updated, false otherwise.
469 */
470 public function update_icon( $value ) {
471 if ( ! wp_attachment_is_image( $value ) ) {
472 return false;
473 }
474 return \update_option( 'site_icon', $value );
475 }
476
477 /**
478 * Update the User-Header-Image.
479 *
480 * @param mixed $value The new value.
481 * @return bool True if the attribute was updated, false otherwise.
482 */
483 public function update_header( $value ) {
484 if ( ! wp_attachment_is_image( $value ) ) {
485 return false;
486 }
487 return \update_option( 'activitypub_header_image', $value );
488 }
489
490 /**
491 * Get the User - Hashtags.
492 *
493 * @see https://docs.joinmastodon.org/spec/activitypub/#Hashtag
494 *
495 * @return string[] The User - Hashtags.
496 */
497 public function get_tag() {
498 $hashtags = array();
499
500 $args = array(
501 'orderby' => 'count',
502 'order' => 'DESC',
503 'number' => 10,
504 );
505
506 $tags = get_tags( $args );
507
508 foreach ( $tags as $tag ) {
509 $hashtags[] = array(
510 'type' => 'Hashtag',
511 'href' => \get_tag_link( $tag->term_id ),
512 'name' => esc_hashtag( $tag->name ),
513 );
514 }
515
516 return $hashtags;
517 }
518
519 /**
520 * Extend the User-Output with Attachments.
521 *
522 * @return array The extended User-Output.
523 */
524 public function get_attachment() {
525 $extra_fields = Extra_Fields::get_actor_fields( $this->_id );
526 return Extra_Fields::fields_to_attachments( $extra_fields );
527 }
528
529 /**
530 * Returns the website hosts allowed to credit this blog.
531 *
532 * @return string[]|null The attribution domains or null if not found.
533 */
534 public function get_attribution_domains() {
535 return get_attribution_domains();
536 }
537
538 /**
539 * Returns the alsoKnownAs.
540 *
541 * @return string[] The alsoKnownAs.
542 */
543 public function get_also_known_as() {
544 $also_known_as = array(
545 \add_query_arg( 'author', $this->_id, \home_url( '/' ) ),
546 $this->get_url(),
547 $this->get_alternate_url(),
548 );
549
550 $also_known_as = array_merge( $also_known_as, \get_option( 'activitypub_blog_user_also_known_as', array() ) );
551
552 return array_unique( $also_known_as );
553 }
554
555 /**
556 * Returns the movedTo.
557 *
558 * @return string The movedTo.
559 */
560 public function get_moved_to() {
561 $moved_to = \get_option( 'activitypub_blog_user_moved_to' );
562
563 return $moved_to && $moved_to !== $this->get_id() ? $moved_to : null;
564 }
565 }
566