| 1 |
<?php |
| 2 |
/** |
| 3 |
* ActivityPub Settings Fields Class. |
| 4 |
* |
| 5 |
* @package Activitypub |
| 6 |
*/ |
| 7 |
|
| 8 |
namespace Activitypub\WP_Admin; |
| 9 |
|
| 10 |
/** |
| 11 |
* Class Settings_Fields. |
| 12 |
*/ |
| 13 |
class Settings_Fields { |
| 14 |
/** |
| 15 |
* Initialize the settings fields. |
| 16 |
*/ |
| 17 |
public static function init() { |
| 18 |
add_action( 'load-settings_page_activitypub', array( self::class, 'register_settings_fields' ) ); |
| 19 |
} |
| 20 |
|
| 21 |
/** |
| 22 |
* Register settings fields. |
| 23 |
*/ |
| 24 |
public static function register_settings_fields() { |
| 25 |
// Add settings sections. |
| 26 |
add_settings_section( |
| 27 |
'activitypub_profiles', |
| 28 |
__( 'Profiles', 'activitypub' ), |
| 29 |
'__return_empty_string', |
| 30 |
'activitypub_settings' |
| 31 |
); |
| 32 |
|
| 33 |
add_settings_section( |
| 34 |
'activitypub_activities', |
| 35 |
__( 'Activities', 'activitypub' ), |
| 36 |
'__return_empty_string', |
| 37 |
'activitypub_settings' |
| 38 |
); |
| 39 |
|
| 40 |
add_settings_section( |
| 41 |
'activitypub_notifications', |
| 42 |
__( 'Notifications', 'activitypub' ), |
| 43 |
array( self::class, 'render_notifications_section' ), |
| 44 |
'activitypub_settings' |
| 45 |
); |
| 46 |
|
| 47 |
add_settings_section( |
| 48 |
'activitypub_general', |
| 49 |
__( 'General', 'activitypub' ), |
| 50 |
'__return_empty_string', |
| 51 |
'activitypub_settings' |
| 52 |
); |
| 53 |
|
| 54 |
// Add settings fields. |
| 55 |
add_settings_field( |
| 56 |
'activitypub_actor_mode', |
| 57 |
__( 'Enable profiles by type', 'activitypub' ), |
| 58 |
array( self::class, 'render_actor_mode_field' ), |
| 59 |
'activitypub_settings', |
| 60 |
'activitypub_profiles' |
| 61 |
); |
| 62 |
|
| 63 |
add_settings_field( |
| 64 |
'activitypub_object_type', |
| 65 |
__( 'Activity-Object-Type', 'activitypub' ), |
| 66 |
array( self::class, 'render_object_type_field' ), |
| 67 |
'activitypub_settings', |
| 68 |
'activitypub_activities' |
| 69 |
); |
| 70 |
|
| 71 |
$object_type = \get_option( 'activitypub_object_type', ACTIVITYPUB_DEFAULT_OBJECT_TYPE ); |
| 72 |
if ( 'note' === $object_type ) { |
| 73 |
add_settings_field( |
| 74 |
'activitypub_custom_post_content', |
| 75 |
__( 'Post content', 'activitypub' ), |
| 76 |
array( self::class, 'render_custom_post_content_field' ), |
| 77 |
'activitypub_settings', |
| 78 |
'activitypub_activities', |
| 79 |
array( 'label_for' => 'activitypub_custom_post_content' ) |
| 80 |
); |
| 81 |
} |
| 82 |
|
| 83 |
add_settings_field( |
| 84 |
'activitypub_max_image_attachments', |
| 85 |
__( 'Media attachments', 'activitypub' ), |
| 86 |
array( self::class, 'render_max_image_attachments_field' ), |
| 87 |
'activitypub_settings', |
| 88 |
'activitypub_activities', |
| 89 |
array( 'label_for' => 'activitypub_max_image_attachments' ) |
| 90 |
); |
| 91 |
|
| 92 |
add_settings_field( |
| 93 |
'activitypub_support_post_types', |
| 94 |
__( 'Supported post types', 'activitypub' ), |
| 95 |
array( self::class, 'render_support_post_types_field' ), |
| 96 |
'activitypub_settings', |
| 97 |
'activitypub_activities' |
| 98 |
); |
| 99 |
|
| 100 |
add_settings_field( |
| 101 |
'activitypub_use_hashtags', |
| 102 |
__( 'Hashtags', 'activitypub' ), |
| 103 |
array( self::class, 'render_use_hashtags_field' ), |
| 104 |
'activitypub_settings', |
| 105 |
'activitypub_activities', |
| 106 |
array( 'label_for' => 'activitypub_use_hashtags' ) |
| 107 |
); |
| 108 |
|
| 109 |
add_settings_field( |
| 110 |
'activitypub_use_opengraph', |
| 111 |
__( 'OpenGraph', 'activitypub' ), |
| 112 |
array( self::class, 'render_use_opengraph_field' ), |
| 113 |
'activitypub_settings', |
| 114 |
'activitypub_general', |
| 115 |
array( 'label_for' => 'activitypub_use_opengraph' ) |
| 116 |
); |
| 117 |
|
| 118 |
add_settings_field( |
| 119 |
'activitypub_attribution_domains', |
| 120 |
__( 'Attribution Domains', 'activitypub' ), |
| 121 |
array( self::class, 'render_attribution_domains_field' ), |
| 122 |
'activitypub_settings', |
| 123 |
'activitypub_general', |
| 124 |
array( 'label_for' => 'activitypub_attribution_domains' ) |
| 125 |
); |
| 126 |
|
| 127 |
add_settings_field( |
| 128 |
'activitypub_blocklist', |
| 129 |
__( 'Blocklist', 'activitypub' ), |
| 130 |
array( self::class, 'render_blocklist_field' ), |
| 131 |
'activitypub_settings', |
| 132 |
'activitypub_general' |
| 133 |
); |
| 134 |
|
| 135 |
add_settings_field( |
| 136 |
'activitypub_outbox_purge_days', |
| 137 |
__( 'Outbox Retention Period', 'activitypub' ), |
| 138 |
array( self::class, 'render_outbox_purge_days_field' ), |
| 139 |
'activitypub_settings', |
| 140 |
'activitypub_general', |
| 141 |
array( 'label_for' => 'activitypub_outbox_purge_days' ) |
| 142 |
); |
| 143 |
|
| 144 |
if ( ! defined( 'ACTIVITYPUB_AUTHORIZED_FETCH' ) ) { |
| 145 |
add_settings_section( |
| 146 |
'activitypub_security', |
| 147 |
__( 'Security', 'activitypub' ), |
| 148 |
'__return_empty_string', |
| 149 |
'activitypub_settings' |
| 150 |
); |
| 151 |
|
| 152 |
add_settings_field( |
| 153 |
'activitypub_authorized_fetch', |
| 154 |
__( 'Authorized Fetch', 'activitypub' ), |
| 155 |
array( self::class, 'render_authorized_fetch_field' ), |
| 156 |
'activitypub_settings', |
| 157 |
'activitypub_security', |
| 158 |
array( 'label_for' => 'activitypub_authorized_fetch' ) |
| 159 |
); |
| 160 |
} |
| 161 |
} |
| 162 |
|
| 163 |
/** |
| 164 |
* Render notifications section. |
| 165 |
*/ |
| 166 |
public static function render_notifications_section() { |
| 167 |
?> |
| 168 |
<p> |
| 169 |
<?php \esc_html_e( 'Choose which notifications you want to receive. The plugin currently only supports e-mail notifications, but we will add more options in the future.', 'activitypub' ); ?> |
| 170 |
</p> |
| 171 |
<table class="form-table"> |
| 172 |
<tbody> |
| 173 |
<tr> |
| 174 |
<th scope="col"> |
| 175 |
<?php \esc_html_e( 'Type', 'activitypub' ); ?> |
| 176 |
</th> |
| 177 |
<th scope="col"> |
| 178 |
<?php \esc_html_e( 'E-Mail', 'activitypub' ); ?> |
| 179 |
</th> |
| 180 |
</tr> |
| 181 |
<tr> |
| 182 |
<td> |
| 183 |
<?php \esc_html_e( 'New followers', 'activitypub' ); ?> |
| 184 |
</td> |
| 185 |
<td> |
| 186 |
<label> |
| 187 |
<input type="checkbox" name="activitypub_mailer_new_follower" id="activitypub_mailer_new_follower" value="1" <?php \checked( '1', \get_option( 'activitypub_mailer_new_follower', '0' ) ); ?> /> |
| 188 |
</label> |
| 189 |
</td> |
| 190 |
</tr> |
| 191 |
<tr> |
| 192 |
<td> |
| 193 |
<?php \esc_html_e( 'Direct Messages', 'activitypub' ); ?> |
| 194 |
</td> |
| 195 |
<td> |
| 196 |
<label> |
| 197 |
<input type="checkbox" name="activitypub_mailer_new_dm" id="activitypub_mailer_new_dm" value="1" <?php \checked( '1', \get_option( 'activitypub_mailer_new_dm', '0' ) ); ?> /> |
| 198 |
</label> |
| 199 |
</td> |
| 200 |
</tr> |
| 201 |
</tbody> |
| 202 |
</table> |
| 203 |
<?php |
| 204 |
} |
| 205 |
|
| 206 |
/** |
| 207 |
* Render actor mode field. |
| 208 |
*/ |
| 209 |
public static function render_actor_mode_field() { |
| 210 |
$value = get_option( 'activitypub_actor_mode', ACTIVITYPUB_ACTOR_MODE ); |
| 211 |
?> |
| 212 |
<p> |
| 213 |
<label> |
| 214 |
<input type="radio" name="activitypub_actor_mode" value="<?php echo esc_attr( ACTIVITYPUB_ACTOR_MODE ); ?>" <?php checked( ACTIVITYPUB_ACTOR_MODE, $value ); ?> /> |
| 215 |
<strong><?php esc_html_e( 'Author Profiles Only', 'activitypub' ); ?></strong> |
| 216 |
</label> |
| 217 |
</p> |
| 218 |
<p class="description"> |
| 219 |
<?php echo wp_kses( __( 'Every author on this blog (with the <code>activitypub</code> capability) gets their own ActivityPub profile.', 'activitypub' ), array( 'code' => array() ) ); ?> |
| 220 |
<strong> |
| 221 |
<?php |
| 222 |
echo wp_kses( |
| 223 |
sprintf( |
| 224 |
// translators: %s is a URL. |
| 225 |
__( 'You can add/remove the capability in the <a href="%s">user settings.</a>', 'activitypub' ), |
| 226 |
admin_url( '/users.php' ) |
| 227 |
), |
| 228 |
array( 'a' => array( 'href' => array() ) ) |
| 229 |
); |
| 230 |
?> |
| 231 |
</strong> |
| 232 |
<?php echo wp_kses( __( 'Select all the users you want to update, choose the method from the drop-down list and click on the "Apply" button.', 'activitypub' ), array( 'code' => array() ) ); ?> |
| 233 |
</p> |
| 234 |
<p> |
| 235 |
<label> |
| 236 |
<input type="radio" name="activitypub_actor_mode" value="<?php echo esc_attr( ACTIVITYPUB_BLOG_MODE ); ?>" <?php checked( ACTIVITYPUB_BLOG_MODE, $value ); ?> /> |
| 237 |
<strong><?php esc_html_e( 'Blog profile only', 'activitypub' ); ?></strong> |
| 238 |
</label> |
| 239 |
</p> |
| 240 |
<p class="description"> |
| 241 |
<?php esc_html_e( 'Your blog becomes a single ActivityPub profile and every post will be published under this profile instead of the individual author profiles.', 'activitypub' ); ?> |
| 242 |
</p> |
| 243 |
<p> |
| 244 |
<label> |
| 245 |
<input type="radio" name="activitypub_actor_mode" value="<?php echo esc_attr( ACTIVITYPUB_ACTOR_AND_BLOG_MODE ); ?>" <?php checked( ACTIVITYPUB_ACTOR_AND_BLOG_MODE, $value ); ?> /> |
| 246 |
<strong><?php esc_html_e( 'Both author and blog profiles', 'activitypub' ); ?></strong> |
| 247 |
</label> |
| 248 |
</p> |
| 249 |
<p class="description"> |
| 250 |
<?php esc_html_e( "This combines both modes. Users can be followed individually, while following the blog will show boosts of individual user's posts.", 'activitypub' ); ?> |
| 251 |
</p> |
| 252 |
<?php |
| 253 |
} |
| 254 |
|
| 255 |
/** |
| 256 |
* Render object type field. |
| 257 |
*/ |
| 258 |
public static function render_object_type_field() { |
| 259 |
$value = get_option( 'activitypub_object_type', ACTIVITYPUB_DEFAULT_OBJECT_TYPE ); |
| 260 |
?> |
| 261 |
<p> |
| 262 |
<label> |
| 263 |
<input type="radio" name="activitypub_object_type" value="wordpress-post-format" <?php checked( 'wordpress-post-format', $value ); ?> /> |
| 264 |
<?php esc_html_e( 'Automatic (default)', 'activitypub' ); ?> |
| 265 |
- |
| 266 |
<span class="description"> |
| 267 |
<?php esc_html_e( 'Let the plugin choose the best possible format for you.', 'activitypub' ); ?> |
| 268 |
</span> |
| 269 |
</label> |
| 270 |
</p> |
| 271 |
<p> |
| 272 |
<label> |
| 273 |
<input type="radio" name="activitypub_object_type" value="note" <?php checked( 'note', $value ); ?> /> |
| 274 |
<?php esc_html_e( 'Note', 'activitypub' ); ?> |
| 275 |
- |
| 276 |
<span class="description"> |
| 277 |
<?php esc_html_e( 'Should work with most platforms.', 'activitypub' ); ?> |
| 278 |
</span> |
| 279 |
</label> |
| 280 |
</p> |
| 281 |
<?php |
| 282 |
} |
| 283 |
|
| 284 |
/** |
| 285 |
* Render custom post content field. |
| 286 |
*/ |
| 287 |
public static function render_custom_post_content_field() { |
| 288 |
$value = get_option( 'activitypub_custom_post_content', ACTIVITYPUB_CUSTOM_POST_CONTENT ); |
| 289 |
?> |
| 290 |
<p><strong><?php esc_html_e( 'These settings only apply if you use the "Note" Object-Type setting above.', 'activitypub' ); ?></strong></p> |
| 291 |
<p> |
| 292 |
<textarea id="activitypub_custom_post_content" name="activitypub_custom_post_content" rows="10" cols="50" class="large-text" placeholder="<?php echo esc_attr( ACTIVITYPUB_CUSTOM_POST_CONTENT ); ?>"><?php echo esc_textarea( wp_kses( $value, 'post' ) ); ?></textarea> |
| 293 |
<details> |
| 294 |
<summary><?php esc_html_e( 'See a list of ActivityPub Template Tags.', 'activitypub' ); ?></summary> |
| 295 |
<div class="description"> |
| 296 |
<ul> |
| 297 |
<li><code>[ap_title]</code> - <?php esc_html_e( 'The post’s title.', 'activitypub' ); ?></li> |
| 298 |
<li><code>[ap_content]</code> - <?php esc_html_e( 'The post’s content.', 'activitypub' ); ?></li> |
| 299 |
<li><code>[ap_excerpt]</code> - <?php esc_html_e( 'The post’s excerpt (may be truncated).', 'activitypub' ); ?></li> |
| 300 |
<li><code>[ap_permalink]</code> - <?php esc_html_e( 'The post’s permalink.', 'activitypub' ); ?></li> |
| 301 |
<li><code>[ap_shortlink]</code> - <?php echo wp_kses( __( 'The post’s shortlink. I can recommend <a href="https://wordpress.org/plugins/hum/" target="_blank">Hum</a>.', 'activitypub' ), 'default' ); ?></li> |
| 302 |
<li><code>[ap_hashtags]</code> - <?php esc_html_e( 'The post’s tags as hashtags.', 'activitypub' ); ?></li> |
| 303 |
</ul> |
| 304 |
<p><?php esc_html_e( 'You can find the full list with all possible attributes in the help section on the top-right of the screen.', 'activitypub' ); ?></p> |
| 305 |
</div> |
| 306 |
</details> |
| 307 |
</p> |
| 308 |
<?php |
| 309 |
} |
| 310 |
|
| 311 |
/** |
| 312 |
* Render max image attachments field. |
| 313 |
*/ |
| 314 |
public static function render_max_image_attachments_field() { |
| 315 |
$value = get_option( 'activitypub_max_image_attachments', ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ); |
| 316 |
?> |
| 317 |
<input id="activitypub_max_image_attachments" value="<?php echo esc_attr( $value ); ?>" name="activitypub_max_image_attachments" type="number" min="0" class="small-text" /> |
| 318 |
<p class="description"> |
| 319 |
<?php |
| 320 |
echo wp_kses( |
| 321 |
sprintf( |
| 322 |
// translators: %s is a number. |
| 323 |
__( 'The number of media (images, audio, video) to attach to posts. Default: <code>%s</code>', 'activitypub' ), |
| 324 |
esc_html( ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS ) |
| 325 |
), |
| 326 |
'default' |
| 327 |
); |
| 328 |
?> |
| 329 |
</p> |
| 330 |
<p class="description"> |
| 331 |
<em> |
| 332 |
<?php esc_html_e( 'Note: audio and video attachments are only supported from Block Editor.', 'activitypub' ); ?> |
| 333 |
</em> |
| 334 |
</p> |
| 335 |
<?php |
| 336 |
} |
| 337 |
|
| 338 |
/** |
| 339 |
* Render support post types field. |
| 340 |
*/ |
| 341 |
public static function render_support_post_types_field() { |
| 342 |
$post_types = get_post_types( array( 'public' => true ), 'objects' ); |
| 343 |
$supported_post_types = (array) get_option( 'activitypub_support_post_types', array( 'post' ) ); |
| 344 |
?> |
| 345 |
<fieldset> |
| 346 |
<?php esc_html_e( 'Automatically publish items of the selected post types to the fediverse:', 'activitypub' ); ?> |
| 347 |
<ul> |
| 348 |
<?php foreach ( $post_types as $post_type ) : ?> |
| 349 |
<li> |
| 350 |
<input type="checkbox" id="activitypub_support_post_type_<?php echo esc_attr( $post_type->name ); ?>" name="activitypub_support_post_types[]" value="<?php echo esc_attr( $post_type->name ); ?>" <?php checked( in_array( $post_type->name, $supported_post_types, true ) ); ?> /> |
| 351 |
<label for="activitypub_support_post_type_<?php echo esc_attr( $post_type->name ); ?>"><?php echo esc_html( $post_type->label ); ?></label> |
| 352 |
<span class="description"> |
| 353 |
<?php echo esc_html( \Activitypub\get_post_type_description( $post_type ) ); ?> |
| 354 |
</span> |
| 355 |
</li> |
| 356 |
<?php endforeach; ?> |
| 357 |
</ul> |
| 358 |
</fieldset> |
| 359 |
<?php |
| 360 |
} |
| 361 |
|
| 362 |
/** |
| 363 |
* Render use hashtags field. |
| 364 |
*/ |
| 365 |
public static function render_use_hashtags_field() { |
| 366 |
$value = get_option( 'activitypub_use_hashtags', '1' ); |
| 367 |
?> |
| 368 |
<p> |
| 369 |
<label> |
| 370 |
<input type="checkbox" id="activitypub_use_hashtags" name="activitypub_use_hashtags" value="1" <?php checked( '1', $value ); ?> /> |
| 371 |
<?php echo wp_kses( __( 'Add hashtags in the content as native tags and replace the <code>#tag</code> with the tag link.', 'activitypub' ), 'default' ); ?> |
| 372 |
</label> |
| 373 |
</p> |
| 374 |
<?php |
| 375 |
} |
| 376 |
|
| 377 |
/** |
| 378 |
* Render use OpenGraph field. |
| 379 |
*/ |
| 380 |
public static function render_use_opengraph_field() { |
| 381 |
$value = get_option( 'activitypub_use_opengraph', '1' ); |
| 382 |
?> |
| 383 |
<p> |
| 384 |
<label> |
| 385 |
<input type="checkbox" id="activitypub_use_opengraph" name="activitypub_use_opengraph" value="1" <?php checked( '1', $value ); ?> /> |
| 386 |
<?php echo wp_kses( __( 'Automatically add <code><meta name="fediverse:creator" /></code> tags for Authors and the Blog-User. You can read more about the feature on the <a href="https://blog.joinmastodon.org/2024/07/highlighting-journalism-on-mastodon/" target="_blank">Mastodon Blog</a>.', 'activitypub' ), 'post' ); ?> |
| 387 |
</label> |
| 388 |
</p> |
| 389 |
<?php |
| 390 |
} |
| 391 |
|
| 392 |
/** |
| 393 |
* Render attribution domains field. |
| 394 |
*/ |
| 395 |
public static function render_attribution_domains_field() { |
| 396 |
$value = get_option( 'activitypub_attribution_domains', \Activitypub\home_host() ); |
| 397 |
?> |
| 398 |
<textarea id="activitypub_attribution_domains" name="activitypub_attribution_domains" class="large-text" cols="50" rows="5" placeholder="<?php echo esc_attr( \Activitypub\home_host() ); ?>"><?php echo esc_textarea( $value ); ?></textarea> |
| 399 |
<p class="description"><?php esc_html_e( 'Websites allowed to credit you, one per line. Protects from false attributions.', 'activitypub' ); ?></p> |
| 400 |
<?php |
| 401 |
} |
| 402 |
|
| 403 |
/** |
| 404 |
* Render blocklist field. |
| 405 |
*/ |
| 406 |
public static function render_blocklist_field() { |
| 407 |
?> |
| 408 |
<p> |
| 409 |
<?php |
| 410 |
echo wp_kses( |
| 411 |
sprintf( |
| 412 |
// translators: %s is a URL. |
| 413 |
__( 'To block servers, add the host of the server to the "<a href="%s">Disallowed Comment Keys</a>" list.', 'activitypub' ), |
| 414 |
esc_url( admin_url( 'options-discussion.php#disallowed_keys' ) ) |
| 415 |
), |
| 416 |
'default' |
| 417 |
); |
| 418 |
?> |
| 419 |
</p> |
| 420 |
<?php |
| 421 |
} |
| 422 |
|
| 423 |
/** |
| 424 |
* Render outbox purge days field. |
| 425 |
*/ |
| 426 |
public static function render_outbox_purge_days_field() { |
| 427 |
$value = get_option( 'activitypub_outbox_purge_days', 180 ); |
| 428 |
echo '<input type="number" id="activitypub_outbox_purge_days" name="activitypub_outbox_purge_days" value="' . esc_attr( $value ) . '" class="small-text" min="0" max="365" />'; |
| 429 |
echo '<p class="description">' . wp_kses( |
| 430 |
sprintf( |
| 431 |
// translators: 1: Definition of Outbox; 2: Default value (180). |
| 432 |
__( 'Maximum number of days to keep items in the <abbr title="%1$s">Outbox</abbr>. A lower value might be better for sites with lots of activity to maintain site performance. Default: <code>%2$s</code>', 'activitypub' ), |
| 433 |
esc_attr__( 'A virtual location on a user’s profile where all the activities (posts, likes, replies) they publish are stored, acting as a feed that other users can access to see their publicly shared content', 'activitypub' ), |
| 434 |
esc_html( 180 ) |
| 435 |
), |
| 436 |
array( |
| 437 |
'abbr' => array( 'title' => array() ), |
| 438 |
'code' => array(), |
| 439 |
) |
| 440 |
) . '</p>'; |
| 441 |
} |
| 442 |
|
| 443 |
/** |
| 444 |
* Render use hashtags field. |
| 445 |
*/ |
| 446 |
public static function render_authorized_fetch_field() { |
| 447 |
$value = get_option( 'activitypub_authorized_fetch', '1' ); |
| 448 |
?> |
| 449 |
<p> |
| 450 |
<label> |
| 451 |
<input type="checkbox" id="activitypub_authorized_fetch" name="activitypub_authorized_fetch" value="1" <?php checked( '1', $value ); ?> /> |
| 452 |
<?php esc_html_e( 'Require HTTP signature authentication on ActivityPub representations of public posts and profiles.', 'activitypub' ); ?> |
| 453 |
</label> |
| 454 |
</p> |
| 455 |
<p class="description"> |
| 456 |
<?php \esc_html_e( '⚠ Secure mode has its limitations, which is why it is not enabled by default. It is not fully supported by all software in the fediverse, and some features may break, especially when interacting with Mastodon servers older than version 3.0. Additionally, since it requires authentication for public content, caching is not possible, leading to higher computational costs.', 'activitypub' ); ?> |
| 457 |
</p> |
| 458 |
<p class="description"> |
| 459 |
<?php \esc_html_e( '⚠ Secure mode does not hide the HTML representations of public posts and profiles. While HTML is a less consistent format (that potentially changes often) compared to first-class ActivityPub representations or the REST API, it still poses a potential risk for content scraping.', 'activitypub' ); ?> |
| 460 |
</p> |
| 461 |
<?php |
| 462 |
} |
| 463 |
} |
| 464 |
|