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 / activitypub.php

activitypub.php in ActivityPub 4.1.1, at activitypub.php

279 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: ActivityPub
4 * Plugin URI: https://github.com/pfefferle/wordpress-activitypub/
5 * Description: The ActivityPub protocol is a decentralized social networking protocol based upon the ActivityStreams 2.0 data format.
6 * Version: 4.1.1
7 * Author: Matthias Pfefferle & Automattic
8 * Author URI: https://automattic.com/
9 * License: MIT
10 * License URI: http://opensource.org/licenses/MIT
11 * Requires PHP: 7.0
12 * Text Domain: activitypub
13 * Domain Path: /languages
14 *
15 * @package Activitypub
16 */
17
18 namespace Activitypub;
19
20 use WP_CLI;
21
22 require_once __DIR__ . '/includes/compat.php';
23 require_once __DIR__ . '/includes/functions.php';
24
25 \define( 'ACTIVITYPUB_PLUGIN_VERSION', '4.1.1' );
26
27 /**
28 * Initialize the plugin constants.
29 */
30 \defined( 'ACTIVITYPUB_REST_NAMESPACE' ) || \define( 'ACTIVITYPUB_REST_NAMESPACE', 'activitypub/1.0' );
31 \defined( 'ACTIVITYPUB_EXCERPT_LENGTH' ) || \define( 'ACTIVITYPUB_EXCERPT_LENGTH', 400 );
32 \defined( 'ACTIVITYPUB_NOTE_LENGTH' ) || \define( 'ACTIVITYPUB_NOTE_LENGTH', 400 );
33 \defined( 'ACTIVITYPUB_SHOW_PLUGIN_RECOMMENDATIONS' ) || \define( 'ACTIVITYPUB_SHOW_PLUGIN_RECOMMENDATIONS', true );
34 \defined( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS' ) || \define( 'ACTIVITYPUB_MAX_IMAGE_ATTACHMENTS', 3 );
35 \defined( 'ACTIVITYPUB_HASHTAGS_REGEXP' ) || \define( 'ACTIVITYPUB_HASHTAGS_REGEXP', '(?:(?<=\s)|(?<=<p>)|(?<=<br>)|^)#([A-Za-z0-9_]+)(?:(?=\s|[[:punct:]]|$))' );
36 \defined( 'ACTIVITYPUB_USERNAME_REGEXP' ) || \define( 'ACTIVITYPUB_USERNAME_REGEXP', '(?:([A-Za-z0-9\._-]+)@((?:[A-Za-z0-9_-]+\.)+[A-Za-z]+))' );
37 \defined( 'ACTIVITYPUB_URL_REGEXP' ) || \define( 'ACTIVITYPUB_URL_REGEXP', '(https?:|www\.)\S+[\w\/]' );
38 \defined( 'ACTIVITYPUB_CUSTOM_POST_CONTENT' ) || \define( 'ACTIVITYPUB_CUSTOM_POST_CONTENT', "[ap_title type=\"html\"]\n\n[ap_content]\n\n[ap_hashtags]" );
39 \defined( 'ACTIVITYPUB_AUTHORIZED_FETCH' ) || \define( 'ACTIVITYPUB_AUTHORIZED_FETCH', false );
40 \defined( 'ACTIVITYPUB_DISABLE_REWRITES' ) || \define( 'ACTIVITYPUB_DISABLE_REWRITES', false );
41 \defined( 'ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS' ) || \define( 'ACTIVITYPUB_DISABLE_INCOMING_INTERACTIONS', false );
42 // Disable reactions like `Like` and `Announce` by default.
43 \defined( 'ACTIVITYPUB_DISABLE_REACTIONS' ) || \define( 'ACTIVITYPUB_DISABLE_REACTIONS', true );
44 \defined( 'ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS' ) || \define( 'ACTIVITYPUB_DISABLE_OUTGOING_INTERACTIONS', false );
45 \defined( 'ACTIVITYPUB_SHARED_INBOX_FEATURE' ) || \define( 'ACTIVITYPUB_SHARED_INBOX_FEATURE', false );
46 \defined( 'ACTIVITYPUB_SEND_VARY_HEADER' ) || \define( 'ACTIVITYPUB_SEND_VARY_HEADER', false );
47 \defined( 'ACTIVITYPUB_DEFAULT_OBJECT_TYPE' ) || \define( 'ACTIVITYPUB_DEFAULT_OBJECT_TYPE', 'wordpress-post-format' );
48
49 /*
50 * Mastodon HTML sanitizer.
51 *
52 * @see https://docs.joinmastodon.org/spec/activitypub/#sanitization
53 */
54 \define(
55 'ACTIVITYPUB_MASTODON_HTML_SANITIZER',
56 array(
57 'p' => array(),
58 'span' => array( 'class' ),
59 'br' => array(),
60 'a' => array( 'href', 'rel', 'class' ),
61 'del' => array(),
62 'pre' => array(),
63 'code' => array(),
64 'em' => array(),
65 'strong' => array(),
66 'b' => array(),
67 'i' => array(),
68 'u' => array(),
69 'ul' => array(),
70 'ol' => array( 'start', 'reversed' ),
71 'li' => array( 'value' ),
72 'blockquote' => array(),
73 'h1' => array(),
74 'h2' => array(),
75 'h3' => array(),
76 'h4' => array(),
77 )
78 );
79
80 // Define Actor-Modes for the plugin.
81 \define( 'ACTIVITYPUB_ACTOR_MODE', 'actor' );
82 \define( 'ACTIVITYPUB_BLOG_MODE', 'blog' );
83 \define( 'ACTIVITYPUB_ACTOR_AND_BLOG_MODE', 'actor_blog' );
84
85 // Post visibility constants.
86 \define( 'ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC', '' );
87 \define( 'ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC', 'quiet_public' );
88 \define( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL', 'local' );
89
90 // Plugin related constants.
91 \define( 'ACTIVITYPUB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
92 \define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
93 \define( 'ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
94 \define( 'ACTIVITYPUB_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
95
96 /**
97 * Initialize REST routes.
98 */
99 function rest_init() {
100 Rest\Actors::init();
101 Rest\Outbox::init();
102 Rest\Inbox::init();
103 Rest\Followers::init();
104 Rest\Following::init();
105 Rest\Webfinger::init();
106 Rest\Comment::init();
107 Rest\Server::init();
108 Rest\Collection::init();
109 Rest\Interaction::init();
110
111 // Load NodeInfo endpoints only if blog is public.
112 if ( is_blog_public() ) {
113 Rest\NodeInfo::init();
114 }
115 }
116 \add_action( 'rest_api_init', __NAMESPACE__ . '\rest_init' );
117
118 /**
119 * Initialize plugin.
120 */
121 function plugin_init() {
122 \add_action( 'init', array( __NAMESPACE__ . '\Migration', 'init' ) );
123 \add_action( 'init', array( __NAMESPACE__ . '\Activitypub', 'init' ) );
124 \add_action( 'init', array( __NAMESPACE__ . '\Activity_Dispatcher', 'init' ) );
125 \add_action( 'init', array( __NAMESPACE__ . '\Handler', 'init' ) );
126 \add_action( 'init', array( __NAMESPACE__ . '\Admin', 'init' ) );
127 \add_action( 'init', array( __NAMESPACE__ . '\Hashtag', 'init' ) );
128 \add_action( 'init', array( __NAMESPACE__ . '\Mention', 'init' ) );
129 \add_action( 'init', array( __NAMESPACE__ . '\Health_Check', 'init' ) );
130 \add_action( 'init', array( __NAMESPACE__ . '\Scheduler', 'init' ) );
131 \add_action( 'init', array( __NAMESPACE__ . '\Comment', 'init' ) );
132 \add_action( 'init', array( __NAMESPACE__ . '\Link', 'init' ) );
133
134 if ( site_supports_blocks() ) {
135 \add_action( 'init', array( __NAMESPACE__ . '\Blocks', 'init' ) );
136 }
137
138 $debug_file = __DIR__ . '/includes/debug.php';
139 if ( \WP_DEBUG && file_exists( $debug_file ) && is_readable( $debug_file ) ) {
140 require_once $debug_file;
141 Debug::init();
142 }
143 }
144 \add_action( 'plugins_loaded', __NAMESPACE__ . '\plugin_init' );
145
146
147 /**
148 * Class Autoloader.
149 */
150 \spl_autoload_register(
151 function ( $full_class ) {
152 $base_dir = __DIR__ . '/includes/';
153 $base = 'Activitypub\\';
154
155 if ( strncmp( $full_class, $base, strlen( $base ) ) === 0 ) {
156 $maybe_uppercase = str_replace( $base, '', $full_class );
157 $class = strtolower( $maybe_uppercase );
158 // All classes should be capitalized. If this is instead looking for a lowercase method, we ignore that.
159 if ( $maybe_uppercase === $class ) {
160 return;
161 }
162
163 if ( false !== strpos( $class, '\\' ) ) {
164 $parts = explode( '\\', $class );
165 $class = array_pop( $parts );
166 $sub_dir = strtr( implode( '/', $parts ), '_', '-' );
167 $base_dir = $base_dir . $sub_dir . '/';
168 }
169
170 $filename = 'class-' . strtr( $class, '_', '-' );
171 $file = $base_dir . $filename . '.php';
172
173 if ( file_exists( $file ) && is_readable( $file ) ) {
174 require_once $file;
175 } else {
176 // translators: %s is the class name.
177 $message = sprintf( esc_html__( 'Required class not found or not readable: %s', 'activitypub' ), esc_html( $full_class ) );
178 Debug::write_log( $message );
179 \wp_die( $message ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
180 }
181 }
182 }
183 );
184
185 /**
186 * Add plugin settings link.
187 *
188 * @param array $actions The current actions.
189 */
190 function plugin_settings_link( $actions ) {
191 $settings_link = array();
192 $settings_link[] = \sprintf(
193 '<a href="%1s">%2s</a>',
194 \menu_page_url( 'activitypub', false ),
195 \__( 'Settings', 'activitypub' )
196 );
197
198 return \array_merge( $settings_link, $actions );
199 }
200 \add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), __NAMESPACE__ . '\plugin_settings_link' );
201
202 \register_activation_hook(
203 __FILE__,
204 array(
205 __NAMESPACE__ . '\Activitypub',
206 'activate',
207 )
208 );
209
210 \register_deactivation_hook(
211 __FILE__,
212 array(
213 __NAMESPACE__ . '\Activitypub',
214 'deactivate',
215 )
216 );
217
218 \register_uninstall_hook(
219 __FILE__,
220 array(
221 __NAMESPACE__ . '\Activitypub',
222 'uninstall',
223 )
224 );
225
226 // Load integrations.
227 require_once __DIR__ . '/integration/load.php';
228
229 /**
230 * `get_plugin_data` wrapper.
231 *
232 * @param array $default_headers Optional. The default plugin headers. Default empty array.
233 * @return array The plugin metadata array.
234 */
235 function get_plugin_meta( $default_headers = array() ) {
236 if ( ! $default_headers ) {
237 $default_headers = array(
238 'Name' => 'Plugin Name',
239 'PluginURI' => 'Plugin URI',
240 'Version' => 'Version',
241 'Description' => 'Description',
242 'Author' => 'Author',
243 'AuthorURI' => 'Author URI',
244 'TextDomain' => 'Text Domain',
245 'DomainPath' => 'Domain Path',
246 'Network' => 'Network',
247 'RequiresWP' => 'Requires at least',
248 'RequiresPHP' => 'Requires PHP',
249 'UpdateURI' => 'Update URI',
250 );
251 }
252
253 return \get_file_data( __FILE__, $default_headers, 'plugin' );
254 }
255
256 /**
257 * Plugin Version Number used for caching.
258 */
259 function get_plugin_version() {
260 if ( \defined( 'ACTIVITYPUB_PLUGIN_VERSION' ) ) {
261 return ACTIVITYPUB_PLUGIN_VERSION;
262 }
263
264 $meta = get_plugin_meta( array( 'Version' => 'Version' ) );
265
266 return $meta['Version'];
267 }
268
269 // Check for CLI env, to add the CLI commands.
270 if ( defined( 'WP_CLI' ) && WP_CLI ) {
271 WP_CLI::add_command(
272 'activitypub',
273 '\Activitypub\Cli',
274 array(
275 'shortdesc' => __( 'ActivityPub related commands: Meta-Infos, Delete and soon Self-Destruct.', 'activitypub' ),
276 )
277 );
278 }
279