Changeset 65250
- Timestamp:
- 11/03/2026 08:34:25 PM (15 hours ago)
- Location:
- trunk
- Files:
-
- 3 edited
-
src/wp-includes/ms-blogs.php (modified) (1 diff)
-
src/wp-includes/query.php (modified) (3 diffs)
-
tests/phpunit/tests/query/randomContentRedirect.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/ms-blogs.php
r64304 r65250 890 890 * @since 4.0.0 891 891 * @since 6.2.0 Added the `$post` parameter. 892 * 893 * @param int $post_id Post ID. 894 * @param WP_Post $post Post object. 895 */ 896 function _update_posts_count_on_delete( $post_id, $post ) { 897 if ( ! $post || 'publish' !== $post->post_status || 'post' !== $post->post_type ) { 892 * @since 7.2.0 The `$post` parameter isn't always guaranteed to be provided. 893 * 894 * @param int $post_id Post ID. 895 * @param WP_Post|null $post Optional. Post object. Default null. 896 */ 897 function _update_posts_count_on_delete( $post_id, $post = null ) { 898 if ( ! $post instanceof WP_Post || 'publish' !== $post->post_status || 'post' !== $post->post_type ) { 898 899 return; 899 900 } -
trunk/src/wp-includes/query.php
r65042 r65250 1514 1514 * 1515 1515 * Runs on the {@see 'wp_after_insert_post'} and {@see 'after_delete_post'} actions. 1516 * Third-party code may fire these actions with unexpected values, so the parameters are 1517 * not type declared. When `$post` is omitted it is looked up from `$post_id`. Passing 1518 * anything other than a `WP_Post` as `$post`, or a post that cannot be looked up, is 1519 * incorrect usage and nothing is flushed. `$post_before` is only considered on 1520 * `wp_after_insert_post`, where passing anything other than a `WP_Post` or null is 1521 * incorrect usage and the value is ignored. 1516 1522 * 1517 1523 * @since 7.2.0 … … 1521 1527 * 1522 1528 * @param int $post_id Post ID. 1523 * @param WP_Post $post Post object.1529 * @param WP_Post|null $post Optional. Post object. Looked up from `$post_id` when null. Default null. 1524 1530 * @param bool $update Optional. Whether this is an existing post being updated. Default false. 1525 1531 * @param WP_Post|null $post_before Optional. Post object before the update, null for new posts. Default null. 1526 1532 */ 1527 function wp_random_content_flush_rewrite_rules_for_post( int $post_id, WP_Post $post, bool $update = false, ?WP_Post$post_before = null ): void {1533 function wp_random_content_flush_rewrite_rules_for_post( $post_id, $post = null, $update = false, $post_before = null ): void { 1528 1534 global $wp_rewrite; 1535 1536 // Only look up a real ID: get_post() falls back to the global post for an empty value. 1537 if ( null === $post && (int) $post_id > 0 ) { 1538 $post = get_post( (int) $post_id ); 1539 } 1540 1541 if ( ! $post instanceof WP_Post ) { 1542 _doing_it_wrong( 1543 __FUNCTION__, 1544 sprintf( 1545 /* translators: 1: $post, 2: WP_Post */ 1546 __( 'The %1$s argument must be a %2$s object.' ), 1547 '<code>$post</code>', 1548 '<code>WP_Post</code>' 1549 ), 1550 '7.2.0' 1551 ); 1552 return; 1553 } 1554 1555 $posts = array( $post ); 1556 1557 // Only wp_after_insert_post passes the previous post object, which matters when it was renamed or moved. 1558 if ( 'wp_after_insert_post' === current_action() ) { 1559 if ( $post_before instanceof WP_Post ) { 1560 $posts[] = $post_before; 1561 } elseif ( null !== $post_before ) { 1562 _doing_it_wrong( 1563 __FUNCTION__, 1564 sprintf( 1565 /* translators: 1: $post_before, 2: WP_Post */ 1566 __( 'The %1$s argument must be a %2$s object or null.' ), 1567 '<code>$post_before</code>', 1568 '<code>WP_Post</code>' 1569 ), 1570 '7.2.0' 1571 ); 1572 } 1573 } 1529 1574 1530 1575 if ( ! $wp_rewrite->using_permalinks() || ! wp_is_random_content_redirect_enabled() ) { … … 1532 1577 } 1533 1578 1534 foreach ( array( $post, $post_before )as $page ) {1579 foreach ( $posts as $page ) { 1535 1580 if ( 1536 $page instanceof WP_Post 1537 && $wp_rewrite->get_random_base() === $page->post_name 1581 $wp_rewrite->get_random_base() === $page->post_name 1538 1582 && ( 1539 1583 ( 'page' === $page->post_type && 0 === (int) $page->post_parent ) -
trunk/tests/phpunit/tests/query/randomContentRedirect.php
r65042 r65250 250 250 ) 251 251 ); 252 } 253 254 /** 255 * Creates a published post and returns the post object. 256 * 257 * @param array<string, mixed> $args Optional. Post arguments. 258 * @return WP_Post Post object. 259 */ 260 protected function create_post_object( array $args = array() ): WP_Post { 261 $post = get_post( $this->create_post( $args ) ); 262 263 $this->assertInstanceOf( WP_Post::class, $post ); 264 265 return $post; 252 266 } 253 267 … … 1407 1421 } 1408 1422 1423 /** 1424 * @dataProvider data_invalid_arguments 1425 * 1426 * @param array<int, mixed> $args The arguments to call the function with. 1427 */ 1428 public function test_invalid_arguments_do_not_flush_rewrite_rules( array $args ): void { 1429 // The data provider cannot query the database, so PHP_INT_MAX stands in for a nonexistent post ID. 1430 $args = array_map( 1431 function ( $arg ) { 1432 return PHP_INT_MAX === $arg ? $this->get_nonexistent_post_id() : $arg; 1433 }, 1434 $args 1435 ); 1436 1437 $this->setExpectedIncorrectUsage( 'wp_random_content_flush_rewrite_rules_for_post' ); 1438 1439 $flushes = new MockAction(); 1440 add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); 1441 1442 wp_random_content_flush_rewrite_rules_for_post( ...$args ); // @phpstan-ignore argument.type (Intentionally passing invalid values.) 1443 1444 $this->assertSame( 0, $flushes->get_call_count(), 'Invalid arguments should not flush the rewrite rules.' ); 1445 } 1446 1447 /** 1448 * Data provider. 1449 * 1450 * Core never fires the `wp_after_insert_post` and `after_delete_post` actions with invalid 1451 * arguments, but third-party code can. Doing so is incorrect usage and must not cause a 1452 * fatal error. 1453 * 1454 * `PHP_INT_MAX` is replaced with a post ID that is verified not to exist when the test runs. 1455 * 1456 * @return array<string, array{array<int, mixed>}> 1457 */ 1458 public function data_invalid_arguments(): array { 1459 return array( 1460 'nulls' => array( array( null, null, false, null ) ), 1461 'strings' => array( array( 'random', 'random', 'yes', 'random' ) ), 1462 'arrays' => array( array( array(), array( 'post_name' => 'random' ), 1, array() ) ), 1463 'nulls without optional values' => array( array( null, null ) ), 1464 'strings without optional values' => array( array( 'random', 'random' ) ), 1465 'post ID of zero without a post' => array( array( 0 ) ), 1466 'nonexistent post ID without a post' => array( array( PHP_INT_MAX ) ), 1467 ); 1468 } 1469 1470 /** 1471 * Returns a post ID that does not exist. 1472 * 1473 * Starts at `PHP_INT_MAX` and decrements until no post is found. 1474 * 1475 * @return int Post ID. 1476 */ 1477 protected function get_nonexistent_post_id(): int { 1478 $post_id = PHP_INT_MAX; 1479 1480 while ( get_post( $post_id ) instanceof WP_Post ) { 1481 --$post_id; 1482 } 1483 1484 return $post_id; 1485 } 1486 1487 /** 1488 * Tests that an omitted post object does not fall back to the global post. 1489 * 1490 * `get_post()` returns the global post for an empty value, which would flush the 1491 * rewrite rules for whatever post is being displayed rather than the one passed in. 1492 */ 1493 public function test_omitted_post_does_not_fall_back_to_the_global_post(): void { 1494 $this->setExpectedIncorrectUsage( 'wp_random_content_flush_rewrite_rules_for_post' ); 1495 1496 $GLOBALS['post'] = $this->create_post_object( 1497 array( 1498 'post_type' => 'page', 1499 'post_name' => 'random', 1500 ) 1501 ); 1502 1503 $flushes = new MockAction(); 1504 add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); 1505 1506 wp_random_content_flush_rewrite_rules_for_post( null ); // @phpstan-ignore argument.type (Intentionally omitting the post ID.) 1507 1508 $this->assertSame( 0, $flushes->get_call_count(), 'An omitted post should not be looked up from the global post.' ); 1509 } 1510 1511 /** 1512 * Tests that an omitted post object is looked up from the post ID. 1513 * 1514 * The `$post` parameter was added to `after_delete_post` in 5.5.0, but third-party 1515 * code written against the original signature may still fire the action with only 1516 * the post ID. 1517 */ 1518 public function test_omitted_post_is_looked_up_from_the_post_id(): void { 1519 $page_id = $this->create_post( 1520 array( 1521 'post_type' => 'page', 1522 'post_name' => 'random', 1523 ) 1524 ); 1525 1526 $flushes = new MockAction(); 1527 add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); 1528 1529 wp_random_content_flush_rewrite_rules_for_post( $page_id ); 1530 1531 $this->assertSame( 1, $flushes->get_call_count(), 'A page at the random base should flush the rewrite rules when only its ID is passed.' ); 1532 } 1533 1534 /** 1535 * Tests that firing `after_delete_post` with only a post ID does not cause a fatal error. 1536 * 1537 * As the post is already deleted, it cannot be looked up from the ID, so the call is 1538 * incorrect usage and the rewrite rules are left alone. 1539 * 1540 * @covers ::_update_posts_count_on_delete 1541 */ 1542 public function test_after_delete_post_fired_with_only_a_post_id_does_not_flush_rewrite_rules(): void { 1543 $post_id = $this->create_post(); 1544 wp_delete_post( $post_id, true ); 1545 1546 $this->setExpectedIncorrectUsage( 'wp_random_content_flush_rewrite_rules_for_post' ); 1547 1548 $flushes = new MockAction(); 1549 add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); 1550 1551 do_action( 'after_delete_post', $post_id ); // @phpstan-ignore WordPress.hookParamCountMismatch (Intentionally omitting the post object.) 1552 1553 $this->assertSame( 0, $flushes->get_call_count(), 'Firing after_delete_post for a deleted post without the post object should not flush the rewrite rules.' ); 1554 } 1555 1556 public function test_page_named_random_still_flushes_rewrite_rules_when_the_other_arguments_are_invalid(): void { 1557 $page = $this->create_post_object( 1558 array( 1559 'post_type' => 'page', 1560 'post_name' => 'random', 1561 ) 1562 ); 1563 1564 $this->setExpectedIncorrectUsage( 'wp_random_content_flush_rewrite_rules_for_post' ); 1565 1566 $flushes = new MockAction(); 1567 add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); 1568 1569 do_action( 'wp_after_insert_post', (string) $page->ID, $page, 'yes', false ); 1570 1571 $this->assertSame( 1, $flushes->get_call_count(), 'A page at the random base should flush the rewrite rules even when the other arguments are invalid.' ); 1572 } 1573 1574 /** 1575 * Tests that the previous post object is only considered on `wp_after_insert_post`. 1576 * 1577 * `after_delete_post` has no previous post, so a value passed in its place is ignored 1578 * rather than reported as incorrect usage. 1579 */ 1580 public function test_post_before_is_ignored_outside_wp_after_insert_post(): void { 1581 $page_before = $this->create_post_object( 1582 array( 1583 'post_type' => 'page', 1584 'post_name' => 'random', 1585 ) 1586 ); 1587 $post = $this->create_post_object(); 1588 1589 $flushes = new MockAction(); 1590 add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); 1591 1592 wp_random_content_flush_rewrite_rules_for_post( $post->ID, $post, false, 'not a post' ); // @phpstan-ignore argument.type (Intentionally passing an invalid value.) 1593 wp_random_content_flush_rewrite_rules_for_post( $post->ID, $post, false, $page_before ); 1594 1595 $this->assertSame( 0, $flushes->get_call_count(), 'The previous post should not be considered outside wp_after_insert_post.' ); 1596 } 1597 1598 public function test_renamed_page_at_random_base_flushes_rewrite_rules_via_post_before(): void { 1599 $page_before = $this->create_post_object( 1600 array( 1601 'post_type' => 'page', 1602 'post_name' => 'random', 1603 ) 1604 ); 1605 $post = $this->create_post_object(); 1606 1607 $flushes = new MockAction(); 1608 add_filter( 'pre_update_option_rewrite_rules', array( $flushes, 'filter' ) ); 1609 1610 do_action( 'wp_after_insert_post', $post->ID, $post, true, $page_before ); 1611 1612 $this->assertSame( 1, $flushes->get_call_count(), 'A page previously at the random base should flush the rewrite rules on wp_after_insert_post.' ); 1613 } 1614 1409 1615 /* 1410 1616 * Opting out.
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)