← All changes
|
src/rest-api/content-helper/class-endpoint-smart-linking.php
+192
-118
3.17.0
→
3.24.2
View file →
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | 3 | * Endpoint: Smart Linking |
| 4 | - * Parse.ly Content Helper `/smart-linking` API endpoint class | |
| 4 | + * Parse.ly Content Intelligence `/smart-linking` API endpoint class | |
| 5 | 5 | * |
| 6 | 6 | * @package Parsely |
| 7 | 7 | * @since 3.17.0 |
| 8 | 8 | */ |
| @@ -11,11 +11,13 @@ | ||
| 11 | 11 | |
| 12 | 12 | namespace Parsely\REST_API\Content_Helper; |
| 13 | 13 | |
| 14 | 14 | use Parsely\Models\Smart_Link; |
| 15 | +use Parsely\Models\Smart_Link_Status; | |
| 15 | 16 | use Parsely\REST_API\Base_Endpoint; |
| 16 | 17 | use Parsely\REST_API\Use_Post_ID_Parameter_Trait; |
| 17 | 18 | use Parsely\Services\Suggestions_API\Suggestions_API_Service; |
| 19 | +use Parsely\Utils\Utils; | |
| 18 | 20 | use WP_Error; |
| 19 | 21 | use WP_Post; |
| 20 | 22 | use WP_REST_Request; |
| 21 | 23 | use WP_REST_Response; |
| @@ -44,9 +46,9 @@ | ||
| 44 | 46 | * Initializes the class. |
| 45 | 47 | * |
| 46 | 48 | * @since 3.17.0 |
| 47 | 49 | * |
| 48 | - * @param Content_Helper_Controller $controller The content helper controller. | |
| 50 | + * @param Content_Helper_Controller $controller The Content Intelligence controller. | |
| 49 | 51 | */ |
| 50 | 52 | public function __construct( Content_Helper_Controller $controller ) { |
| 51 | 53 | parent::__construct( $controller ); |
| 52 | 54 | $this->suggestions_api = $controller->get_parsely()->get_suggestions_api(); |
| @@ -56,9 +58,9 @@ | ||
| 56 | 58 | * Returns the name of the endpoint. |
| 57 | 59 | * |
| 58 | 60 | * @since 3.17.0 |
| 59 | 61 | * |
| 60 | - * @return string The endpoint name. | |
| 62 | + * @return string The endpoint's name. | |
| 61 | 63 | */ |
| 62 | 64 | public static function get_endpoint_name(): string { |
| 63 | 65 | return 'smart-linking'; |
| 64 | 66 | } |
| @@ -67,9 +69,9 @@ | ||
| 67 | 69 | * Returns the name of the feature associated with the current endpoint. |
| 68 | 70 | * |
| 69 | 71 | * @since 3.17.0 |
| 70 | 72 | * |
| 71 | - * @return string The feature name. | |
| 73 | + * @return string The feature's name. | |
| 72 | 74 | */ |
| 73 | 75 | public function get_pch_feature_name(): string { |
| 74 | 76 | return 'smart_linking'; |
| 75 | 77 | } |
| @@ -91,19 +93,20 @@ | ||
| 91 | 93 | array( |
| 92 | 94 | 'text' => array( |
| 93 | 95 | 'required' => true, |
| 94 | 96 | 'type' => 'string', |
| 95 | - 'description' => __( 'The text to generate smart links for.', 'wp-parsely' ), | |
| 97 | + 'description' => __( 'The text to generate Smart Links for.', 'wp-parsely' ), | |
| 96 | 98 | ), |
| 97 | 99 | 'max_links' => array( |
| 98 | 100 | 'type' => 'integer', |
| 99 | - 'description' => __( 'The maximum number of smart links to generate.', 'wp-parsely' ), | |
| 101 | + 'description' => __( 'The maximum number of Smart Links to generate.', 'wp-parsely' ), | |
| 100 | 102 | 'default' => 10, |
| 101 | 103 | ), |
| 102 | 104 | 'url_exclusion_list' => array( |
| 103 | 105 | 'type' => 'array', |
| 104 | - 'description' => __( 'The list of URLs to exclude from the smart links.', 'wp-parsely' ), | |
| 105 | - 'validate_callback' => array( $this, 'validate_url_exclusion_list' ), | |
| 106 | + 'description' => __( 'The list of URLs to exclude from the Smart Links.', 'wp-parsely' ), | |
| 107 | + 'validate_callback' => array( Validations\Validate_Url_Exclusion_List::class, 'validate' ), | |
| 108 | + 'sanitize_callback' => array( Validations\Validate_Url_Exclusion_List::class, 'sanitize' ), | |
| 106 | 109 | 'default' => array(), |
| 107 | 110 | ), |
| 108 | 111 | ) |
| 109 | 112 | ); |
| @@ -129,14 +132,14 @@ | ||
| 129 | 132 | array( |
| 130 | 133 | 'link' => array( |
| 131 | 134 | 'required' => true, |
| 132 | 135 | 'type' => 'object', |
| 133 | - 'description' => __( 'The smart link data to add.', 'wp-parsely' ), | |
| 136 | + 'description' => __( 'The Smart Link data to add.', 'wp-parsely' ), | |
| 134 | 137 | 'validate_callback' => array( $this, 'validate_smart_link_params' ), |
| 135 | 138 | ), |
| 136 | 139 | 'update' => array( |
| 137 | 140 | 'type' => 'boolean', |
| 138 | - 'description' => __( 'Whether to update the existing smart link.', 'wp-parsely' ), | |
| 141 | + 'description' => __( 'Whether to update the existing Smart Link.', 'wp-parsely' ), | |
| 139 | 142 | 'default' => false, |
| 140 | 143 | ), |
| 141 | 144 | ) |
| 142 | 145 | ); |
| @@ -152,14 +155,14 @@ | ||
| 152 | 155 | array( |
| 153 | 156 | 'links' => array( |
| 154 | 157 | 'required' => true, |
| 155 | 158 | 'type' => 'array', |
| 156 | - 'description' => __( 'The multiple smart links data to add.', 'wp-parsely' ), | |
| 159 | + 'description' => __( 'The multiple Smart Links data to add.', 'wp-parsely' ), | |
| 157 | 160 | 'validate_callback' => array( $this, 'validate_multiple_smart_links' ), |
| 158 | 161 | ), |
| 159 | 162 | 'update' => array( |
| 160 | 163 | 'type' => 'boolean', |
| 161 | - 'description' => __( 'Whether to update the existing smart links.', 'wp-parsely' ), | |
| 164 | + 'description' => __( 'Whether to update the existing Smart Links.', 'wp-parsely' ), | |
| 162 | 165 | 'default' => false, |
| 163 | 166 | ), |
| 164 | 167 | ) |
| 165 | 168 | ); |
| @@ -175,9 +178,9 @@ | ||
| 175 | 178 | array( |
| 176 | 179 | 'links' => array( |
| 177 | 180 | 'required' => true, |
| 178 | 181 | 'type' => 'array', |
| 179 | - 'description' => __( 'The smart links data to set.', 'wp-parsely' ), | |
| 182 | + 'description' => __( 'The Smart Links data to set.', 'wp-parsely' ), | |
| 180 | 183 | 'validate_callback' => array( $this, 'validate_multiple_smart_links' ), |
| 181 | 184 | ), |
| 182 | 185 | ) |
| 183 | 186 | ); |
| @@ -182,15 +185,24 @@ | ||
| 182 | 185 | ) |
| 183 | 186 | ); |
| 184 | 187 | |
| 185 | 188 | /** |
| 186 | - * POST /smart-linking/url-to-post-type | |
| 187 | - * Converts a URL to a post type. | |
| 189 | + * POST /smart-linking/get-post-meta-for-urls | |
| 190 | + * Gets the post meta information for the passed URLs. | |
| 188 | 191 | */ |
| 189 | 192 | $this->register_rest_route( |
| 190 | - 'url-to-post-type', | |
| 193 | + 'get-post-meta-for-urls', | |
| 191 | 194 | array( 'POST' ), |
| 192 | - array( $this, 'url_to_post_type' ) | |
| 195 | + array( $this, 'get_post_meta_for_urls' ), | |
| 196 | + array( | |
| 197 | + 'urls' => array( | |
| 198 | + 'required' => true, | |
| 199 | + 'type' => 'array', | |
| 200 | + 'items' => array( 'type' => 'string' ), | |
| 201 | + 'maxItems' => 500, | |
| 202 | + 'description' => __( 'The URLs to get meta information for.', 'wp-parsely' ), | |
| 203 | + ), | |
| 204 | + ) | |
| 193 | 205 | ); |
| 194 | 206 | } |
| 195 | 207 | |
| 196 | 208 | /** |
| @@ -227,11 +239,11 @@ | ||
| 227 | 239 | |
| 228 | 240 | $response = $this->suggestions_api->get_smart_links( |
| 229 | 241 | $post_content, |
| 230 | 242 | array( |
| 231 | - 'max_items' => $max_links, | |
| 232 | - ), | |
| 233 | - $url_exclusion_list | |
| 243 | + 'max_items' => $max_links, | |
| 244 | + 'url_exclusion_list' => $url_exclusion_list, | |
| 245 | + ) | |
| 234 | 246 | ); |
| 235 | 247 | |
| 236 | 248 | if ( is_wp_error( $response ) ) { |
| 237 | 249 | return $response; |
| @@ -238,8 +250,11 @@ | ||
| 238 | 250 | } |
| 239 | 251 | |
| 240 | 252 | $smart_links = array_map( |
| 241 | 253 | function ( Smart_Link $link ) { |
| 254 | + // Set the context to Smart Linking. | |
| 255 | + $link->set_context( $this->get_pch_feature_name() ); | |
| 256 | + | |
| 242 | 257 | return $link->to_array(); |
| 243 | 258 | }, |
| 244 | 259 | $response |
| 245 | 260 | ); |
| @@ -252,32 +267,35 @@ | ||
| 252 | 267 | * |
| 253 | 268 | * Gets the smart links for a post. |
| 254 | 269 | * |
| 255 | 270 | * @since 3.16.0 |
| 271 | + * @since 3.24.2 Inbound links of non-visible source posts are omitted. | |
| 256 | 272 | * |
| 257 | 273 | * @param WP_REST_Request $request The request object. |
| 258 | - * @return WP_REST_Response The response object. | |
| 274 | + * @return WP_REST_Response|WP_Error The response object. | |
| 259 | 275 | */ |
| 260 | - public function get_smart_links( WP_REST_Request $request ): WP_REST_Response { | |
| 261 | - /** | |
| 262 | - * The post object. | |
| 263 | - * | |
| 264 | - * @var WP_Post $post | |
| 265 | - */ | |
| 266 | - $post = $request->get_param( 'post' ); | |
| 276 | + public function get_smart_links( WP_REST_Request $request ) { | |
| 277 | + $post = $this->get_request_post( $request ); | |
| 267 | 278 | |
| 268 | - $outbound_links = Smart_Link::get_outbound_smart_links( $post->ID ); | |
| 269 | - $inbound_links = Smart_Link::get_inbound_smart_links( $post->ID ); | |
| 279 | + if ( ! $post instanceof WP_Post ) { | |
| 280 | + return new WP_Error( | |
| 281 | + 'invalid_post', | |
| 282 | + __( 'Invalid post.', 'wp-parsely' ), | |
| 283 | + array( 'status' => 404 ) | |
| 284 | + ); | |
| 285 | + } | |
| 270 | 286 | |
| 287 | + $outbound_links = Smart_Link::get_outbound_smart_links( $post->ID, Smart_Link_Status::APPLIED ); | |
| 288 | + $inbound_links = Smart_Link::get_inbound_smart_links( $post->ID, Smart_Link_Status::APPLIED ); | |
| 289 | + | |
| 271 | 290 | $response = array( |
| 272 | 291 | 'outbound' => $this->serialize_smart_links( $outbound_links ), |
| 273 | - 'inbound' => $this->serialize_smart_links( $inbound_links ), | |
| 292 | + 'inbound' => $this->serialize_visible_inbound_links( $inbound_links ), | |
| 274 | 293 | ); |
| 275 | 294 | |
| 276 | 295 | return new WP_REST_Response( array( 'data' => $response ), 200 ); |
| 277 | 296 | } |
| 278 | 297 | |
| 279 | - | |
| 280 | 298 | /** |
| 281 | 299 | * API Endpoint: POST /smart-linking/{post_id}/add. |
| 282 | 300 | * |
| 283 | 301 | * Adds a smart link to a post. |
| @@ -301,9 +319,9 @@ | ||
| 301 | 319 | return new WP_REST_Response( |
| 302 | 320 | array( |
| 303 | 321 | 'error' => array( |
| 304 | 322 | 'name' => 'smart_link_exists', |
| 305 | - 'message' => __( 'Smart link already exists.', 'wp-parsely' ), | |
| 323 | + 'message' => __( 'Smart Link already exists.', 'wp-parsely' ), | |
| 306 | 324 | ), |
| 307 | 325 | ), |
| 308 | 326 | 409 // HTTP Conflict. |
| 309 | 327 | ); |
| @@ -308,8 +326,16 @@ | ||
| 308 | 326 | 409 // HTTP Conflict. |
| 309 | 327 | ); |
| 310 | 328 | } |
| 311 | 329 | |
| 330 | + // Mark as applied. | |
| 331 | + $smart_link->set_status( Smart_Link_Status::APPLIED ); | |
| 332 | + | |
| 333 | + // If the context is not set, set it to Smart Linking. | |
| 334 | + if ( null === $smart_link->get_context() ) { | |
| 335 | + $smart_link->set_context( $this->get_pch_feature_name() ); | |
| 336 | + } | |
| 337 | + | |
| 312 | 338 | // The smart link properties are set in the validate callback. |
| 313 | 339 | $saved = $smart_link->save(); |
| 314 | 340 | if ( ! $saved ) { |
| 315 | 341 | return new WP_REST_Response( |
| @@ -315,9 +341,9 @@ | ||
| 315 | 341 | return new WP_REST_Response( |
| 316 | 342 | array( |
| 317 | 343 | 'error' => array( |
| 318 | 344 | 'name' => 'add_smart_link_failed', |
| 319 | - 'message' => __( 'Failed to add the smart link.', 'wp-parsely' ), | |
| 345 | + 'message' => __( 'Failed to add the Smart Link.', 'wp-parsely' ), | |
| 320 | 346 | ), |
| 321 | 347 | ), |
| 322 | 348 | 500 |
| 323 | 349 | ); |
| @@ -322,8 +348,11 @@ | ||
| 322 | 348 | 500 |
| 323 | 349 | ); |
| 324 | 350 | } |
| 325 | 351 | |
| 352 | + // Clear the cache for the smart link. | |
| 353 | + $smart_link->flush_all_cache(); | |
| 354 | + | |
| 326 | 355 | return new WP_REST_Response( |
| 327 | 356 | array( |
| 328 | 357 | 'data' => json_decode( $smart_link->serialize() ), |
| 329 | 358 | ), |
| @@ -361,8 +390,11 @@ | ||
| 361 | 390 | } |
| 362 | 391 | |
| 363 | 392 | $updated_link = $smart_link->exists() && $should_update; |
| 364 | 393 | |
| 394 | + // Mark as applied. | |
| 395 | + $smart_link->set_status( Smart_Link_Status::APPLIED ); | |
| 396 | + | |
| 365 | 397 | // The smart link properties are set in the validate callback. |
| 366 | 398 | $saved = $smart_link->save(); |
| 367 | 399 | |
| 368 | 400 | if ( ! $saved ) { |
| @@ -374,8 +406,11 @@ | ||
| 374 | 406 | $updated_links[] = $smart_link; |
| 375 | 407 | } else { |
| 376 | 408 | $added_links[] = $smart_link; |
| 377 | 409 | } |
| 410 | + | |
| 411 | + // Clear the cache for the smart link. | |
| 412 | + $smart_link->flush_all_cache(); | |
| 378 | 413 | } |
| 379 | 414 | |
| 380 | 415 | // If no link was added, return an error response. |
| 381 | 416 | if ( count( $added_links ) === 0 && count( $updated_links ) === 0 ) { |
| @@ -382,9 +417,9 @@ | ||
| 382 | 417 | return new WP_REST_Response( |
| 383 | 418 | array( |
| 384 | 419 | 'error' => array( |
| 385 | 420 | 'name' => 'add_smart_link_failed', |
| 386 | - 'message' => __( 'Failed to add all the smart links.', 'wp-parsely' ), | |
| 421 | + 'message' => __( 'Failed to add all the Smart Links.', 'wp-parsely' ), | |
| 387 | 422 | ), |
| 388 | 423 | ), |
| 389 | 424 | 500 |
| 390 | 425 | ); |
| @@ -411,18 +446,21 @@ | ||
| 411 | 446 | * |
| 412 | 447 | * @since 3.16.0 |
| 413 | 448 | * |
| 414 | 449 | * @param WP_REST_Request $request The request object. |
| 415 | - * @return WP_REST_Response The response object. | |
| 450 | + * @return WP_REST_Response|WP_Error The response object. | |
| 416 | 451 | */ |
| 417 | - public function set_smart_links( WP_REST_Request $request ): WP_REST_Response { | |
| 418 | - /** | |
| 419 | - * The post object. | |
| 420 | - * | |
| 421 | - * @var WP_Post $post | |
| 422 | - */ | |
| 423 | - $post = $request->get_param( 'post' ); | |
| 452 | + public function set_smart_links( WP_REST_Request $request ) { | |
| 453 | + $post = $this->get_request_post( $request ); | |
| 424 | 454 | |
| 455 | + if ( ! $post instanceof WP_Post ) { | |
| 456 | + return new WP_Error( | |
| 457 | + 'invalid_post', | |
| 458 | + __( 'Invalid post.', 'wp-parsely' ), | |
| 459 | + array( 'status' => 404 ) | |
| 460 | + ); | |
| 461 | + } | |
| 462 | + | |
| 425 | 463 | /** |
| 426 | 464 | * Array of Smart Link models provided in the request. |
| 427 | 465 | * |
| 428 | 466 | * @var Smart_Link[] $smart_links |
| @@ -429,9 +467,9 @@ | ||
| 429 | 467 | */ |
| 430 | 468 | $smart_links = $request->get_param( 'smart_links' ); |
| 431 | 469 | |
| 432 | 470 | // Get the current stored smart links. |
| 433 | - $existing_links = Smart_Link::get_outbound_smart_links( $post->ID ); | |
| 471 | + $existing_links = Smart_Link::get_outbound_smart_links( $post->ID, Smart_Link_Status::APPLIED ); | |
| 434 | 472 | $removed_links = array(); |
| 435 | 473 | |
| 436 | 474 | foreach ( $existing_links as $existing_link ) { |
| 437 | 475 | $found = false; |
| @@ -444,8 +482,11 @@ | ||
| 444 | 482 | |
| 445 | 483 | if ( ! $found ) { |
| 446 | 484 | $removed_links[] = $existing_link; |
| 447 | 485 | $existing_link->delete(); |
| 486 | + | |
| 487 | + // Clear the cache for the smart link. | |
| 488 | + $existing_link->flush_all_cache(); | |
| 448 | 489 | } |
| 449 | 490 | } |
| 450 | 491 | |
| 451 | 492 | $saved_links = array(); |
| @@ -451,8 +492,11 @@ | ||
| 451 | 492 | $saved_links = array(); |
| 452 | 493 | $failed_links = array(); |
| 453 | 494 | |
| 454 | 495 | foreach ( $smart_links as $smart_link ) { |
| 496 | + // Mark as applied. | |
| 497 | + $smart_link->set_status( Smart_Link_Status::APPLIED ); | |
| 498 | + | |
| 455 | 499 | // The smart link properties are set in the validate callback. |
| 456 | 500 | $saved = $smart_link->save(); |
| 457 | 501 | |
| 458 | 502 | if ( ! $saved ) { |
| @@ -460,8 +504,11 @@ | ||
| 460 | 504 | continue; |
| 461 | 505 | } |
| 462 | 506 | |
| 463 | 507 | $saved_links[] = $smart_link; |
| 508 | + | |
| 509 | + // Clear the cache for the smart link. | |
| 510 | + $smart_link->flush_all_cache(); | |
| 464 | 511 | } |
| 465 | 512 | |
| 466 | 513 | $response = array( |
| 467 | 514 | 'saved' => $this->serialize_smart_links( $saved_links ), |
| @@ -474,104 +521,67 @@ | ||
| 474 | 521 | |
| 475 | 522 | return new WP_REST_Response( array( 'data' => $response ), 200 ); |
| 476 | 523 | } |
| 477 | 524 | |
| 478 | - | |
| 479 | 525 | /** |
| 480 | - * API Endpoint: POST /smart-linking/url-to-post-type. | |
| 526 | + * API Endpoint: POST /smart-linking/get-post-meta-for-urls. | |
| 481 | 527 | * |
| 482 | - * Converts a URL to a post type. | |
| 528 | + * Returns post meta for the passed URLs. | |
| 483 | 529 | * |
| 484 | - * @since 3.16.0 | |
| 530 | + * @since 3.18.0 | |
| 485 | 531 | * |
| 486 | 532 | * @param WP_REST_Request $request The request object. |
| 487 | 533 | * @return WP_REST_Response The response object. |
| 488 | 534 | */ |
| 489 | - public function url_to_post_type( WP_REST_Request $request ): WP_REST_Response { | |
| 490 | - $url = $request->get_param( 'url' ); | |
| 535 | + public function get_post_meta_for_urls( WP_REST_Request $request ): WP_REST_Response { | |
| 536 | + $urls = $request->get_param( 'urls' ); | |
| 537 | + $posts_meta = array(); | |
| 491 | 538 | |
| 492 | - if ( ! is_string( $url ) ) { | |
| 493 | - return new WP_REST_Response( | |
| 494 | - array( | |
| 495 | - 'error' => array( | |
| 496 | - 'name' => 'invalid_request', | |
| 497 | - 'message' => __( 'Invalid request body.', 'wp-parsely' ), | |
| 498 | - ), | |
| 499 | - ), | |
| 500 | - 400 | |
| 501 | - ); | |
| 502 | - } | |
| 539 | + foreach ( $urls as $url ) { | |
| 540 | + $post_id = Utils::get_post_id_by_url( $url ); | |
| 503 | 541 | |
| 504 | - $post_id = 0; | |
| 505 | - $cache = wp_cache_get( $url, 'wp_parsely_smart_link_url_to_postid' ); | |
| 542 | + if ( $post_id > 0 ) { | |
| 543 | + $post = get_post( $post_id ); | |
| 506 | 544 | |
| 507 | - if ( is_integer( $cache ) ) { | |
| 508 | - $post_id = $cache; | |
| 509 | - } elseif ( function_exists( 'wpcom_vip_url_to_postid' ) ) { | |
| 510 | - $post_id = wpcom_vip_url_to_postid( $url ); | |
| 511 | - } else { | |
| 512 | - // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.url_to_postid_url_to_postid | |
| 513 | - $post_id = url_to_postid( $url ); | |
| 514 | - wp_cache_set( $url, $post_id, 'wp_parsely_smart_link_url_to_postid' ); | |
| 515 | - } | |
| 545 | + // URLs resolve by slug, irrespective of the post's status. | |
| 546 | + if ( null !== $post && current_user_can( 'read_post', $post_id ) ) { | |
| 547 | + $post_type_obj = get_post_type_object( $post->post_type ); | |
| 548 | + $post_type_name = $post_type_obj instanceof \WP_Post_Type ? $post_type_obj->labels->singular_name : ''; | |
| 516 | 549 | |
| 517 | - $response = array( | |
| 518 | - 'data' => array( | |
| 519 | - 'post_id' => false, | |
| 520 | - 'post_type' => false, | |
| 521 | - ), | |
| 522 | - ); | |
| 523 | - | |
| 524 | - if ( 0 !== $post_id ) { | |
| 525 | - $response['data']['post_id'] = $post_id; | |
| 526 | - $response['data']['post_type'] = get_post_type( $post_id ); | |
| 550 | + $posts_meta[] = array( | |
| 551 | + 'author' => get_the_author_meta( 'display_name', intval( $post->post_author ) ), | |
| 552 | + 'date' => get_the_date( '', $post ), | |
| 553 | + 'id' => $post_id, | |
| 554 | + 'title' => $post->post_title, | |
| 555 | + 'thumbnail' => get_the_post_thumbnail_url( $post, 'thumbnail' ), | |
| 556 | + 'type' => $post_type_name, | |
| 557 | + 'url' => $url, | |
| 558 | + ); | |
| 559 | + } | |
| 560 | + } | |
| 527 | 561 | } |
| 528 | 562 | |
| 529 | - return new WP_REST_Response( $response, 200 ); | |
| 563 | + return new WP_REST_Response( array( 'data' => $posts_meta ), 200 ); | |
| 530 | 564 | } |
| 531 | 565 | |
| 532 | 566 | /** |
| 533 | - * Validates the URL exclusion list parameter. | |
| 534 | - * | |
| 535 | - * The callback sets the URL exclusion list in the request object if the parameter is valid. | |
| 536 | - * | |
| 537 | - * @since 3.17.0 | |
| 538 | - * @access private | |
| 539 | - * | |
| 540 | - * @param mixed $param The parameter value. | |
| 541 | - * @param WP_REST_Request $request The request object. | |
| 542 | - * @return true|WP_Error Whether the parameter is valid. | |
| 543 | - */ | |
| 544 | - public function validate_url_exclusion_list( $param, WP_REST_Request $request ) { | |
| 545 | - if ( ! is_array( $param ) ) { | |
| 546 | - return new WP_Error( 'invalid_url_exclusion_list', __( 'The URL exclusion list must be an array.', 'wp-parsely' ) ); | |
| 547 | - } | |
| 548 | - | |
| 549 | - $valid_urls = array_filter( | |
| 550 | - $param, | |
| 551 | - function ( $url ) { | |
| 552 | - return is_string( $url ) && false !== filter_var( $url, FILTER_VALIDATE_URL ); | |
| 553 | - } | |
| 554 | - ); | |
| 555 | - | |
| 556 | - $request->set_param( 'url_exclusion_list', $valid_urls ); | |
| 557 | - | |
| 558 | - return true; | |
| 559 | - } | |
| 560 | - | |
| 561 | - /** | |
| 562 | 567 | * Validates the smart link parameters. |
| 563 | 568 | * |
| 564 | 569 | * The callback sets the smart link object in the request object if the parameters are valid. |
| 565 | 570 | * |
| 566 | 571 | * @since 3.16.0 |
| 572 | + * @since 3.24.2 Rejects non-arrays. | |
| 567 | 573 | * @access private |
| 568 | 574 | * |
| 569 | - * @param array<mixed> $params The parameters. | |
| 575 | + * @param mixed $params The raw parameter value, as validation runs before type checks. | |
| 570 | 576 | * @param WP_REST_Request $request The request object. |
| 571 | 577 | * @return bool Whether the parameters are valid. |
| 572 | 578 | */ |
| 573 | - public function validate_smart_link_params( array $params, WP_REST_Request $request ): bool { | |
| 579 | + public function validate_smart_link_params( $params, WP_REST_Request $request ): bool { | |
| 580 | + if ( ! is_array( $params ) ) { | |
| 581 | + return false; | |
| 582 | + } | |
| 583 | + | |
| 574 | 584 | $required_params = array( 'uid', 'href', 'title', 'text', 'offset' ); |
| 575 | 585 | |
| 576 | 586 | foreach ( $required_params as $param ) { |
| 577 | 587 | if ( ! isset( $params[ $param ] ) ) { |
| @@ -592,13 +602,25 @@ | ||
| 592 | 602 | if ( ! is_string( $params['uid'] ) ) { |
| 593 | 603 | return false; |
| 594 | 604 | } |
| 595 | 605 | |
| 606 | + if ( ! is_array( $params['href'] ) ) { | |
| 607 | + return false; | |
| 608 | + } | |
| 609 | + | |
| 610 | + if ( ! is_string( $params['href']['raw'] ) ) { | |
| 611 | + return false; | |
| 612 | + } | |
| 613 | + | |
| 614 | + if ( ! Smart_Link::is_valid_href( $params['href']['raw'] ) ) { | |
| 615 | + return false; | |
| 616 | + } | |
| 617 | + | |
| 596 | 618 | // Try to get the smart link from the UID. |
| 597 | 619 | $smart_link = Smart_Link::get_smart_link( $params['uid'], intval( $post_id ) ); |
| 598 | 620 | if ( $smart_link->exists() ) { |
| 599 | 621 | // Update the smart link with the new data. |
| 600 | - $smart_link->set_href( $params['href'] ); | |
| 622 | + $smart_link->set_href( $params['href']['raw'] ); | |
| 601 | 623 | $smart_link->title = $params['title']; |
| 602 | 624 | $smart_link->text = $params['text']; |
| 603 | 625 | $smart_link->offset = $params['offset']; |
| 604 | 626 | } else { |
| @@ -610,8 +632,13 @@ | ||
| 610 | 632 | $smart_link = Smart_Link::deserialize( $encoded_data ); |
| 611 | 633 | $smart_link->set_source_post_id( intval( $post_id ) ); |
| 612 | 634 | } |
| 613 | 635 | |
| 636 | + // If the context is not set, set it to Smart Linking. | |
| 637 | + if ( null === $smart_link->get_context() ) { | |
| 638 | + $smart_link->set_context( $this->get_pch_feature_name() ); | |
| 639 | + } | |
| 640 | + | |
| 614 | 641 | // Set the smart link attribute in the request. |
| 615 | 642 | $request->set_param( 'smart_link', $smart_link ); |
| 616 | 643 | |
| 617 | 644 | return true; |
| @@ -622,15 +649,20 @@ | ||
| 622 | 649 | * |
| 623 | 650 | * The callback sets the smart links object in the request object if the parameters are valid. |
| 624 | 651 | * |
| 625 | 652 | * @since 3.16.0 |
| 653 | + * @since 3.24.2 Rejects non-arrays. | |
| 626 | 654 | * @access private |
| 627 | 655 | * |
| 628 | - * @param array<array<mixed>> $param The parameter value. | |
| 629 | - * @param WP_REST_Request $request The request object. | |
| 656 | + * @param mixed $param The raw parameter value, as validation runs before type checks. | |
| 657 | + * @param WP_REST_Request $request The request object. | |
| 630 | 658 | * @return bool Whether the parameter is valid. |
| 631 | 659 | */ |
| 632 | - public function validate_multiple_smart_links( array $param, WP_REST_Request $request ): bool { | |
| 660 | + public function validate_multiple_smart_links( $param, WP_REST_Request $request ): bool { | |
| 661 | + if ( ! is_array( $param ) ) { | |
| 662 | + return false; | |
| 663 | + } | |
| 664 | + | |
| 633 | 665 | $smart_links = array(); |
| 634 | 666 | |
| 635 | 667 | foreach ( $param as $link ) { |
| 636 | 668 | if ( $this->validate_smart_link_params( $link, $request ) ) { |
| @@ -643,8 +675,50 @@ | ||
| 643 | 675 | $request->set_param( 'smart_link', null ); |
| 644 | 676 | $request->set_param( 'smart_links', $smart_links ); |
| 645 | 677 | |
| 646 | 678 | return true; |
| 679 | + } | |
| 680 | + | |
| 681 | + /** | |
| 682 | + * Serializes inbound Smart Links, dropping the ones whose source post the | |
| 683 | + * current user cannot see. | |
| 684 | + * | |
| 685 | + * @since 3.24.2 | |
| 686 | + * | |
| 687 | + * @param Smart_Link[] $links The inbound Smart Links to serialize. | |
| 688 | + * @return array<mixed> The serialized Smart Links. | |
| 689 | + */ | |
| 690 | + private function serialize_visible_inbound_links( array $links ): array { | |
| 691 | + $serialized = array(); | |
| 692 | + | |
| 693 | + foreach ( $links as $link ) { | |
| 694 | + $source_post_id = $link->source_post_id; | |
| 695 | + $can_edit = current_user_can( 'edit_post', $source_post_id ); | |
| 696 | + | |
| 697 | + if ( ! $can_edit && ! is_post_publicly_viewable( $source_post_id ) ) { | |
| 698 | + continue; | |
| 699 | + } | |
| 700 | + | |
| 701 | + $data = json_decode( $link->serialize(), true ); | |
| 702 | + | |
| 703 | + if ( ! is_array( $data ) ) { | |
| 704 | + continue; | |
| 705 | + } | |
| 706 | + | |
| 707 | + // WordPress withholds a protected post's content; the anchor text | |
| 708 | + // and the paragraph are both drawn from it. | |
| 709 | + if ( ! $can_edit && post_password_required( $source_post_id ) ) { | |
| 710 | + $data['text'] = ''; | |
| 711 | + | |
| 712 | + if ( isset( $data['post_data'] ) && is_array( $data['post_data'] ) ) { | |
| 713 | + $data['post_data']['paragraph'] = ''; | |
| 714 | + } | |
| 715 | + } | |
| 716 | + | |
| 717 | + $serialized[] = $data; | |
| 718 | + } | |
| 719 | + | |
| 720 | + return $serialized; | |
| 647 | 721 | } |
| 648 | 722 | |
| 649 | 723 | /** |
| 650 | 724 | * Serializes an array of Smart Links. |