3

I've added a way for my registered users to delete their account but Im fairly sure that wp_delete_user() deletes:

  • User posts and all post meta
  • Links
  • User and all user meta

I also want to delete all the comments from that user (which probably means that all replies has to be deleted as well..). Could anyone help me with that? Especially with getting replies of these posts..


This is currently functions.php version but I'll eventually add it to custom user profile template:

if ( is_user_logged_in() && ! empty( $_GET['delete-my-account'] ) ) {

    add_action( 'init', 'delete_user_account' );
}

function delete_user_account() {

    //Check Nonce
    if ( wp_verify_nonce( 'delete_account' ) ) {

        //Delete user
        $current_user = wp_get_current_user();
        wp_delete_user( $current_user->ID );

        //Just in case - not sure if required
        wp_logout();

        //Redirect to custom "We're sad to see you go.. Your account has been deleted" page
        wp_redirect( 'absolute URI' );
        //Always exit after wp_redirect()
        exit;
    }
}
8
  • Sometimes a plugin would make all a little easier, this one Delete Me is doing all and more. When not wanting it, look in the code. (In the inc folder, delete_user.php line 57/73 shows all code you need/want.)
    – Charles
    Feb 27, 2016 at 1:10
  • 1
    @Charles I actually considered this but I prefer to do this with ~20 lines of code instead of huge amount of files it adds + multisite support + options + shortcodes etc. But I might find what I need from there (kind of stupid of me for not thinking of that), thanks for suggestion.
    – N00b
    Feb 27, 2016 at 1:16
  • I know that it is bulky (most plugins are) but it (those lines as mentioned) contain exactly what you need. Please add complete working code as answer, so others also have some from it :)
    – Charles
    Feb 27, 2016 at 1:19
  • @Charles There is still one problem with that code.. I made a test: commented on my post, also replied to that comment few times. Then I deleted main comment. Problem is that replies still remain but are not shown in front-end. That means that I would need to get replies and delete them as well.. Any idea? This was also my main concern with my question.
    – N00b
    Feb 27, 2016 at 1:33
  • 1
    Take also a good look at the code in the codex for wp_delete_comment click "Expand full source code''.(because there is some more to do!)
    – Charles
    Feb 27, 2016 at 4:34

1 Answer 1

3

Here are a few functions that make use of WP_Comment_Query to pull the user's Comments, then loop through to find any replies, and trash them all.

$current_user = wp_get_current_user();

$deleteReplies = true;
$force_delete = false;
deleteUserComments ( $current_user->ID, $deleteReplies, $force_delete );

If you want to test this without permanently trashing the items, you can reset the comment status using this little function.

$includeReplies = true;
setUserCommentStatus ( $current_user->ID, $includeReplies, 'approve' );

You can certainly reduce this code to fewer lines but it just made sense to break it out. In general, the first search is for all Comments made that are tied to a User's ID. The second loop goes through each of those IDs to find any Comments using those as their parent ID and the process continues until all replies are found.

Finally wp_delete_comment() is run for each unique ID in the final list.


/**
 * Return a list of IDs from Comments by Author
 *
 * @param int|string $user_id
 * @param bool       $includeReplies
 * @param array      $args Overrides for WP_Comment_Query
 *
 * @return array list of Comment IDs
 */
function getCommentsByUser( $user_id, $includeReplies = false, $args = array () ) {
    $query    = new WP_Comment_Query;
    $comments = $query->query( wp_parse_args( $args, array (
        'type'    => 'comment',
        'user_id' => $user_id,
        'fields'  => 'ids',
        'status'  => 'any',
    ) ) );

    if ( ! $includeReplies || empty( $comments ) ) {
        return $comments;
    }

    $children = array ();
    foreach ( $comments as $comment ) {
        $children = array_merge( $children, getCommentReplies( $comment ) );
    }
    return array_filter( array_unique( array_merge( $comments, $children ) ) );
}

/**
 * Return a list of IDs from Comment's Replies
 *
 * @param int|string $comment_id
 * @param array      $args
 *
 * @return array list of Comment IDs
 */
function getCommentReplies( $comment_id, $args = array () ) {
    $query    = new WP_Comment_Query;
    $comments = $query->query( wp_parse_args( $args, array (
        'parent' => $comment_id,
        'type'   => 'comment',
        'fields' => 'ids',
        'status' => 'any',
    ) ) );
    if ( empty( $comments ) ) {
        return $comments;
    }
    $children = array ();
    foreach ( $comments as $comment ) {
        $children = array_merge( $children, getCommentReplies( $comment ) );
    }

    return array_filter( array_unique( array_merge( $comments, $children ) ) );
}

/**
 * Deletes Comments from list of IDs
 *
 * @param array $commentList List of Comment IDs
 * @param bool  $force_delete
 */
function deleteComments( $commentList, $force_delete = false ) {
    $commentList = array_filter( $commentList );
    foreach ( $commentList as $comment ) {
        wp_delete_comment( $comment, $force_delete );
    }
}

/**
 * Deletes all the comments associated with a User
 * @param int|string $userId
 * @param bool       $deleteReplies
 * @param bool       $force_delete
 */
function deleteUserComments( $userId, $deleteReplies = true, $force_delete = false ) {
    $comments = getCommentsByUser( $userId, $deleteReplies, array (
        'status' => array (
            // including 'trash' will permanently delete any trashed items in this operation
            // regardless of force_delete
            'hold', 'approve', 'spam', ( $force_delete ? 'trash' : '' ),
        ),
    ) );
    if ( ! empty( $comments ) ) {
        deleteComments( $comments, $force_delete );
    }
}

/**
 * Set's the status of User's Comments
 * @param int|string $userId
 * @param bool       $includeReplies
 * @param string     $status ['hold', 'approve', 'spam', 'trash']
 */
function setUserCommentStatus( $userId, $includeReplies = true, $status = 'approve' ) {
    $comments = getCommentsByUser( $userId, $includeReplies, array ( 'status' => 'any' ) ); 
    if ( ! empty( $comments ) ) {
        foreach ( $comments as $comment ) { 
            wp_set_comment_status( $comment, $status );
        }
    }
}

Version 2

This one is a bit more condensed.

function getCommentReplies( $comment_id ) {
    $query    = new WP_Comment_Query;
    $comments = $query->query( array (
        'parent' => $comment_id,
        'type'   => 'comment',
        'fields' => 'ids',
        'status' => 'any',
    ) );
    if ( empty( $comments ) ) {
        return $comments;
    }
    $children = array ();
    foreach ( $comments as $comment ) {
        $children = array_merge( $children, getCommentReplies( $comment ) );
    }
    return array_filter( array_unique( array_merge( $comments, $children ) ) );
}

$query    = new WP_Comment_Query;
$comments = $query->query( array (
    'user_id' => get_current_user_id(),
    'type'    => 'comment',
    'fields'  => 'ids',
    'status'  => 'any',
) );

$children = array ();
foreach ( $comments as $comment ) {
    $children = array_merge( $children, getCommentReplies( $comment ) );
}

$final = array_filter( array_unique( array_merge( $comments, $children ) ) );
foreach ( $final as $comment ) {
    wp_delete_comment( $comment, true );
}
2
  • 2
    It could be handy to have functions like wpse_branch_delete_{post,comment,term}(). I don't think there are such core functions. Maybe it would be a good idea to additionally wrap the code into such a function for comments? I'm sure it could be helpful to others.
    – birgire
    Feb 27, 2016 at 15:18
  • 1
    Sounds like a good idea
    – jgraup
    Feb 27, 2016 at 15:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.