PluginProbe
ActivityPub / 5.7.0
ActivityPub v5.7.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 5.7.0, at includes/model/class-blog.php

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