PluginProbe
Parse.ly / 3.24.2
Parse.ly v3.24.2
3.24.2 3.24.1 3.24.0 3.23.7 3.23.6 3.23.5 3.23.4 3.23.3 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.17.0 3.18.0 3.18.1 3.19.0 3.19.1 3.19.2 3.19.3 3.2.0 3.2.1 3.20.0 3.20.1 3.20.2 All 106 releases
← All changes | wp-parsely.php +279 -92 3.2.1 → 3.24.2 View file →
@@ -1,18 +1,18 @@
1 1 <?php
2 2 /**
3 3 * Parse.ly
4 4 *
5 - * @package Parsely\wp-parsely
6 - * @author Parse.ly
7 - * @copyright 2012 Parse.ly
8 - * @license GPL-2.0-or-later
5 + * @package Parsely
6 + * @author Parse.ly
7 + * @copyright 2012 Parse.ly
8 + * @license GPL-2.0-or-later
9 9 *
10 10 * @wordpress-plugin
11 11 * Plugin Name: Parse.ly
12 - * Plugin URI: https://www.parse.ly/help/integration/wordpress
12 + * Plugin URI: https://docs.parse.ly/wordpress
13 13 * Description: This plugin makes it a snap to add Parse.ly tracking code and metadata to your WordPress blog.
14 - * Version: 3.2.1
14 + * Version: 3.24.2
15 15 * Author: Parse.ly
16 16 * Author URI: https://www.parse.ly
17 17 * Text Domain: wp-parsely
18 18 * License: GPL-2.0-or-later
@@ -17,10 +17,10 @@
17 17 * Text Domain: wp-parsely
18 18 * License: GPL-2.0-or-later
19 19 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
20 20 * GitHub Plugin URI: https://github.com/Parsely/wp-parsely
21 - * Requires PHP: 7.1
22 - * Requires WP: 5.0.0
21 + * Requires PHP: 7.4
22 + * Requires WP: 6.1.0
23 23 */
24 24
25 25 declare(strict_types=1);
26 26
@@ -25,135 +25,190 @@
25 25 declare(strict_types=1);
26 26
27 27 namespace Parsely;
28 28
29 -use Parsely\Endpoints\Related_API_Proxy;
29 +use Parsely\Content_Helper\Dashboard_Widget;
30 +use Parsely\Content_Helper\Editor_Sidebar;
31 +use Parsely\Content_Helper\Post_List_Stats;
30 32 use Parsely\Endpoints\GraphQL_Metadata;
31 33 use Parsely\Endpoints\Rest_Metadata;
34 +use Parsely\Headline_Testing;
32 35 use Parsely\Integrations\Amp;
33 -use Parsely\Integrations\Facebook_Instant_Articles;
34 36 use Parsely\Integrations\Google_Web_Stories;
35 37 use Parsely\Integrations\Integrations;
36 -use Parsely\RemoteAPI\Cached_Proxy;
37 -use Parsely\RemoteAPI\Related_Proxy;
38 -use Parsely\RemoteAPI\WordPress_Cache;
39 38 use Parsely\UI\Admin_Bar;
40 39 use Parsely\UI\Admin_Warning;
40 +use Parsely\UI\Dashboard_Page;
41 +use Parsely\UI\Metadata_Renderer;
42 +use Parsely\UI\Network_Admin_Sites_List;
41 43 use Parsely\UI\Plugins_Actions;
42 -use Parsely\UI\Network_Admin_Sites_List;
43 44 use Parsely\UI\Recommended_Widget;
44 45 use Parsely\UI\Row_Actions;
45 46 use Parsely\UI\Settings_Page;
47 +use Parsely\UI\Site_Health;
46 48
47 49 if ( class_exists( Parsely::class ) ) {
48 50 return;
49 51 }
50 52
51 -const PARSELY_VERSION = '3.2.1';
52 -const PARSELY_FILE = __FILE__;
53 +const PARSELY_VERSION = '3.24.2';
54 +const PARSELY_FILE = __FILE__;
55 +const PARSELY_DATA_SCHEMA_VERSION = '1';
56 +const PARSELY_CACHE_GROUP = 'wp-parsely';
53 57
54 -require __DIR__ . '/src/class-parsely.php';
55 -require __DIR__ . '/src/class-scripts.php';
56 -require __DIR__ . '/src/class-dashboard-link.php';
57 -require __DIR__ . '/src/UI/class-admin-bar.php';
58 -require __DIR__ . '/src/Endpoints/class-metadata-endpoint.php';
59 -require __DIR__ . '/src/Endpoints/class-graphql-metadata.php';
58 +if ( file_exists( __DIR__ . '/vendor/autoload.php' ) ) {
59 + require_once __DIR__ . '/vendor/autoload.php';
60 +}
60 61
62 +// Load Telemetry classes.
63 +require_once __DIR__ . '/src/Telemetry/telemetry-init.php';
64 +
65 +/**
66 + * Gets the Parsely object.
67 + *
68 + * @since 3.19.0
69 + *
70 + * @return Parsely The Parsely object.
71 + */
72 +function get_parsely(): Parsely {
73 + if ( ! isset( $GLOBALS['parsely'] ) ) {
74 + $GLOBALS['parsely'] = new Parsely();
75 + }
76 +
77 + return $GLOBALS['parsely'];
78 +}
79 +
61 80 add_action( 'plugins_loaded', __NAMESPACE__ . '\\parsely_initialize_plugin' );
62 81 /**
63 - * Register the basic classes to initialize the plugin.
64 - *
65 - * @return void
82 + * Registers the basic classes to initialize the plugin.
66 83 */
67 84 function parsely_initialize_plugin(): void {
68 - $GLOBALS['parsely'] = new Parsely();
69 - $GLOBALS['parsely']->run();
85 + $parsely = get_parsely();
86 + $parsely->run();
70 87
71 88 if ( class_exists( 'WPGraphQL' ) ) {
72 - $graphql = new GraphQL_Metadata( $GLOBALS['parsely'] );
89 + $graphql = new GraphQL_Metadata( $parsely );
73 90 $graphql->run();
74 91 }
75 92
76 - $scripts = new Scripts( $GLOBALS['parsely'] );
93 + $scripts = new Scripts( $parsely );
77 94 $scripts->run();
78 95
79 - $admin_bar = new Admin_Bar( $GLOBALS['parsely'] );
96 + $admin_bar = new Admin_Bar( $parsely );
80 97 $admin_bar->run();
98 +
99 + $metadata_renderer = new Metadata_Renderer( $parsely );
100 + $metadata_renderer->run();
101 +
102 + // Initialize Headline Testing feature.
103 + $headline_testing = new Headline_Testing( $parsely );
104 + $headline_testing->run();
81 105 }
82 106
83 -require __DIR__ . '/src/UI/class-admin-warning.php';
84 -require __DIR__ . '/src/UI/class-plugins-actions.php';
85 -require __DIR__ . '/src/UI/class-row-actions.php';
107 +add_action( 'admin_init', __NAMESPACE__ . '\\parsely_admin_init_register' );
108 +/**
109 + * Registers the Parse.ly wp-admin warnings, plugin actions and row actions.
110 + */
111 +function parsely_admin_init_register(): void {
112 + $parsely = get_parsely();
86 113
87 -add_action( 'admin_init', __NAMESPACE__ . '\\parsely_admin_init_register' );
114 + ( new Admin_Warning( $parsely ) )->run();
115 + ( new Plugins_Actions() )->run();
116 + ( new Row_Actions( $parsely ) )->run();
117 + ( new Post_List_Stats( $parsely ) )->run();
118 + ( new Site_Health( $parsely ) )->run();
119 + ( new Dashboard_Widget( $parsely ) )->run();
120 +}
121 +
122 +add_action( 'admin_init', __NAMESPACE__ . '\\create_engagement_boost_changeset_post' );
88 123 /**
89 - * Register the Parse.ly wp-admin warnings, plugin actions and row actions.
124 + * Creates a predefined changeset post in order to make the Engagement Boost
125 + * preview work for non-administrator user roles.
90 126 *
91 - * @return void
127 + * When the Engagement Boost preview iframe is loaded, it calls the WordPress
128 + * Customizer in the `iFrameSrc()` function. The Customizer requires the current
129 + * user to have the `customize` capability (available to Administrators), or the
130 + * passed UUID to have a corresponding changeset post in the database. Otherwise
131 + * it fails with -1 ("Non-existent changeset UUID") around line 561 in
132 + * `class-wp-customize-manager.php` and prevents preview, displaying "-1".
133 + *
134 + * By creating a predefined changeset post with a known UUID that we use in
135 + * `iFrameSrc()`, we guarantee that the preview will work for all authorized
136 + * user roles.
137 + *
138 + * @since 3.20.7
92 139 */
93 -function parsely_admin_init_register(): void {
94 - $admin_warning = new Admin_Warning( $GLOBALS['parsely'] );
95 - $admin_warning->run();
140 +function create_engagement_boost_changeset_post(): void {
141 + if ( ! function_exists( 'post_exists' ) ) {
142 + return;
143 + }
96 144
97 - $plugins_actions = new Plugins_Actions();
98 - $plugins_actions->run();
145 + $parsely = get_parsely();
99 146
100 - $row_actions = new Row_Actions( $GLOBALS['parsely'] );
101 - $row_actions->run();
147 + if ( ! $parsely->api_secret_is_set() || ! Permissions::current_user_can_use_pch_feature(
148 + 'traffic_boost',
149 + $parsely->get_options()['content_helper']
150 + ) ) {
151 + return;
152 + }
153 +
154 + // Needs to match the UUID in `iFrameSrc()` in `preview-iframe.tsx`.
155 + $uuid = '905b130b-4129-4416-919c-9e31433a6f65';
156 + $post_id = post_exists( "wp-parsely-$uuid", '', '', 'customize_changeset', 'private' );
157 +
158 + if ( 0 === $post_id ) {
159 + wp_insert_post(
160 + array(
161 + 'post_type' => 'customize_changeset',
162 + 'post_name' => $uuid,
163 + 'post_title' => "wp-parsely-$uuid",
164 + 'post_status' => 'private',
165 + )
166 + );
167 + }
102 168 }
103 169
104 -require __DIR__ . '/src/UI/class-settings-page.php';
105 -require __DIR__ . '/src/UI/class-network-admin-sites-list.php';
106 -
107 170 add_action( 'init', __NAMESPACE__ . '\\parsely_wp_admin_early_register' );
108 171 /**
109 - * Register the additions the Parse.ly wp-admin settings page and Multisite Network Admin Sites List table.
110 - *
111 - * @return void
172 + * Registers the additions the Parse.ly wp-admin settings page and Multisite
173 + * Network Admin Sites List table.
112 174 */
113 175 function parsely_wp_admin_early_register(): void {
114 - $settings_page = new Settings_Page( $GLOBALS['parsely'] );
115 - $settings_page->run();
176 + $parsely = get_parsely();
116 177
117 - $network_admin_sites_list = new Network_Admin_Sites_List( $GLOBALS['parsely'] );
178 + // Plugin dashboard page.
179 + $GLOBALS['parsely_dashboard_page'] = new Dashboard_Page( $parsely );
180 + $GLOBALS['parsely_dashboard_page']->run();
181 +
182 + // Plugin settings page.
183 + $GLOBALS['parsely_settings_page'] = new Settings_Page( $parsely );
184 + $GLOBALS['parsely_settings_page']->run();
185 +
186 + $network_admin_sites_list = new Network_Admin_Sites_List( $parsely );
118 187 $network_admin_sites_list->run();
188 +
189 + // Initialize the REST API Controller.
190 + $rest_api_controller = $parsely->get_rest_api_controller();
191 + $rest_api_controller->init();
119 192 }
120 193
121 -require __DIR__ . '/src/RemoteAPI/interface-cache.php';
122 -require __DIR__ . '/src/RemoteAPI/interface-proxy.php';
123 -require __DIR__ . '/src/RemoteAPI/class-base-proxy.php';
124 -require __DIR__ . '/src/RemoteAPI/class-cached-proxy.php';
125 -require __DIR__ . '/src/RemoteAPI/class-related-proxy.php';
126 -require __DIR__ . '/src/RemoteAPI/class-wordpress-cache.php';
127 -require __DIR__ . '/src/Endpoints/class-related-api-proxy.php';
128 -require __DIR__ . '/src/Endpoints/class-rest-metadata.php';
129 -
130 194 add_action( 'rest_api_init', __NAMESPACE__ . '\\parsely_rest_api_init' );
131 195 /**
132 - * Register REST Endpoints that act as a proxy to the Parse.ly API.
133 - * This is needed to get around a CORS issues with Firefox.
196 + * Registers REST Endpoints that act as a proxy to the Parse.ly API.
197 + * This is needed to get around CORS issues with Firefox.
134 198 *
135 199 * @since 3.2.0
136 - *
137 - * @return void
138 200 */
139 201 function parsely_rest_api_init(): void {
140 - $rest = new Rest_Metadata( $GLOBALS['parsely'] );
202 + $parsely = get_parsely();
203 +
204 + $rest = new Rest_Metadata( $parsely );
141 205 $rest->run();
142 -
143 - $proxy = new Related_Proxy( $GLOBALS['parsely'] );
144 - $cached_proxy = new Cached_Proxy( $proxy, new WordPress_Cache() );
145 - $endpoint = new Related_API_Proxy( $GLOBALS['parsely'], $cached_proxy );
146 - $endpoint->run();
147 206 }
148 207
149 -require __DIR__ . '/src/blocks/recommendations/class-recommendations-block.php';
150 -
151 208 add_action( 'init', __NAMESPACE__ . '\\init_recommendations_block' );
152 209 /**
153 - * Register the Recommendations Block.
154 - *
155 - * @return void
210 + * Registers the Recommendations Block.
156 211 */
157 212 function init_recommendations_block(): void {
158 213 $recommendations_block = new Recommendations_Block();
159 214 $recommendations_block->run();
@@ -158,40 +213,172 @@
158 213 $recommendations_block = new Recommendations_Block();
159 214 $recommendations_block->run();
160 215 }
161 216
162 -require __DIR__ . '/src/UI/class-recommended-widget.php';
217 +add_action( 'enqueue_block_editor_assets', __NAMESPACE__ . '\\init_content_helper_editor_sidebar' );
218 +/**
219 + * Inserts the PCH Editor Sidebar.
220 + *
221 + * @since 3.5.0 Moved from Parsely\Scripts\enqueue_block_editor_assets().
222 + * @since 3.9.0 Renamed from init_content_helper().
223 + */
224 +function init_content_helper_editor_sidebar(): void {
225 + $GLOBALS['parsely_editor_sidebar']->run();
226 +}
163 227
228 +add_action( 'enqueue_block_assets', __NAMESPACE__ . '\\init_content_helper_canvas_styles' );
229 +/**
230 + * Inserts the PCH Editor Sidebar styles that need to reach the Editor canvas.
231 + *
232 + * @since 3.24.0
233 + */
234 +function init_content_helper_canvas_styles(): void {
235 + if ( ! isset( $GLOBALS['parsely_editor_sidebar'] ) ) {
236 + return;
237 + }
238 +
239 + $GLOBALS['parsely_editor_sidebar']->run_canvas_styles();
240 +}
241 +
242 +add_action( 'admin_init', __NAMESPACE__ . '\\parsely_content_helper_editor_sidebar_features' );
243 +add_action( 'rest_api_init', __NAMESPACE__ . '\\parsely_content_helper_editor_sidebar_features' );
244 +/**
245 + * Initializes the PCH Editor Sidebar features.
246 + *
247 + * @since 3.16.0
248 + */
249 +function parsely_content_helper_editor_sidebar_features(): void {
250 + if ( ! isset( $GLOBALS['parsely_editor_sidebar'] ) ) {
251 + /**
252 + * The Editor Sidebar instance.
253 + *
254 + * @since 3.16.0
255 + * @var Editor_Sidebar $GLOBALS['parsely_editor_sidebar']
256 + */
257 + $parsely = get_parsely();
258 +
259 + $GLOBALS['parsely_editor_sidebar'] = new Editor_Sidebar( $parsely );
260 + $GLOBALS['parsely_editor_sidebar']->init_features();
261 + }
262 +}
263 +
164 264 add_action( 'widgets_init', __NAMESPACE__ . '\\parsely_recommended_widget_register' );
165 265 /**
166 - * Register the Parse.ly Recommended widget.
167 - *
168 - * @return void
266 + * Registers the Parse.ly Recommended widget.
169 267 */
170 268 function parsely_recommended_widget_register(): void {
171 - register_widget( Recommended_Widget::class );
269 + $parsely = get_parsely();
270 +
271 + register_widget( new Recommended_Widget( $parsely ) );
172 272 }
173 273
174 -require __DIR__ . '/src/Integrations/class-integration.php';
175 -require __DIR__ . '/src/Integrations/class-integrations.php';
176 -require __DIR__ . '/src/Integrations/class-amp.php';
177 -require __DIR__ . '/src/Integrations/class-facebook-instant-articles.php';
178 -require __DIR__ . '/src/Integrations/class-google-web-stories.php';
179 -
180 -add_action( 'init', __NAMESPACE__ . '\\parsely_integrations' );
274 +add_action( 'init', __NAMESPACE__ . '\\parsely_integrations' ); // @phpstan-ignore-line
181 275 /**
182 - * Instantiate Integrations collection and register built-in integrations.
276 + * Instantiates Integrations collection and registers built-in integrations.
183 277 *
184 278 * @since 2.6.0
185 279 *
280 + * @param Parsely|string|null $parsely The Parsely object to pass to the integrations.
186 281 * @return Integrations
187 282 */
188 -function parsely_integrations(): Integrations {
189 - $parsely_integrations = new Integrations();
283 +function parsely_integrations( $parsely = null ): Integrations {
284 + // If $parsely value is "", then this function is being called by the init
285 + // hook and we can get the value from $GLOBALS. If $parsely is an instance
286 + // of the Parsely object, then this function is being called by a test.
287 + if ( ! is_object( $parsely ) || get_class( $parsely ) !== Parsely::class ) {
288 + $parsely = get_parsely();
289 + }
290 +
291 + $parsely_integrations = new Integrations( $parsely );
190 292 $parsely_integrations->register( 'amp', Amp::class );
191 - $parsely_integrations->register( 'fbia', Facebook_Instant_Articles::class );
192 293 $parsely_integrations->register( 'webstories', Google_Web_Stories::class );
193 294 $parsely_integrations = apply_filters( 'wp_parsely_add_integration', $parsely_integrations );
194 295 $parsely_integrations->integrate();
195 296
196 297 return $parsely_integrations;
298 +}
299 +
300 +add_action( 'admin_init', __NAMESPACE__ . '\\parsely_check_data_schema_updates', 999 );
301 +/**
302 + * Checks and performs any data schema updates.
303 + *
304 + * @since 3.19.0 Handles the update from schema version 0 to 1.
305 + */
306 +function parsely_check_data_schema_updates(): void {
307 + $current_data_schema_version = get_option( 'parsely_data_schema_version' );
308 +
309 + if ( false === $current_data_schema_version ) {
310 + $current_data_schema_version = 0;
311 + }
312 +
313 + if ( PARSELY_DATA_SCHEMA_VERSION <= $current_data_schema_version ) {
314 + return;
315 + }
316 +
317 + /**
318 + * Updates the smart links to have the Smart Link Status terms,
319 + * and checks the _smart_link_applied meta, if it exists.
320 + *
321 + * Schema version 1.
322 + *
323 + * @since 3.19.0
324 + */
325 + if ( 0 === $current_data_schema_version ) {
326 + // Get all the smart links that do not have any Smart Link Status terms.
327 + // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.get_posts_get_posts
328 + $smart_links_without_status = get_posts(
329 + array(
330 + 'post_type' => 'parsely_smart_link',
331 + 'posts_per_page' => -1, // phpcs:ignore WordPressVIPMinimum.Performance.NoPaging.posts_per_page_posts_per_page
332 + 'fields' => 'ids',
333 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
334 + 'tax_query' => array(
335 + array(
336 + 'taxonomy' => 'smart_link_status',
337 + 'field' => 'name',
338 + 'terms' => \Parsely\Models\Smart_Link_Status::get_all_statuses(),
339 + 'operator' => 'NOT IN',
340 + ),
341 + ),
342 + )
343 + );
344 +
345 + if ( count( $smart_links_without_status ) === 0 ) {
346 + update_option( 'parsely_data_schema_version', PARSELY_DATA_SCHEMA_VERSION );
347 + return;
348 + }
349 +
350 + // Loop through the smart links and update them to have the Smart Link Status terms.
351 + foreach ( $smart_links_without_status as $post_id ) {
352 + $smart_link = \Parsely\Models\Smart_Link::get_smart_link_by_id( intval( $post_id ) );
353 +
354 + if ( false === $smart_link ) {
355 + continue;
356 + }
357 +
358 + $meta_exists = metadata_exists( 'post', $post_id, '_smart_link_applied' );
359 +
360 + // If there is no meta, it means that the smart link is considered applied,
361 + // for backwards compatibility with Parse.ly < 3.18.0.
362 + if ( ! $meta_exists ) {
363 + $smart_link->set_status( \Parsely\Models\Smart_Link_Status::APPLIED, true );
364 + continue;
365 + }
366 +
367 + // Get the value of the _smart_link_applied meta.
368 + $meta_value = get_post_meta( $post_id, '_smart_link_applied', true );
369 +
370 + // If the meta value is true, then the smart link is considered applied.
371 + if ( 'true' === $meta_value || true === $meta_value ) {
372 + $smart_link->set_status( \Parsely\Models\Smart_Link_Status::APPLIED, true );
373 + } else {
374 + // If the meta value is not true, then the smart link is considered pending.
375 + $smart_link->set_status( \Parsely\Models\Smart_Link_Status::PENDING, true );
376 + }
377 +
378 + // Flush the cache for the smart link.
379 + $smart_link->flush_all_cache();
380 + }
381 +
382 + update_option( 'parsely_data_schema_version', PARSELY_DATA_SCHEMA_VERSION );
383 + }
197 384 }