PluginProbe
ActivityPub / 4.1.1
ActivityPub v4.1.1
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 4.1.1, at includes/model/class-blog.php

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