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 | src/class-parsely.php +91 -28 3.19.0 → 3.24.2 View file →
@@ -9,14 +9,14 @@
9 9 declare(strict_types=1);
10 10
11 11 namespace Parsely;
12 12
13 +use Parsely\Content_Helper\Suggestion_Defaults;
13 14 use Parsely\REST_API\REST_API_Controller;
14 15 use Parsely\Services\Content_API\Content_API_Service;
15 16 use Parsely\Services\Suggestions_API\Suggestions_API_Service;
16 17 use Parsely\UI\Metadata_Renderer;
17 18 use Parsely\UI\Settings_Page;
18 -use Parsely\Utils\Utils;
19 19 use WP_Post;
20 20
21 21 /**
22 22 * Holds most of the logic for the plugin.
@@ -31,8 +31,9 @@
31 31 * use_top_level_cats: bool,
32 32 * custom_taxonomy_section: string,
33 33 * cats_as_tags: bool,
34 34 * content_helper: Parsely_Options_Content_Helper,
35 + * headline_testing: Parsely_Options_Headline_Testing,
35 36 * track_authenticated_users: bool,
36 37 * lowercase_tags: bool,
37 38 * force_https_canonicals: bool,
38 39 * track_post_types: string[],
@@ -58,10 +59,22 @@
58 59 *
59 60 * @phpstan-type Parsely_Options_Content_Helper_Feature array{
60 61 * enabled: bool,
61 62 * allowed_user_roles: string[],
63 + * default_length?: int,
64 + * default_tone?: string,
65 + * default_persona?: string,
62 66 * }
63 67 *
68 + * @phpstan-type Parsely_Options_Headline_Testing array{
69 + * enabled: bool,
70 + * installation_method: string,
71 + * enable_flicker_control: bool,
72 + * enable_live_updates: bool,
73 + * live_update_timeout: int,
74 + * allow_after_content_load: bool,
75 + * }
76 + *
64 77 * @phpstan-type WP_HTTP_Request_Args array{
65 78 * method?: string,
66 79 * timeout?: float,
67 80 * blocking?: bool,
@@ -125,12 +138,17 @@
125 138 ),
126 139 'title_suggestions' => array(
127 140 'enabled' => true,
128 141 'allowed_user_roles' => array( 'administrator' ),
142 + 'default_tone' => Suggestion_Defaults::DEFAULT_TONE,
143 + 'default_persona' => Suggestion_Defaults::DEFAULT_PERSONA,
129 144 ),
130 145 'excerpt_suggestions' => array(
131 146 'enabled' => true,
132 147 'allowed_user_roles' => array( 'administrator' ),
148 + 'default_length' => Suggestion_Defaults::DEFAULT_LENGTH,
149 + 'default_tone' => Suggestion_Defaults::DEFAULT_TONE,
150 + 'default_persona' => Suggestion_Defaults::DEFAULT_PERSONA,
133 151 ),
134 152 'traffic_boost' => array(
135 153 'enabled' => true,
136 154 'allowed_user_roles' => array( 'administrator' ),
@@ -135,8 +153,16 @@
135 153 'enabled' => true,
136 154 'allowed_user_roles' => array( 'administrator' ),
137 155 ),
138 156 ),
157 + 'headline_testing' => array(
158 + 'enabled' => false,
159 + 'installation_method' => 'one_line',
160 + 'enable_flicker_control' => false,
161 + 'enable_live_updates' => false,
162 + 'live_update_timeout' => 30000,
163 + 'allow_after_content_load' => false,
164 + ),
139 165 'track_authenticated_users' => false,
140 166 'lowercase_tags' => true,
141 167 'force_https_canonicals' => false,
142 168 'track_post_types' => array(),
@@ -354,10 +380,21 @@
354 380 */
355 381 public function get_tracker_url(): string {
356 382 if ( $this->site_id_is_set() ) {
357 383 $tracker_url = 'https://cdn.parsely.com/keys/' . $this->get_site_id() . '/p.js';
358 - return esc_url( $tracker_url );
384 +
385 + /**
386 + * Filters the URL of the Parse.ly tracker script.
387 + *
388 + * The filtered value gets sanitized with {@see esc_url_raw()}.
389 + *
390 + * @since 3.23.0
391 + *
392 + * @param string $tracker_url The URL of the tracker script.
393 + */
394 + return esc_url_raw( apply_filters( 'wp_parsely_tracker_url', $tracker_url ) );
359 395 }
396 +
360 397 return '';
361 398 }
362 399
363 400 /**
@@ -560,15 +597,16 @@
560 597 if ( is_array( $options ) && ! isset( $options['full_metadata_in_non_posts'] ) ) {
561 598 $this->set_default_full_metadata_in_non_posts();
562 599 }
563 600
564 - // Existing plugin installation without Content Helper options.
601 + // Existing plugin installation without Content Intelligence options.
565 602 /* @phpstan-ignore isset.offset, booleanAnd.alwaysFalse */
566 603 if ( is_array( $options ) && ! isset( $options['content_helper'] ) ) {
567 604 $this->set_default_content_helper_settings_values();
568 605 }
569 606
570 - // Existing plugin installation that's missing a Content Helper feature option.
607 + // Existing plugin installation that's missing a Content Intelligence
608 + // feature option.
571 609 /* @phpstan-ignore isset.offset */
572 610 if ( is_array( $options ) && isset( $options['content_helper'] ) ) {
573 611 /** @var array<string,Parsely_Options_Content_Helper_Feature> $pch_options */
574 612 $pch_options = $options['content_helper'];
@@ -684,9 +722,9 @@
684 722 }
685 723 }
686 724
687 725 /**
688 - * Sets the default values for Content Helper options.
726 + * Sets the default values for Content Intelligence options.
689 727 *
690 728 * Gives PCH access to all users having the edit_posts capability, to keep
691 729 * consistent behavior with plugin versions prior to 3.16.0.
692 730 *
@@ -1006,15 +1044,15 @@
1006 1044 $post_id = is_int( $post ) ? $post : $post->ID;
1007 1045 $canonical_url = get_post_meta( $post_id, self::PARSELY_CANONICAL_URL_META_KEY, true );
1008 1046
1009 1047 if ( null !== $canonical_url && is_string( $canonical_url ) && '' !== $canonical_url ) {
1010 - return $canonical_url;
1048 + return self::get_canonical_url( $canonical_url );
1011 1049 }
1012 1050
1013 1051 $permalink = get_permalink( $post );
1014 1052
1015 1053 if ( false === $permalink ) {
1016 - return 'no permalink';
1054 + return __( 'no permalink', 'wp-parsely' );
1017 1055 }
1018 1056
1019 1057 return self::get_canonical_url( $permalink );
1020 1058 }
@@ -1019,37 +1057,49 @@
1019 1057 return self::get_canonical_url( $permalink );
1020 1058 }
1021 1059
1022 1060 /**
1023 - * Gets the canonical URL for a given URL.
1061 + * Returns the canonical version of the passed URL.
1024 1062 *
1025 - * If the current domain is different from the Parse.ly site ID, this function
1026 - * will return the URL with the current domain.
1063 + * In this context, the canonical URL is the URL containing the Site ID as
1064 + * its domain. If the Site ID differs from the real domain, the
1065 + * `wp_parsely_canonical_url_domain` filter can be used to set it.
1027 1066 *
1028 1067 * @since 3.19.0
1068 + * @since 3.20.4 Made the domain overridable.
1029 1069 *
1030 1070 * @param string $url The URL to get the canonical URL for.
1031 1071 * @return string The canonical URL.
1032 1072 */
1033 1073 public static function get_canonical_url( string $url ): string {
1034 - $parsely = \Parsely\get_parsely();
1035 - $site_id = $parsely->get_site_id();
1074 + $canonical_url_domain = apply_filters(
1075 + 'wp_parsely_canonical_url_domain',
1076 + null
1077 + );
1036 1078
1037 - if ( wp_parse_url( $url, PHP_URL_HOST ) === $site_id ) {
1038 - return $url;
1079 + // Handle domain override.
1080 + if ( is_string( $canonical_url_domain ) ) {
1081 + // Get the canonical URL domain without protocol, trailing slashes
1082 + // or accidental whitespace.
1083 + $canonical_url_domain = rtrim( trim( $canonical_url_domain ), '/' );
1084 + $canonical_url_domain = preg_replace( '#^https?://#', '', $canonical_url_domain );
1085 +
1086 + if ( is_string( $canonical_url_domain ) && '' !== $canonical_url_domain ) {
1087 + $url_domain = (string) wp_parse_url( $url, PHP_URL_HOST );
1088 + return str_replace( $url_domain, $canonical_url_domain, $url );
1089 + }
1039 1090 }
1040 1091
1041 - $home_url = home_url();
1092 + $site_id = \Parsely\get_parsely()->get_site_id();
1093 + $home_url_host = (string) wp_parse_url( home_url(), PHP_URL_HOST );
1042 1094
1043 - // Strip the protocol from the home URL.
1044 - $home_url = preg_replace( '/^https?:\/\//', '', $home_url );
1045 -
1046 - if ( null === $home_url ) {
1095 + if ( $home_url_host === $site_id ) {
1096 + // URL does not need to be modified.
1047 1097 return $url;
1048 1098 }
1049 1099
1050 - // Replace the current domain with the Parse.ly site ID.
1051 - return str_replace( $home_url, $site_id, $url );
1100 + // Return the URL with the Site ID as the domain.
1101 + return str_replace( $home_url_host, $site_id, $url );
1052 1102 }
1053 1103
1054 1104 /**
1055 1105 * Sets the Parse.ly canonical URL for a post.
@@ -1060,10 +1110,16 @@
1060 1110 * @param string $url The canonical URL.
1061 1111 * @return bool True if the canonical URL was set, false otherwise.
1062 1112 */
1063 1113 public static function set_canonical_url( $post, string $url ): bool {
1064 - $post_id = is_int( $post ) ? $post : $post->ID;
1065 - return false !== update_post_meta( $post_id, self::PARSELY_CANONICAL_URL_META_KEY, $url );
1114 + $post_id = is_int( $post ) ? $post : $post->ID;
1115 + $canonical_url = self::get_canonical_url( $url );
1116 +
1117 + return false !== update_post_meta(
1118 + $post_id,
1119 + self::PARSELY_CANONICAL_URL_META_KEY,
1120 + sanitize_url( $canonical_url, array( 'http', 'https' ) )
1121 + );
1066 1122 }
1067 1123
1068 1124 /**
1069 1125 * Sanitizes the value of the passed managed option.
@@ -1145,8 +1201,9 @@
1145 1201 *
1146 1202 * This is needed for environments, such as wp-now, that block remote requests.
1147 1203 *
1148 1204 * @since 3.13.0
1205 + * @since 3.24.2 Matches the Parse.ly hosts exactly, over HTTPS.
1149 1206 * @access private
1150 1207 */
1151 1208 private function allow_parsely_remote_requests(): void {
1152 1209 $allowed_urls = array(
@@ -1157,14 +1214,20 @@
1157 1214
1158 1215 add_filter(
1159 1216 'http_request_host_is_external',
1160 1217 function ( bool $external, string $host, string $url ) use ( $allowed_urls ) {
1161 - // Check if the URL matches any URLs on the allowed list.
1162 - foreach ( $allowed_urls as $allowed_url ) {
1163 - if ( Utils::str_starts_with( $url, $allowed_url ) ) {
1164 - return true;
1165 - }
1218 + $scheme = strtolower( (string) wp_parse_url( $url, PHP_URL_SCHEME ) );
1219 + $allowed_hosts = array_map(
1220 + static function ( string $allowed_url ): string {
1221 + return (string) wp_parse_url( $allowed_url, PHP_URL_HOST );
1222 + },
1223 + $allowed_urls
1224 + );
1225 +
1226 + if ( 'https' === $scheme && in_array( strtolower( $host ), $allowed_hosts, true ) ) {
1227 + return true;
1166 1228 }
1229 +
1167 1230 return $external;
1168 1231 },
1169 1232 10,
1170 1233 3