← All changes
|
src/rest-api/content-helper/class-endpoint-traffic-boost.php
+117
-15
3.23.5
→
3.24.2
View file →
| @@ -304,15 +304,18 @@ | ||
| 304 | 304 | * @param WP_REST_Request $request The request object. |
| 305 | 305 | * @return WP_REST_Response|WP_Error The response object. |
| 306 | 306 | */ |
| 307 | 307 | public function generate_link_suggestions( WP_REST_Request $request ) { |
| 308 | - /** | |
| 309 | - * The post object. | |
| 310 | - * | |
| 311 | - * @var WP_Post $post | |
| 312 | - */ | |
| 313 | - $post = $request->get_param( 'post' ); | |
| 308 | + $post = $this->get_request_post( $request ); | |
| 314 | 309 | |
| 310 | + if ( ! $post instanceof WP_Post ) { | |
| 311 | + return new WP_Error( | |
| 312 | + 'invalid_post', | |
| 313 | + __( 'Invalid post.', 'wp-parsely' ), | |
| 314 | + array( 'status' => 404 ) | |
| 315 | + ); | |
| 316 | + } | |
| 317 | + | |
| 315 | 318 | /** |
| 316 | 319 | * The maximum number of suggestions to return. |
| 317 | 320 | * |
| 318 | 321 | * @var int $max_items |
| @@ -351,8 +354,12 @@ | ||
| 351 | 354 | if ( is_wp_error( $inbound_suggestions ) ) { |
| 352 | 355 | return $inbound_suggestions; |
| 353 | 356 | } |
| 354 | 357 | |
| 358 | + $inbound_suggestions = $this->filter_accessible_links( | |
| 359 | + $inbound_suggestions | |
| 360 | + ); | |
| 361 | + | |
| 355 | 362 | $discard_result = null; |
| 356 | 363 | |
| 357 | 364 | // If the discard_previous flag is set, discard the previous suggestions. |
| 358 | 365 | if ( $discard_previous ) { |
| @@ -397,15 +404,19 @@ | ||
| 397 | 404 | * @param WP_REST_Request $request The request object. |
| 398 | 405 | * @return WP_REST_Response|WP_Error The response object. |
| 399 | 406 | */ |
| 400 | 407 | public function generate_placement_suggestions( WP_REST_Request $request ) { |
| 401 | - /** | |
| 402 | - * The destination post, that the inbound link links to. | |
| 403 | - * | |
| 404 | - * @var WP_Post $destination_post | |
| 405 | - */ | |
| 406 | - $destination_post = $request->get_param( 'post' ); | |
| 408 | + // The destination post, that the inbound link links to. | |
| 409 | + $destination_post = $this->get_request_post( $request ); | |
| 407 | 410 | |
| 411 | + if ( ! $destination_post instanceof WP_Post ) { | |
| 412 | + return new WP_Error( | |
| 413 | + 'invalid_post', | |
| 414 | + __( 'Invalid post.', 'wp-parsely' ), | |
| 415 | + array( 'status' => 404 ) | |
| 416 | + ); | |
| 417 | + } | |
| 418 | + | |
| 408 | 419 | /** |
| 409 | 420 | * The source post ID, where the inbound link will be placed. |
| 410 | 421 | * |
| 411 | 422 | * @var int $source_post_id |
| @@ -446,8 +457,15 @@ | ||
| 446 | 457 | __( 'Invalid source post.', 'wp-parsely' ) |
| 447 | 458 | ); |
| 448 | 459 | } |
| 449 | 460 | |
| 461 | + $source_post_access = $this->validate_source_post_access( | |
| 462 | + $source_post->ID | |
| 463 | + ); | |
| 464 | + if ( is_wp_error( $source_post_access ) ) { | |
| 465 | + return $source_post_access; | |
| 466 | + } | |
| 467 | + | |
| 450 | 468 | $suggestions = $this->suggestions_api->get_inbound_link_positions( |
| 451 | 469 | $source_post, |
| 452 | 470 | $destination_post, |
| 453 | 471 | array( |
| @@ -523,9 +541,11 @@ | ||
| 523 | 541 | */ |
| 524 | 542 | public function get_existing_suggestions( WP_REST_Request $request ) { |
| 525 | 543 | $post_id = $request->get_param( 'post_id' ); |
| 526 | 544 | |
| 527 | - $suggestions = Inbound_Smart_Link::get_existing_suggestions( $post_id ); | |
| 545 | + $suggestions = $this->filter_accessible_links( | |
| 546 | + Inbound_Smart_Link::get_existing_suggestions( $post_id ) | |
| 547 | + ); | |
| 528 | 548 | |
| 529 | 549 | // Convert the inbound smart links to an array. |
| 530 | 550 | $suggestions = array_map( |
| 531 | 551 | function ( Inbound_Smart_Link $link ) { |
| @@ -566,9 +586,14 @@ | ||
| 566 | 586 | public function get_inbound_smart_links( WP_REST_Request $request ) { |
| 567 | 587 | $post_id = $request->get_param( 'post_id' ); |
| 568 | 588 | |
| 569 | 589 | // Get the inbound smart links for the post. |
| 570 | - $inbound_links = Inbound_Smart_Link::get_inbound_smart_links( $post_id, Smart_Link_Status::APPLIED ); | |
| 590 | + $inbound_links = $this->filter_accessible_links( | |
| 591 | + Inbound_Smart_Link::get_inbound_smart_links( | |
| 592 | + $post_id, | |
| 593 | + Smart_Link_Status::APPLIED | |
| 594 | + ) | |
| 595 | + ); | |
| 571 | 596 | |
| 572 | 597 | // Convert the inbound smart links to an array. |
| 573 | 598 | $inbound_links = array_map( |
| 574 | 599 | function ( Inbound_Smart_Link $link ) { |
| @@ -605,9 +630,9 @@ | ||
| 605 | 630 | * |
| 606 | 631 | * @since 3.19.0 |
| 607 | 632 | * |
| 608 | 633 | * @param WP_REST_Request $request The request object. |
| 609 | - * @return WP_REST_Response The response object. | |
| 634 | + * @return WP_REST_Response|WP_Error The response object. | |
| 610 | 635 | */ |
| 611 | 636 | public function discard_suggestion( WP_REST_Request $request ) { |
| 612 | 637 | /** |
| 613 | 638 | * The inbound smart link. |
| @@ -615,8 +640,15 @@ | ||
| 615 | 640 | * @var Inbound_Smart_Link $inbound_link |
| 616 | 641 | */ |
| 617 | 642 | $inbound_link = $request->get_param( 'inbound_link' ); |
| 618 | 643 | |
| 644 | + $source_post_access = $this->validate_source_post_access( | |
| 645 | + $inbound_link->source_post_id | |
| 646 | + ); | |
| 647 | + if ( is_wp_error( $source_post_access ) ) { | |
| 648 | + return $source_post_access; | |
| 649 | + } | |
| 650 | + | |
| 619 | 651 | $deleted = $inbound_link->delete(); |
| 620 | 652 | |
| 621 | 653 | return new WP_REST_Response( array( 'data' => array( 'success' => $deleted ) ), 200 ); |
| 622 | 654 | } |
| @@ -645,8 +677,15 @@ | ||
| 645 | 677 | * @var bool $restore_original_link |
| 646 | 678 | */ |
| 647 | 679 | $restore_original_link = $request->get_param( 'restore_original' ); |
| 648 | 680 | |
| 681 | + $source_post_access = $this->validate_source_post_access( | |
| 682 | + $inbound_link->source_post_id | |
| 683 | + ); | |
| 684 | + if ( is_wp_error( $source_post_access ) ) { | |
| 685 | + return $source_post_access; | |
| 686 | + } | |
| 687 | + | |
| 649 | 688 | $deleted = $inbound_link->remove( $restore_original_link ); |
| 650 | 689 | |
| 651 | 690 | if ( is_wp_error( $deleted ) ) { |
| 652 | 691 | return $deleted; |
| @@ -701,8 +740,15 @@ | ||
| 701 | 740 | * @var bool $restore_original_link |
| 702 | 741 | */ |
| 703 | 742 | $restore_original_link = (bool) $request->get_param( 'restore_original' ); |
| 704 | 743 | |
| 744 | + $source_post_access = $this->validate_source_post_access( | |
| 745 | + $inbound_link->source_post_id | |
| 746 | + ); | |
| 747 | + if ( is_wp_error( $source_post_access ) ) { | |
| 748 | + return $source_post_access; | |
| 749 | + } | |
| 750 | + | |
| 705 | 751 | $updated = $inbound_link->update_link_text( $text, $offset, $restore_original_link ); |
| 706 | 752 | |
| 707 | 753 | $post = get_post( $inbound_link->source_post_id ); |
| 708 | 754 | if ( null === $post ) { |
| @@ -779,8 +825,15 @@ | ||
| 779 | 825 | __( 'Smart Link already applied.', 'wp-parsely' ) |
| 780 | 826 | ); |
| 781 | 827 | } |
| 782 | 828 | |
| 829 | + $source_post_access = $this->validate_source_post_access( | |
| 830 | + $inbound_link->source_post_id | |
| 831 | + ); | |
| 832 | + if ( is_wp_error( $source_post_access ) ) { | |
| 833 | + return $source_post_access; | |
| 834 | + } | |
| 835 | + | |
| 783 | 836 | $applied = $inbound_link->apply(); |
| 784 | 837 | |
| 785 | 838 | if ( is_wp_error( $applied ) ) { |
| 786 | 839 | return $applied; |
| @@ -805,8 +858,57 @@ | ||
| 805 | 858 | 'post_content' => $post->post_content, |
| 806 | 859 | ), |
| 807 | 860 | ), |
| 808 | 861 | 200 |
| 862 | + ); | |
| 863 | + } | |
| 864 | + | |
| 865 | + /** | |
| 866 | + * Removes Smart Links whose source post the current user cannot use the | |
| 867 | + * feature on. | |
| 868 | + * | |
| 869 | + * Also stops the list endpoints from returning data about source posts the | |
| 870 | + * user has no access to. | |
| 871 | + * | |
| 872 | + * @since 3.23.6 | |
| 873 | + * | |
| 874 | + * @param array<Inbound_Smart_Link> $links The Smart Links to filter. | |
| 875 | + * @return array<Inbound_Smart_Link> The accessible Smart Links. | |
| 876 | + */ | |
| 877 | + private function filter_accessible_links( array $links ): array { | |
| 878 | + return array_values( | |
| 879 | + array_filter( | |
| 880 | + $links, | |
| 881 | + function ( Inbound_Smart_Link $link ): bool { | |
| 882 | + return $this->is_pch_feature_enabled_for_user( | |
| 883 | + $link->source_post_id | |
| 884 | + ); | |
| 885 | + } | |
| 886 | + ) | |
| 887 | + ); | |
| 888 | + } | |
| 889 | + | |
| 890 | + /** | |
| 891 | + * Validates that the current user can use the feature on the source post. | |
| 892 | + * | |
| 893 | + * The source post is the post that gets read and modified when a placement | |
| 894 | + * is generated or accepted. It is not always known at permission callback | |
| 895 | + * time, as it can be derived from a stored Smart Link. | |
| 896 | + * | |
| 897 | + * @since 3.23.6 | |
| 898 | + * | |
| 899 | + * @param int $source_post_id The ID of the source post. | |
| 900 | + * @return bool|WP_Error True if access is allowed, WP_Error otherwise. | |
| 901 | + */ | |
| 902 | + private function validate_source_post_access( int $source_post_id ) { | |
| 903 | + if ( $this->is_pch_feature_enabled_for_user( $source_post_id ) ) { | |
| 904 | + return true; | |
| 905 | + } | |
| 906 | + | |
| 907 | + return new WP_Error( | |
| 908 | + 'parsely_cannot_access_source_post', | |
| 909 | + __( 'You are not allowed to modify the source post.', 'wp-parsely' ), | |
| 910 | + array( 'status' => 403 ) | |
| 809 | 911 | ); |
| 810 | 912 | } |
| 811 | 913 | |
| 812 | 914 | /** |