| @@ -90,9 +90,9 @@ | ||
| 90 | 90 | * |
| 91 | 91 | * @since 3.16.0 |
| 92 | 92 | * @var string The URL of the suggested link. |
| 93 | 93 | */ |
| 94 | - protected $href; | |
| 94 | + protected $href = ''; | |
| 95 | 95 | |
| 96 | 96 | /** |
| 97 | 97 | * The title of the suggested link. |
| 98 | 98 | * |
| @@ -195,10 +195,11 @@ | ||
| 195 | 195 | */ |
| 196 | 196 | private function get_smart_link_object_by_uid( string $uid ): int { |
| 197 | 197 | $cache_key = self::get_uid_to_smart_link_cache_key( $uid ); |
| 198 | 198 | $cached = wp_cache_get( $cache_key, PARSELY_CACHE_GROUP ); |
| 199 | - if ( is_int( $cached ) && 0 !== $cached ) { | |
| 200 | - return $cached; | |
| 199 | + | |
| 200 | + if ( false !== $cached && is_numeric( $cached ) ) { | |
| 201 | + return (int) $cached; | |
| 201 | 202 | } |
| 202 | 203 | |
| 203 | 204 | $smart_links = new \WP_Query( |
| 204 | 205 | array( |
| @@ -728,21 +729,48 @@ | ||
| 728 | 729 | $this->uid = $uid; |
| 729 | 730 | } |
| 730 | 731 | |
| 731 | 732 | /** |
| 733 | + * Determines whether an href is valid for a Smart Link. | |
| 734 | + * | |
| 735 | + * Only web URLs are accepted. Scheme-less references such as `/path/` or | |
| 736 | + * `#anchor` also pass, unless they contain a colon, which WordPress reads | |
| 737 | + * as a scheme delimiter. `esc_url_raw()` is used instead of a scheme | |
| 738 | + * comparison, as it also catches case and whitespace variations. | |
| 739 | + * | |
| 740 | + * @since 3.24.2 | |
| 741 | + * | |
| 742 | + * @param string $href The href to check. | |
| 743 | + * @return bool Whether the href is valid. | |
| 744 | + */ | |
| 745 | + public static function is_valid_href( string $href ): bool { | |
| 746 | + return '' !== esc_url_raw( $href, array( 'http', 'https' ) ); | |
| 747 | + } | |
| 748 | + | |
| 749 | + /** | |
| 732 | 750 | * Sets the href of the smart link. |
| 733 | 751 | * |
| 752 | + * Invalid hrefs are ignored. Callers accepting user input should validate | |
| 753 | + * with `is_valid_href()` first, to report the rejection. | |
| 754 | + * | |
| 755 | + * No canonical URL is stored, as this runs during REST argument | |
| 756 | + * validation, which must not have side effects. | |
| 757 | + * | |
| 734 | 758 | * @since 3.16.0 |
| 759 | + * @since 3.24.2 Invalid hrefs are ignored, and no canonical URL is stored. | |
| 735 | 760 | * |
| 736 | 761 | * @param string $href The href of the smart link. |
| 737 | 762 | */ |
| 738 | 763 | public function set_href( string $href ): void { |
| 764 | + if ( ! self::is_valid_href( $href ) ) { | |
| 765 | + return; | |
| 766 | + } | |
| 767 | + | |
| 739 | 768 | $this->href = $href; |
| 740 | 769 | $destination_post_id = Utils::get_post_id_by_url( $href ); |
| 741 | 770 | |
| 742 | 771 | if ( 0 !== $destination_post_id ) { |
| 743 | - // Set the destination post ID, and update the canonical URL. | |
| 744 | - $this->set_destination_post_id( $destination_post_id, $href ); | |
| 772 | + $this->set_destination_post_id( $destination_post_id ); | |
| 745 | 773 | } |
| 746 | 774 | } |
| 747 | 775 | |
| 748 | 776 | /** |
| @@ -948,9 +976,9 @@ | ||
| 948 | 976 | } |
| 949 | 977 | // Build the query arguments. |
| 950 | 978 | $query_args = array( |
| 951 | 979 | 'post_type' => 'parsely_smart_link', |
| 952 | - 'posts_per_page' => -1, | |
| 980 | + 'posts_per_page' => -1, // phpcs:ignore WordPressVIPMinimum.Performance.NoPaging.posts_per_page_posts_per_page | |
| 953 | 981 | 'fields' => 'ids', // Only get the post IDs to improve performance. |
| 954 | 982 | // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query |
| 955 | 983 | 'tax_query' => array_merge( array( 'relation' => 'AND' ), $tax_query ), |
| 956 | 984 | ); |
| @@ -1096,10 +1124,9 @@ | ||
| 1096 | 1124 | $cache_key = self::get_smart_link_counts_cache_key( $status ); |
| 1097 | 1125 | $cache_group = self::get_smart_links_post_cache_group( $post_id ); |
| 1098 | 1126 | $link_counts = wp_cache_get( $cache_key, $cache_group ); |
| 1099 | 1127 | |
| 1100 | - if ( false !== $link_counts ) { | |
| 1101 | - /** @var array<string,int> */ | |
| 1128 | + if ( false !== $link_counts && is_array( $link_counts ) ) { | |
| 1102 | 1129 | return $link_counts; |
| 1103 | 1130 | } |
| 1104 | 1131 | |
| 1105 | 1132 | $base_query_args = array( |