PluginProbe
Parse.ly / 3.8.4
Parse.ly v3.8.4
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 3.20.3 All 105 releases
← All changes | src/class-parsely.php +125 -585 3.17.03.8.4 View file →
@@ -9,14 +9,9 @@
9 9 declare(strict_types=1);
10 10
11 11 namespace Parsely;
12 12
13 -use Parsely\REST_API\REST_API_Controller;
14 -use Parsely\Services\Content_API\Content_API_Service;
15 -use Parsely\Services\Suggestions_API\Suggestions_API_Service;
16 13 use Parsely\UI\Metadata_Renderer;
17 -use Parsely\UI\Settings_Page;
18 -use Parsely\Utils\Utils;
19 14 use WP_Post;
20 15
21 16 /**
22 17 * Holds most of the logic for the plugin.
@@ -30,9 +25,8 @@
30 25 * api_secret: string,
31 26 * use_top_level_cats: bool,
32 27 * custom_taxonomy_section: string,
33 28 * cats_as_tags: bool,
34 - * content_helper: Parsely_Options_Content_Helper,
35 29 * track_authenticated_users: bool,
36 30 * lowercase_tags: bool,
37 31 * force_https_canonicals: bool,
38 32 * track_post_types: string[],
@@ -37,39 +31,18 @@
37 31 * force_https_canonicals: bool,
38 32 * track_post_types: string[],
39 33 * track_page_types: string[],
40 34 * track_post_types_as?: array<string, string>,
41 - * full_metadata_in_non_posts: bool,
42 35 * disable_javascript: bool,
43 36 * disable_amp: bool,
44 37 * meta_type: string,
45 38 * logo: string,
46 39 * metadata_secret: string,
40 + * parsely_wipe_metadata_cache: bool,
47 41 * disable_autotrack: bool,
48 42 * plugin_version: string,
49 43 * }
50 44 *
51 - * @phpstan-type Parsely_Options_Content_Helper array{
52 - * ai_features_enabled: bool,
53 - * smart_linking: Parsely_Options_Content_Helper_Feature,
54 - * title_suggestions: Parsely_Options_Content_Helper_Feature,
55 - * excerpt_suggestions: Parsely_Options_Content_Helper_Feature,
56 - * }
57 - *
58 - * @phpstan-type Parsely_Options_Content_Helper_Feature array{
59 - * enabled: bool,
60 - * allowed_user_roles: string[],
61 - * }
62 - *
63 - * @phpstan-type WP_HTTP_Request_Args array{
64 - * method?: string,
65 - * timeout?: float,
66 - * blocking?: bool,
67 - * headers?: array<string, string>,
68 - * body?: string,
69 - * data_format?: string,
70 - * }
71 - *
72 45 * @phpstan-import-type Metadata_Attributes from Metadata
73 46 */
74 47 class Parsely {
75 48 /**
@@ -74,84 +47,49 @@
74 47 class Parsely {
75 48 /**
76 49 * Declare our constants
77 50 */
78 - public const VERSION = PARSELY_VERSION;
79 - public const MENU_SLUG = 'parsely'; // The page param passed to options-general.php.
80 - public const OPTIONS_KEY = 'parsely'; // The key used to store options in the WP database.
81 - public const CAPABILITY = 'manage_options'; // The capability required to administer settings.
82 - public const DASHBOARD_BASE_URL = 'https://dash.parsely.com';
51 + public const VERSION = PARSELY_VERSION;
52 + public const MENU_SLUG = 'parsely'; // Defines the page param passed to options-general.php.
53 + public const OPTIONS_KEY = 'parsely'; // Defines the key used to store options in the WP database.
54 + public const CAPABILITY = 'manage_options'; // The capability required for the user to administer settings.
55 + public const DASHBOARD_BASE_URL = 'https://dash.parsely.com';
56 + public const PUBLIC_API_BASE_URL = 'https://api.parsely.com/v2';
83 57
84 58 /**
85 - * The Content API service.
86 - *
87 - * @var ?Content_API_Service $content_api_service
88 - */
89 - private $content_api_service;
90 -
91 - /**
92 - * The Suggestions API service.
93 - *
94 - * @var ?Suggestions_API_Service $suggestions_api_service
95 - */
96 - private $suggestions_api_service;
97 -
98 - /**
99 - * The Parse.ly internal REST API controller.
100 - *
101 - * @var REST_API_Controller|null $rest_api_controller
102 - */
103 - private $rest_api_controller;
104 -
105 - /**
106 59 * Declare some class properties
107 60 *
108 61 * @var Parsely_Options $option_defaults The defaults we need for the class.
109 62 */
110 63 private $option_defaults = array(
111 - 'apikey' => '',
112 - 'content_id_prefix' => '',
113 - 'api_secret' => '',
114 - 'use_top_level_cats' => false,
115 - 'custom_taxonomy_section' => 'category',
116 - 'cats_as_tags' => false,
117 - 'content_helper' => array(
118 - 'ai_features_enabled' => true,
119 - 'smart_linking' => array(
120 - 'enabled' => true,
121 - 'allowed_user_roles' => array( 'administrator' ),
122 - ),
123 - 'title_suggestions' => array(
124 - 'enabled' => true,
125 - 'allowed_user_roles' => array( 'administrator' ),
126 - ),
127 - 'excerpt_suggestions' => array(
128 - 'enabled' => true,
129 - 'allowed_user_roles' => array( 'administrator' ),
130 - ),
131 - ),
132 - 'track_authenticated_users' => false,
133 - 'lowercase_tags' => true,
134 - 'force_https_canonicals' => false,
135 - 'track_post_types' => array(),
136 - 'track_page_types' => array(),
137 - 'full_metadata_in_non_posts' => true,
138 - 'disable_javascript' => false,
139 - 'disable_amp' => false,
140 - 'meta_type' => 'json_ld',
141 - 'logo' => '',
142 - 'metadata_secret' => '',
143 - 'disable_autotrack' => false,
144 - 'plugin_version' => self::VERSION,
64 + 'apikey' => '',
65 + 'content_id_prefix' => '',
66 + 'api_secret' => '',
67 + 'use_top_level_cats' => false,
68 + 'custom_taxonomy_section' => 'category',
69 + 'cats_as_tags' => false,
70 + 'track_authenticated_users' => false,
71 + 'lowercase_tags' => true,
72 + 'force_https_canonicals' => false,
73 + 'track_post_types' => array( 'post' ),
74 + 'track_page_types' => array( 'page' ),
75 + 'disable_javascript' => false,
76 + 'disable_amp' => false,
77 + 'meta_type' => 'json_ld',
78 + 'logo' => '',
79 + 'metadata_secret' => '',
80 + 'parsely_wipe_metadata_cache' => false,
81 + 'disable_autotrack' => false,
82 + 'plugin_version' => '',
145 83 );
146 84
147 85 /**
148 86 * Declare post types that Parse.ly will process as "posts".
149 87 *
88 + * @link https://www.parse.ly/help/integration/jsonld#distinguishing-between-posts-and-pages
89 + *
150 90 * @since 2.5.0
151 91 * @var string[]
152 - *
153 - * @link https://docs.parse.ly/metadata-jsonld/#distinguishing-between-posts-and-non-posts-pages
154 92 */
155 93 public const SUPPORTED_JSONLD_POST_TYPES = array(
156 94 'NewsArticle',
157 95 'Article',
@@ -160,26 +98,17 @@
160 98 'LiveBlogPosting',
161 99 'Report',
162 100 'Review',
163 101 'CreativeWork',
164 - 'OpinionNewsArticle',
165 - 'AnalysisNewsArticle',
166 - 'BackgroundNewsArticle',
167 - 'ReviewNewsArticle',
168 - 'ReportageNewsArticle',
169 - 'Recipe',
170 - 'AdvertiserContentArticle',
171 - 'MedicalWebPage',
172 - 'PodcastEpisode',
173 102 );
174 103
175 104 /**
176 105 * Declare post types that Parse.ly will process as "non-posts".
177 106 *
107 + * @link https://www.parse.ly/help/integration/jsonld#distinguishing-between-posts-and-pages
108 + *
178 109 * @since 2.5.0
179 110 * @var string[]
180 - *
181 - * @link https://docs.parse.ly/metadata-jsonld/#distinguishing-between-posts-and-non-posts-pages
182 111 */
183 112 public const SUPPORTED_JSONLD_NON_POST_TYPES = array(
184 113 'WebPage',
185 114 'Event',
@@ -196,70 +125,15 @@
196 125 */
197 126 private static $all_supported_types;
198 127
199 128 /**
200 - * Returns whether credentials are being managed at the platform level.
201 - *
202 - * This allows hosting providers to provide a more customized experience for
203 - * the plugin by handling credentials automatically.
204 - *
205 - * @since 3.9.0
206 - * @access private
207 - * @var bool
208 - */
209 - public $are_credentials_managed;
210 -
211 - /**
212 - * Holds the managed options and their values.
213 - *
214 - * This allows hosting providers to provide a more customized experience for
215 - * the plugin by handling options automatically.
216 - *
217 - * @since 3.9.0
218 - * @access private
219 - * @var array<empty>|array<string, bool|string|null>
220 - */
221 - public $managed_options = array();
222 -
223 - /**
224 129 * Constructor.
225 130 */
226 131 public function __construct() {
227 132 self::$all_supported_types = array_merge( self::SUPPORTED_JSONLD_POST_TYPES, self::SUPPORTED_JSONLD_NON_POST_TYPES );
228 -
229 - $this->are_credentials_managed = $this->are_credentials_managed();
230 - $this->set_managed_options();
231 -
232 - $this->allow_parsely_remote_requests();
233 133 }
234 134
235 135 /**
236 - * Gets the allowed post statuses for tracking.
237 - *
238 - * Uses the `wp_parsely_trackable_statuses` filter to determine which post statuses are allowed to be tracked.
239 - *
240 - * @since 3.17.0
241 - *
242 - * @param WP_Post|int|null $post The post object.
243 - * @return array<string> The allowed post statuses.
244 - */
245 - public static function get_trackable_statuses( $post = null ): array {
246 - /**
247 - * Filters the statuses that are permitted to be tracked.
248 - *
249 - * By default, the only status tracked is 'publish'. Use this filter if
250 - * you have other published content that has a different (custom) status.
251 - *
252 - * @since 2.5.0
253 - * @since 3.17.0 Filter extracted to a separate method.
254 - *
255 - * @param string[] $trackable_statuses The list of post statuses that are allowed to be tracked.
256 - * @param WP_Post|int|null $post Which post object or ID is being checked.
257 - */
258 - return apply_filters( 'wp_parsely_trackable_statuses', array( 'publish' ), $post );
259 - }
260 -
261 - /**
262 136 * Registers action and filter hook callbacks, and immediately upgrades
263 137 * options if needed.
264 138 */
265 139 public function run(): void {
@@ -275,69 +149,35 @@
275 149 */
276 150 $callable = array( $this, $method );
277 151 call_user_func_array( $callable, array( $options ) );
278 152 }
279 -
280 153 // Update our version info.
281 154 $options['plugin_version'] = self::VERSION;
282 155 update_option( self::OPTIONS_KEY, $options );
283 156 }
284 157
158 + // phpcs:ignore WordPress.WP.CronInterval.CronSchedulesInterval
159 + add_filter( 'cron_schedules', array( $this, 'wpparsely_add_cron_interval' ) );
160 + add_action( 'parsely_bulk_metas_update', array( $this, 'bulk_update_posts' ) );
285 161 add_action( 'save_post', array( $this, 'update_metadata_endpoint' ) );
286 162 }
287 163
288 164 /**
289 - * Returns the Content API service.
165 + * Adds 10 minute cron interval.
290 166 *
291 - * This method returns the Content API service, which is used to interact with the Parse.ly Content API.
167 + * @param array<string, mixed> $schedules WP schedules array.
292 168 *
293 - * @since 3.17.0
294 - *
295 - * @return Content_API_Service
169 + * @return array<string, mixed>
296 170 */
297 - public function get_content_api(): Content_API_Service {
298 - if ( ! isset( $this->content_api_service ) ) {
299 - $this->content_api_service = new Content_API_Service( $this );
300 - }
301 -
302 - return $this->content_api_service;
171 + public function wpparsely_add_cron_interval( array $schedules ): array {
172 + $schedules['everytenminutes'] = array(
173 + 'interval' => 600, // time in seconds.
174 + 'display' => __( 'Every 10 Minutes', 'wp-parsely' ),
175 + );
176 + return $schedules;
303 177 }
304 178
305 179 /**
306 - * Returns the Suggestions API service.
307 - *
308 - * This method returns the Suggestions API service, which is used to interact with the Parse.ly Suggestions API.
309 - *
310 - * @since 3.17.0
311 - *
312 - * @return Suggestions_API_Service
313 - */
314 - public function get_suggestions_api(): Suggestions_API_Service {
315 - if ( ! isset( $this->suggestions_api_service ) ) {
316 - $this->suggestions_api_service = new Suggestions_API_Service( $this );
317 - }
318 -
319 - return $this->suggestions_api_service;
320 - }
321 -
322 - /**
323 - * Gets the REST API controller.
324 - *
325 - * If the controller is not set, a new instance is created.
326 - *
327 - * @since 3.17.0
328 - *
329 - * @return REST_API_Controller
330 - */
331 - public function get_rest_api_controller(): REST_API_Controller {
332 - if ( ! isset( $this->rest_api_controller ) ) {
333 - $this->rest_api_controller = new REST_API_Controller( $this );
334 - }
335 -
336 - return $this->rest_api_controller;
337 - }
338 -
339 - /**
340 180 * Gets the full URL of the JavaScript tracker file for the site. If an API
341 181 * key is not set, return an empty string.
342 182 *
343 183 * @since 3.2.0
@@ -411,9 +251,9 @@
411 251 *
412 252 * @param bool $skip True if the password check should be skipped.
413 253 * @param int|WP_Post $post Which post object or ID is being checked.
414 254 *
415 - * @return bool
255 + * @returns bool
416 256 */
417 257 $skip_password_check = apply_filters( 'wp_parsely_skip_post_password_check', false, $post );
418 258 if ( ! $skip_password_check && post_password_required( $post ) ) {
419 259 $cache[ $post_id ] = false;
@@ -419,9 +259,20 @@
419 259 $cache[ $post_id ] = false;
420 260 return false;
421 261 }
422 262
423 - $statuses = self::get_trackable_statuses( $post );
263 + /**
264 + * Filters the statuses that are permitted to be tracked.
265 + *
266 + * By default, the only status tracked is 'publish'. Use this filter if
267 + * you have other published content that has a different (custom) status.
268 + *
269 + * @since 2.5.0
270 + *
271 + * @param string[] $trackable_statuses The list of post statuses that are allowed to be tracked.
272 + * @param int|WP_Post $post Which post object or ID is being checked.
273 + */
274 + $statuses = apply_filters( 'wp_parsely_trackable_statuses', array( 'publish' ), $post );
424 275 $cache[ $post_id ] = in_array( get_post_status( $post ), $statuses, true );
425 276 return $cache[ $post_id ];
426 277 }
427 278
@@ -434,8 +285,9 @@
434 285 * @see \Parsely\Metadata::construct_metadata
435 286 *
436 287 * @param array<string, mixed> $parsely_options parsely_options array.
437 288 * @param WP_Post $post object.
289 + *
438 290 * @return Metadata_Attributes
439 291 */
440 292 public function construct_parsely_metadata( array $parsely_options, WP_Post $post ) {
441 293 _deprecated_function( __FUNCTION__, '3.3', 'Metadata::construct_metadata()' );
@@ -471,14 +323,14 @@
471 323 'authors' => $metadata['creator'] ?? '',
472 324 'tags' => $metadata['keywords'] ?? '',
473 325 );
474 326
475 - $parsely_api_base_url = Content_API_Service::get_base_url();
476 - $parsely_api_endpoint = $parsely_api_base_url . '/metadata/posts';
327 + $parsely_api_endpoint = self::PUBLIC_API_BASE_URL . '/metadata/posts';
477 328 $parsely_metadata_secret = $parsely_options['metadata_secret'];
478 -
479 - $headers = array( 'Content-Type' => 'application/json' );
480 - $body = wp_json_encode(
329 + $headers = array(
330 + 'Content-Type' => 'application/json',
331 + );
332 + $body = wp_json_encode(
481 333 array(
482 334 'secret' => $parsely_metadata_secret,
483 335 'apikey' => $this->get_site_id(),
484 336 'metadata' => $endpoint_metadata,
@@ -483,27 +335,67 @@
483 335 'apikey' => $this->get_site_id(),
484 336 'metadata' => $endpoint_metadata,
485 337 )
486 338 );
339 + $response = wp_remote_post(
340 + $parsely_api_endpoint,
341 + array(
342 + 'method' => 'POST',
343 + 'headers' => $headers,
344 + 'blocking' => false,
345 + 'body' => $body,
346 + 'data_format' => 'body',
347 + )
348 + );
487 349
350 + if ( ! is_wp_error( $response ) ) {
351 + $current_timestamp = time();
352 + update_post_meta( $post_id, 'parsely_metadata_last_updated', $current_timestamp );
353 + }
354 + }
355 +
356 + /**
357 + * Updates posts with Parsely metadata API in bulk.
358 + */
359 + public function bulk_update_posts(): void {
360 + global $wpdb;
361 + $allowed_types = $this->get_all_track_types();
362 + $allowed_types_string = implode(
363 + ', ',
364 + array_map(
365 + function( $v ) {
366 + return "'" . esc_sql( $v ) . "'";
367 + },
368 + $allowed_types
369 + )
370 + );
371 +
488 372 /**
489 - * POST request options.
373 + * Variable.
490 374 *
491 - * @var WP_HTTP_Request_Args $options
375 + * @var int[]|false
492 376 */
493 - $options = array(
494 - 'method' => 'POST',
495 - 'headers' => $headers,
496 - 'blocking' => false,
497 - 'body' => $body,
498 - 'data_format' => 'body',
499 - );
377 + $ids = wp_cache_get( 'parsely_post_ids_need_meta_updating' );
378 + if ( false === $ids ) {
379 + $ids = array();
380 + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
381 + $results = $wpdb->get_results(
382 + $wpdb->prepare( "SELECT DISTINCT(id) FROM {$wpdb->posts} WHERE post_type IN (\" . %s . \") AND id NOT IN (SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = 'parsely_metadata_last_updated');", $allowed_types_string ),
383 + ARRAY_N
384 + );
385 + foreach ( $results as $result ) {
386 + $ids[] = $result[0];
387 + }
388 + wp_cache_set( 'parsely_post_ids_need_meta_updating', $ids, '', 86400 );
389 + }
500 390
501 - $response = wp_remote_post( $parsely_api_endpoint, $options );
502 -
503 - if ( ! is_wp_error( $response ) ) {
504 - $current_timestamp = time();
505 - update_post_meta( $post_id, 'parsely_metadata_last_updated', $current_timestamp );
391 + for ( $i = 0; $i < 100; $i++ ) {
392 + $post_id = array_pop( $ids );
393 + if ( null === $post_id ) {
394 + wp_clear_scheduled_hook( 'parsely_bulk_metas_update' );
395 + break;
396 + }
397 + $this->update_metadata_endpoint( $post_id );
506 398 }
507 399 }
508 400
509 401 /**
@@ -520,142 +412,26 @@
520 412 * Variable.
521 413 *
522 414 * @var Parsely_Options|null
523 415 */
524 - $options = get_option( self::OPTIONS_KEY, null );
416 + $options = get_option( self::OPTIONS_KEY, $this->option_defaults );
525 417
526 - // @phpstan-ignore isset.offset, booleanAnd.alwaysFalse
527 - if ( is_array( $options ) && ! isset( $options['full_metadata_in_non_posts'] ) ) {
528 - // Existing plugin installation without full metadata option.
529 - $this->set_default_full_metadata_in_non_posts();
530 - }
531 -
532 - // @phpstan-ignore isset.offset, booleanAnd.alwaysFalse
533 - if ( is_array( $options ) && ! isset( $options['content_helper'] ) ) {
534 - // Existing plugin installation without Content Helper options.
535 - $this->set_default_content_helper_settings_values();
536 - }
537 -
538 - // New plugin installation that hasn't saved its options yet.
539 418 if ( ! is_array( $options ) ) {
540 - $this->set_default_track_as_values();
541 - $this->set_default_full_metadata_in_non_posts();
542 - $options = $this->option_defaults;
419 + return $this->option_defaults;
543 420 }
544 421
545 - /**
546 - * Final options including managed credentials and options.
547 - *
548 - * @var Parsely_Options
549 - */
550 - return array_merge(
551 - $this->option_defaults,
552 - $options,
553 - $this->get_managed_credentials(),
554 - $this->managed_options
555 - );
422 + return array_merge( $this->option_defaults, $options );
556 423 }
557 424
558 425 /**
559 - * Returns the value of a nested option.
560 - *
561 - * @since 3.16.0
562 - *
563 - * @param string $option The option to get.
564 - * @param Parsely_Options $options The options to get the value from.
565 - * @return mixed The value of the nested option.
566 - */
567 - public static function get_nested_option_value( $option, $options ) {
568 - $keys = explode( '[', str_replace( ']', '', $option ) );
569 - $value = $options;
570 -
571 - foreach ( $keys as $key ) {
572 - if ( isset( $value[ $key ] ) ) {
573 - $value = $value[ $key ];
574 - }
575 - }
576 -
577 - return $value;
578 - }
579 -
580 - /**
581 - * Sets the default values for the track_post_types and track_page_types
582 - * options.
583 - *
584 - * @since 3.9.0
585 - */
586 - public function set_default_track_as_values(): void {
587 - $this->option_defaults['track_page_types'] = array();
588 - $this->option_defaults['track_post_types'] = array();
589 -
590 - $post_types = get_post_types( array( 'public' => true ) );
591 -
592 - foreach ( $post_types as $post_type ) {
593 - if ( ! post_type_supports( $post_type, 'editor' ) ) {
594 - continue;
595 - }
596 -
597 - if ( is_post_type_hierarchical( $post_type ) ) {
598 - $this->option_defaults['track_page_types'][] = $post_type;
599 - } else {
600 - $this->option_defaults['track_post_types'][] = $post_type;
601 - }
602 - }
603 - }
604 -
605 - /**
606 - * Sets the default value for the full_metadata_in_non_posts option.
607 - *
608 - * @since 3.14.0
609 - */
610 - public function set_default_full_metadata_in_non_posts(): void {
611 - $this->option_defaults['full_metadata_in_non_posts'] = true;
612 -
613 - // Usage of any of these filters will result in the setting being set
614 - // to false.
615 - $filter_tags = array(
616 - 'wp_parsely_metadata',
617 - 'wp_parsely_post_tags',
618 - 'wp_parsely_permalink',
619 - 'wp_parsely_post_category',
620 - 'wp_parsely_pre_authors',
621 - 'wp_parsely_post_authors',
622 - 'wp_parsely_custom_taxonomies',
623 - 'wp_parsely_post_type',
624 - );
625 -
626 - foreach ( $filter_tags as $filter_tag ) {
627 - if ( has_filter( $filter_tag ) ) {
628 - $this->option_defaults['full_metadata_in_non_posts'] = false;
629 - break;
630 - }
631 - }
632 - }
633 -
634 - /**
635 - * Sets the default values for Content Helper options.
636 - *
637 - * Gives PCH access to all users having the edit_posts capability, to keep
638 - * consistent behavior with plugin versions prior to 3.16.0.
639 - *
640 - * @since 3.16.0
641 - */
642 - public function set_default_content_helper_settings_values(): void {
643 - $this->option_defaults['content_helper'] =
644 - Permissions::build_pch_permissions_settings_array(
645 - true,
646 - array_keys( Permissions::get_user_roles_with_edit_posts_cap() )
647 - );
648 - }
649 -
650 - /**
651 426 * Gets the URL of the plugin's settings page.
652 427 *
653 428 * @param int|null $_blog_id The Blog ID for the multisite subsite to use
654 429 * for context (Default null for current).
430 + *
655 431 * @return string
656 432 */
657 - public static function get_settings_url( ?int $_blog_id = null ): string {
433 + public static function get_settings_url( int $_blog_id = null ): string {
658 434 return get_admin_url( $_blog_id, 'options-general.php?page=' . self::MENU_SLUG );
659 435 }
660 436
661 437 /**
@@ -672,10 +448,9 @@
672 448 public static function get_dash_url( string $site_id, string $page_url = '' ): string {
673 449 $result = trailingslashit( self::DASHBOARD_BASE_URL . '/' . $site_id ) . 'find';
674 450
675 451 if ( '' !== $page_url ) {
676 - $page_url = self::get_url_with_itm_source( $page_url, null );
677 - $result .= '?url=' . rawurlencode( $page_url );
452 + $result .= '?url=' . rawurlencode( $page_url );
678 453 }
679 454
680 455 return $result;
681 456 }
@@ -680,28 +455,8 @@
680 455 return $result;
681 456 }
682 457
683 458 /**
684 - * Adds or replaces the itm_source parameter in the URL. Removes the
685 - * parameter if the passed value is null or an empty string.
686 - *
687 - * @since 3.9.0
688 - *
689 - * @param string $url The URL to modify.
690 - * @param string|null $itm_source The value of the itm_source parameter.
691 - * @return string The resulting URL.
692 - */
693 - public static function get_url_with_itm_source( string $url, $itm_source ): string {
694 - if ( null === $itm_source || '' === $itm_source ) {
695 - return remove_query_arg( 'itm_source', $url );
696 - }
697 -
698 - $itm_source = rawurlencode( $itm_source );
699 -
700 - return add_query_arg( 'itm_source', $itm_source, $url );
701 - }
702 -
703 - /**
704 459 * Checks to see if the current user is a member of the current blog.
705 460 *
706 461 * @return bool
707 462 */
@@ -721,9 +476,9 @@
721 476 * types, "index" is returned.
722 477 *
723 478 * @since 2.5.0
724 479 *
725 - * @see https://docs.parse.ly/metatags/#h-field-description
480 + * @see https://www.parse.ly/help/integration/metatags#field-description
726 481 *
727 482 * @param string $type JSON-LD type.
728 483 * @return string "post" or "index".
729 484 */
@@ -734,9 +489,9 @@
734 489 /**
735 490 * Determines if a Site ID is saved in the options.
736 491 *
737 492 * @since 2.6.0
738 - * @since 3.7.0 renamed from api_key_is_set.
493 + * @since 3.7.0 renamed from api_key_is_set
739 494 *
740 495 * @return bool True is Site ID is set, false if it is missing.
741 496 */
742 497 public function site_id_is_set(): bool {
@@ -748,9 +503,9 @@
748 503 /**
749 504 * Determines if a Site ID is not saved in the options.
750 505 *
751 506 * @since 2.6.0
752 - * @since 3.7.0 renamed from api_key_is_missing.
507 + * @since 3.7.0 renamed from api_key_is_missing
753 508 *
754 509 * @return bool True if Site ID is missing, false if it is set.
755 510 */
756 511 public function site_id_is_missing(): bool {
@@ -760,9 +515,9 @@
760 515 /**
761 516 * Gets the Site ID if set.
762 517 *
763 518 * @since 2.6.0
764 - * @since 3.7.0 renamed from get_site_id.
519 + * @since 3.7.0 renamed from get_site_id
765 520 *
766 521 * @return string Site ID if set, or empty string if not.
767 522 */
768 523 public function get_site_id(): string {
@@ -829,221 +584,6 @@
829 584 * @return Parsely_Options
830 585 */
831 586 public function get_default_options() {
832 587 return $this->option_defaults;
833 - }
834 -
835 - /**
836 - * Returns the credentials that are being managed at the platform level.
837 - *
838 - * @since 3.9.0
839 - * @access private
840 - *
841 - * @return Parsely_Options|array<empty> The managed credentials.
842 - */
843 - private function get_managed_credentials() {
844 - if ( true !== $this->are_credentials_managed ) {
845 - return array();
846 - }
847 -
848 - $credentials = apply_filters( 'wp_parsely_credentials', array() );
849 -
850 - if ( ! is_array( $credentials ) || 0 === count( $credentials ) ) {
851 - return array();
852 - }
853 -
854 - $result = array();
855 -
856 - if ( isset( $credentials['site_id'] ) ) {
857 - $result['apikey'] = $credentials['site_id'];
858 - }
859 -
860 - if ( isset( $credentials['api_secret'] ) ) {
861 - $result['api_secret'] = $credentials['api_secret'];
862 - }
863 -
864 - if ( isset( $credentials['metadata_secret'] ) ) {
865 - $result['metadata_secret'] = $credentials['metadata_secret'];
866 - }
867 -
868 - return $result;
869 - }
870 -
871 - /**
872 - * Returns whether credentials are being managed at the platform level.
873 - *
874 - * @since 3.9.0
875 - * @access private
876 - *
877 - * @return bool Whether credentials are being managed at the platform level.
878 - */
879 - private function are_credentials_managed(): bool {
880 - $credentials = apply_filters( 'wp_parsely_credentials', array() );
881 -
882 - if ( ! is_array( $credentials ) || 0 === count( $credentials ) ) {
883 - return false;
884 - }
885 -
886 - return $credentials['is_managed'] ?? false;
887 - }
888 -
889 - /**
890 - * Sets the values of managed options.
891 - *
892 - * This function won't accept managing credentials or certain plugin options
893 - * that are being managed through other means. For managing credentials,
894 - * please use the `wp_parsely_credentials` filter.
895 - *
896 - * @since 3.9.0
897 - * @access private
898 - */
899 - private function set_managed_options(): void {
900 - $managed_options = apply_filters( 'wp_parsely_managed_options', false );
901 -
902 - if ( ! is_array( $managed_options ) ) {
903 - return;
904 - }
905 -
906 - // Don't allow certain options to be set as managed.
907 - unset(
908 - $managed_options['apikey'],
909 - $managed_options['api_secret'],
910 - $managed_options['metadata_secret'],
911 - $managed_options['track_post_types'],
912 - $managed_options['track_page_types'],
913 - $managed_options['plugin_version']
914 - );
915 -
916 - if ( 0 === count( $managed_options ) ) {
917 - return;
918 - }
919 -
920 - /**
921 - * Current options.
922 - *
923 - * @var Parsely_Options $current_options
924 - */
925 - $current_options = get_option( self::OPTIONS_KEY, array() );
926 -
927 - // Set managed options values.
928 - foreach ( $managed_options as $key => $value ) {
929 - $is_option_valid = isset( $this->option_defaults[ $key ] );
930 -
931 - if ( $is_option_valid ) {
932 - if ( null === $value ) {
933 - // When null, the option gets its value from the database.
934 - $this->managed_options[ $key ] =
935 - $current_options[ $key ] ?? $this->option_defaults[ $key ];
936 - } else {
937 - $this->managed_options[ $key ] =
938 - $this->sanitize_managed_option( $key, $value );
939 - }
940 - }
941 - }
942 - }
943 -
944 - /**
945 - * Sanitizes the value of the passed managed option.
946 - *
947 - * @since 3.9.0
948 - * @access private
949 - *
950 - * @param string $option_id The option's ID.
951 - * @param bool|string $value The option's value.
952 - * @return bool|string The sanitized option value.
953 - */
954 - private function sanitize_managed_option( string $option_id, $value ) {
955 - $option_value_type = gettype( $this->option_defaults[ $option_id ] );
956 -
957 - if ( 'boolean' === $option_value_type && ! is_bool( $value ) ) {
958 - _doing_it_wrong(
959 - __FUNCTION__,
960 - esc_html(
961 - sprintf( /* translators: 1: Option ID */
962 - __( 'The value of the managed option `%1$s` must be of type `boolean`.', 'wp-parsely' ),
963 - $option_id
964 - )
965 - ),
966 - ''
967 - );
968 -
969 - return false;
970 - }
971 -
972 - if ( 'string' === $option_value_type ) {
973 - if ( ! is_string( $value ) ) {
974 - _doing_it_wrong(
975 - __FUNCTION__,
976 - esc_html(
977 - sprintf( /* translators: 1: Option ID */
978 - __( 'The value of the managed option `%1$s` must be of type `string`.', 'wp-parsely' ),
979 - $option_id
980 - )
981 - ),
982 - ''
983 - );
984 -
985 - $value = strval( $value );
986 - }
987 -
988 - // String options that are restricted to specific values.
989 - $restricted_value_options = array(
990 - 'custom_taxonomy_section' => Settings_Page::get_section_taxonomies(),
991 - 'meta_type' => array( 'json_ld', 'repeated_metas' ),
992 - );
993 -
994 - // Verify that the above values are respected.
995 - foreach ( $restricted_value_options as $option_key => $valid_values ) {
996 - if ( $option_id === $option_key ) {
997 - if ( ! in_array( $value, $valid_values, true ) ) {
998 - _doing_it_wrong(
999 - __FUNCTION__,
1000 - esc_html(
1001 - sprintf( /* translators: 1: Option value 2: Option ID */
1002 - __( 'The value `%1$s` is not allowed for the managed option `%2$s`.', 'wp-parsely' ),
1003 - $value,
1004 - $option_id
1005 - )
1006 - ),
1007 - ''
1008 - );
1009 -
1010 - $value = $this->option_defaults[ $option_id ];
1011 - }
1012 - }
1013 - }
1014 - }
1015 -
1016 - return $value;
1017 - }
1018 -
1019 - /**
1020 - * Allows remote requests to Parse.ly.
1021 - *
1022 - * This is needed for environments, such as wp-now, that block remote requests.
1023 - *
1024 - * @since 3.13.0
1025 - * @access private
1026 - */
1027 - private function allow_parsely_remote_requests(): void {
1028 - $allowed_urls = array(
1029 - self::DASHBOARD_BASE_URL,
1030 - Content_API_Service::get_base_url(),
1031 - Suggestions_API_Service::get_base_url(),
1032 - );
1033 -
1034 - add_filter(
1035 - 'http_request_host_is_external',
1036 - function ( $external, $host, $url ) use ( $allowed_urls ) {
1037 - // Check if the URL matches any URLs on the allowed list.
1038 - foreach ( $allowed_urls as $allowed_url ) {
1039 - if ( Utils::str_starts_with( $url, $allowed_url ) ) {
1040 - return true;
1041 - }
1042 - }
1043 - return $external;
1044 - },
1045 - 10,
1046 - 3
1047 - );
1048 588 }
1049 589 }