Make WordPress Core

Changeset 61274


Ignore:
Timestamp:
11/20/2025 01:58:35 PM (4 days ago)
Author:
wildworks
Message:

Notes: trash (or delete) child notes when parent is deleted.

Ensure that when a top level note is trashed (or deleted), all of its replies (children) are also trashed or deleted. If EMPTY_TRASH_DAYS is 0, notes are deleted immediately; otherwise they are marked as trash for later cleanup.

Reviewed by wildworks.
Merges [61248] to the 6.9 branch.

Props adamsilverstein, desrosj, wildworks, mamaduka, karthickmurugan, jeffpaul, shailu25.
See #64240.

Location:
branches/6.9
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • branches/6.9

  • branches/6.9/src/wp-includes/comment.php

    r61199 r61274  
    15751575 *
    15761576 * @since 2.9.0
     1577 * @since 6.9.0 Any child notes are deleted when deleting a note.
    15771578 *
    15781579 * @param int|WP_Comment $comment_id Comment ID or WP_Comment object.
     
    15811582function wp_trash_comment( $comment_id ) {
    15821583    if ( ! EMPTY_TRASH_DAYS ) {
    1583         return wp_delete_comment( $comment_id, true );
     1584        $comment = get_comment( $comment_id );
     1585        $success = wp_delete_comment( $comment_id, true );
     1586
     1587        if ( ! $success ) {
     1588            return false;
     1589        }
     1590
     1591        // Also delete children of top level 'note' type comments.
     1592        if ( $comment && 'note' === $comment->comment_type && 0 === (int) $comment->comment_parent ) {
     1593            $children = $comment->get_children(
     1594                array(
     1595                    'fields' => 'ids',
     1596                    'status' => 'all',
     1597                    'type'   => 'note',
     1598                )
     1599            );
     1600
     1601            foreach ( $children as $child_id ) {
     1602                if ( ! wp_delete_comment( $child_id, true ) ) {
     1603                    $success = false;
     1604                }
     1605            }
     1606        }
     1607
     1608        return $success;
    15841609    }
    15851610
     
    16161641         */
    16171642        do_action( 'trashed_comment', $comment->comment_ID, $comment );
     1643
     1644        // For top level 'note' type comments, also trash children.
     1645        if ( 'note' === $comment->comment_type && 0 === (int) $comment->comment_parent ) {
     1646            $children = $comment->get_children(
     1647                array(
     1648                    'fields' => 'ids',
     1649                    'status' => 'all',
     1650                    'type'   => 'note',
     1651                )
     1652            );
     1653
     1654            $success = true;
     1655            foreach ( $children as $child_id ) {
     1656                if ( ! wp_trash_comment( $child_id ) ) {
     1657                    $success = false;
     1658                }
     1659            }
     1660            return $success;
     1661        }
    16181662
    16191663        return true;
  • branches/6.9/tests/phpunit/tests/comment.php

    r60486 r61274  
    16731673        $this->assertSame( '1', $comment->comment_approved );
    16741674    }
     1675
     1676    /**
     1677     * Tests that trashing a top-level note also trashes all direct child notes.
     1678     *
     1679     * @ticket 64240
     1680     * @covers ::wp_trash_comment
     1681     * @dataProvider data_comment_approved_statuses
     1682     */
     1683    public function test_wp_trash_comment_trashes_child_notes( $approved_status ) {
     1684        // Create a parent note (top-level, comment_parent=0).
     1685        $parent_note = self::factory()->comment->create(
     1686            array(
     1687                'comment_post_ID'  => self::$post_id,
     1688                'comment_type'     => 'note',
     1689                'comment_parent'   => 0,
     1690                'comment_approved' => $approved_status,
     1691            )
     1692        );
     1693
     1694        // Create child notes under the parent.
     1695        $child_note_1 = self::factory()->comment->create(
     1696            array(
     1697                'comment_post_ID'  => self::$post_id,
     1698                'comment_type'     => 'note',
     1699                'comment_parent'   => $parent_note,
     1700                'comment_approved' => $approved_status,
     1701            )
     1702        );
     1703
     1704        $child_note_2 = self::factory()->comment->create(
     1705            array(
     1706                'comment_post_ID'  => self::$post_id,
     1707                'comment_type'     => 'note',
     1708                'comment_parent'   => $parent_note,
     1709                'comment_approved' => $approved_status,
     1710            )
     1711        );
     1712
     1713        $child_note_3 = self::factory()->comment->create(
     1714            array(
     1715                'comment_post_ID'  => self::$post_id,
     1716                'comment_type'     => 'note',
     1717                'comment_parent'   => $parent_note,
     1718                'comment_approved' => $approved_status,
     1719            )
     1720        );
     1721
     1722        // Trash the parent note.
     1723        wp_trash_comment( $parent_note );
     1724
     1725        // Verify parent note is trashed.
     1726        $this->assertSame( 'trash', get_comment( $parent_note )->comment_approved );
     1727
     1728        // Verify all child notes are also trashed.
     1729        $this->assertSame( 'trash', get_comment( $child_note_1 )->comment_approved );
     1730        $this->assertSame( 'trash', get_comment( $child_note_2 )->comment_approved );
     1731        $this->assertSame( 'trash', get_comment( $child_note_3 )->comment_approved );
     1732    }
     1733
     1734    /**
     1735     * Data provider for test_wp_trash_comment_trashes_child_notes.
     1736     */
     1737    public function data_comment_approved_statuses() {
     1738        return array(
     1739            array( '1' ),
     1740            array( '0' ),
     1741        );
     1742    }
     1743
     1744    /**
     1745     * Tests that trashing a regular comment does NOT trash its children.
     1746     *
     1747     * @ticket 64240
     1748     * @covers ::wp_trash_comment
     1749     */
     1750    public function test_wp_trash_comment_does_not_trash_child_comments() {
     1751        // Create a parent comment (default type='comment').
     1752        $parent_comment = self::factory()->comment->create(
     1753            array(
     1754                'comment_post_ID'  => self::$post_id,
     1755                'comment_type'     => 'comment',
     1756                'comment_parent'   => 0,
     1757                'comment_approved' => '1',
     1758            )
     1759        );
     1760
     1761        // Create child comments under the parent.
     1762        $child_comment_1 = self::factory()->comment->create(
     1763            array(
     1764                'comment_post_ID'  => self::$post_id,
     1765                'comment_type'     => 'comment',
     1766                'comment_parent'   => $parent_comment,
     1767                'comment_approved' => '1',
     1768            )
     1769        );
     1770
     1771        $child_comment_2 = self::factory()->comment->create(
     1772            array(
     1773                'comment_post_ID'  => self::$post_id,
     1774                'comment_type'     => 'comment',
     1775                'comment_parent'   => $parent_comment,
     1776                'comment_approved' => '1',
     1777            )
     1778        );
     1779
     1780        // Trash the parent comment.
     1781        wp_trash_comment( $parent_comment );
     1782
     1783        // Verify parent comment is trashed.
     1784        $this->assertSame( 'trash', get_comment( $parent_comment )->comment_approved );
     1785
     1786        // Verify child comments are NOT trashed (maintaining existing behavior).
     1787        $this->assertSame( '1', get_comment( $child_comment_1 )->comment_approved );
     1788        $this->assertSame( '1', get_comment( $child_comment_2 )->comment_approved );
     1789    }
     1790
     1791    /**
     1792     * Tests that trashing a child note does not affect parent or siblings.
     1793     *
     1794     * @ticket 64240
     1795     * @covers ::wp_trash_comment
     1796     */
     1797    public function test_wp_trash_comment_child_note_does_not_affect_parent_or_siblings() {
     1798        // Create a parent note.
     1799        $parent_note = self::factory()->comment->create(
     1800            array(
     1801                'comment_post_ID'  => self::$post_id,
     1802                'comment_type'     => 'note',
     1803                'comment_parent'   => 0,
     1804                'comment_approved' => '1',
     1805            )
     1806        );
     1807
     1808        // Create multiple child notes.
     1809        $child_note_1 = self::factory()->comment->create(
     1810            array(
     1811                'comment_post_ID'  => self::$post_id,
     1812                'comment_type'     => 'note',
     1813                'comment_parent'   => $parent_note,
     1814                'comment_approved' => '1',
     1815            )
     1816        );
     1817
     1818        $child_note_2 = self::factory()->comment->create(
     1819            array(
     1820                'comment_post_ID'  => self::$post_id,
     1821                'comment_type'     => 'note',
     1822                'comment_parent'   => $parent_note,
     1823                'comment_approved' => '1',
     1824            )
     1825        );
     1826
     1827        $child_note_3 = self::factory()->comment->create(
     1828            array(
     1829                'comment_post_ID'  => self::$post_id,
     1830                'comment_type'     => 'note',
     1831                'comment_parent'   => $parent_note,
     1832                'comment_approved' => '1',
     1833            )
     1834        );
     1835
     1836        // Trash only one child note.
     1837        wp_trash_comment( $child_note_2 );
     1838
     1839        // Verify the parent note is still approved.
     1840        $this->assertSame( '1', get_comment( $parent_note )->comment_approved );
     1841
     1842        // Verify the trashed child is trashed.
     1843        $this->assertSame( 'trash', get_comment( $child_note_2 )->comment_approved );
     1844
     1845        // Verify sibling notes are still approved.
     1846        $this->assertSame( '1', get_comment( $child_note_1 )->comment_approved );
     1847        $this->assertSame( '1', get_comment( $child_note_3 )->comment_approved );
     1848    }
     1849
     1850    /**
     1851     * Tests that only top-level notes trigger child deletion.
     1852     *
     1853     * @ticket 64240
     1854     * @covers ::wp_trash_comment
     1855     */
     1856    public function test_wp_trash_comment_only_top_level_notes_trigger_child_deletion() {
     1857        // Create a parent note.
     1858        $parent_note = self::factory()->comment->create(
     1859            array(
     1860                'comment_post_ID'  => self::$post_id,
     1861                'comment_type'     => 'note',
     1862                'comment_parent'   => 0,
     1863                'comment_approved' => '1',
     1864            )
     1865        );
     1866
     1867        // Create a child note (not top-level, has comment_parent > 0).
     1868        $child_note = self::factory()->comment->create(
     1869            array(
     1870                'comment_post_ID'  => self::$post_id,
     1871                'comment_type'     => 'note',
     1872                'comment_parent'   => $parent_note,
     1873                'comment_approved' => '1',
     1874            )
     1875        );
     1876
     1877        // Create a sibling note (also not top-level).
     1878        $sibling_note = self::factory()->comment->create(
     1879            array(
     1880                'comment_post_ID'  => self::$post_id,
     1881                'comment_type'     => 'note',
     1882                'comment_parent'   => $parent_note,
     1883                'comment_approved' => '1',
     1884            )
     1885        );
     1886
     1887        // Trash the child note (which has comment_parent > 0).
     1888        wp_trash_comment( $child_note );
     1889
     1890        // Verify the child note is trashed.
     1891        $this->assertSame( 'trash', get_comment( $child_note )->comment_approved );
     1892
     1893        // Verify the parent note is NOT trashed.
     1894        $this->assertSame( '1', get_comment( $parent_note )->comment_approved );
     1895
     1896        // Verify the sibling note is NOT trashed (no cascade since child is not top-level).
     1897        $this->assertSame( '1', get_comment( $sibling_note )->comment_approved );
     1898    }
    16751899}
Note: See TracChangeset for help on using the changeset viewer.