PluginProbe
ActivityPub / 7.0.0
ActivityPub v7.0.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.0.0, at includes/model/class-blog.php

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