Skip to content

Commit

Permalink
Duplicate Remover (#409)
Browse files Browse the repository at this point in the history
  • Loading branch information
akirk authored Dec 11, 2024
1 parent 1313240 commit 199af50
Show file tree
Hide file tree
Showing 3 changed files with 224 additions and 18 deletions.
163 changes: 147 additions & 16 deletions includes/class-admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ public function admin_menu() {

$menu_title = __( 'Friends', 'friends' ) . $unread_badge;
$page_type = sanitize_title( $menu_title );
$current_page = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : '';
add_menu_page( 'friends', $menu_title, $required_role, 'friends', null, 'dashicons-groups', 3 );
// phpcs:ignore WordPress.WP.I18n.MissingArgDomain
add_submenu_page( 'friends', __( 'Home' ), __( 'Home' ), $required_role, 'friends', array( $this, 'render_admin_home' ) );
Expand All @@ -130,9 +131,8 @@ public function admin_menu() {
// phpcs:ignore WordPress.WP.I18n.MissingArgDomain
add_submenu_page( 'friends', __( 'Settings' ), __( 'Settings' ), $required_role, 'friends-settings', array( $this, 'render_admin_settings' ) );
if (
isset( $_GET['page'] ) &&
in_array(
$_GET['page'],
$current_page,
apply_filters( 'friends_admin_settings_slugs', array( 'friends-settings', 'friends-notification-manager', 'friends-wp-friendships', 'friends-import-export' ) )
)
) {
Expand All @@ -152,30 +152,50 @@ public function admin_menu() {

if ( $this->friends_unread_friend_request_count( 0 ) > 0 ) {
add_submenu_page( 'friends', __( 'Friend Requests', 'friends' ), __( 'Friend Requests', 'friends' ) . $unread_badge, $required_role, 'friends-list-requests', array( $this, 'render_friends_list' ) );
} elseif ( isset( $_GET['page'] ) && 'friends-list-requests' === $_GET['page'] ) {
} elseif ( 'friends-list-requests' === $current_page ) {
// Don't show a no permission page but redirect to the friends list.
add_submenu_page( 'friends', __( 'Friend Requests', 'friends' ), __( 'Friend Requests', 'friends' ) . $unread_badge, $required_role, 'friends-list-requests', array( $this, 'render_friends_list' ) );
}

if (
isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'friends-refresh' ) && // phpcs:ignore WordPress.Security.ValidateSanitizedInput
isset( $_GET['page'] ) && 'friends-refresh' === $_GET['page']
isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_key( $_GET['_wpnonce'] ), 'friends-refresh' ) && 'friends-refresh' === $current_page
) {
add_submenu_page( 'friends', __( 'Refresh', 'friends' ), __( 'Refresh', 'friends' ), $required_role, 'friends-refresh', array( $this, 'admin_refresh_friend_posts' ) );
}

// phpcs:ignore WordPress.WP.I18n.MissingArgDomain
add_submenu_page( 'friends', __( 'Plugins' ), __( 'Plugins' ), $required_role, 'friends-plugins', array( $this, 'admin_plugin_installer' ) );

if ( isset( $_GET['page'] ) && 0 === strpos( sanitize_key( $_GET['page'] ), 'edit-friend' ) ) {
add_submenu_page( 'friends', __( 'Edit User', 'friends' ), __( 'Edit User', 'friends' ), $required_role, 'edit-friend' . ( 'edit-friend' !== $_GET['page'] && isset( $_GET['user'] ) ? '&user=' . intval( $_GET['user'] ) : '' ), array( $this, 'render_admin_edit_friend' ) );
add_submenu_page( 'friends', __( 'Edit Feeds', 'friends' ), __( 'Edit Feeds', 'friends' ), $required_role, 'edit-friend-feeds' . ( 'edit-friend-feeds' !== $_GET['page'] && isset( $_GET['user'] ) ? '&user=' . intval( $_GET['user'] ) : '' ), array( $this, 'render_admin_edit_friend_feeds' ) );
add_submenu_page( 'friends', __( 'Edit Notifications', 'friends' ), __( 'Edit Notifications', 'friends' ), $required_role, 'edit-friend-notifications' . ( 'edit-friend-notifications' !== $_GET['page'] && isset( $_GET['user'] ) ? '&user=' . intval( $_GET['user'] ) : '' ), array( $this, 'render_admin_edit_friend_notifications' ) );
add_submenu_page( 'friends', __( 'Edit Rules', 'friends' ), __( 'Edit Rules', 'friends' ), $required_role, 'edit-friend-rules' . ( 'edit-friend-rules' !== $_GET['page'] && isset( $_GET['user'] ) ? '&user=' . intval( $_GET['user'] ) : '' ), array( $this, 'render_admin_edit_friend_rules' ) );
add_action( 'load-' . $page_type . '_page_edit-friend', array( $this, 'process_admin_edit_friend' ) );
add_action( 'load-' . $page_type . '_page_edit-friend-feeds', array( $this, 'process_admin_edit_friend_feeds' ) );
add_action( 'load-' . $page_type . '_page_edit-friend-notifications', array( $this, 'process_admin_edit_friend_notifications' ) );
add_action( 'load-' . $page_type . '_page_edit-friend-rules', array( $this, 'process_admin_edit_friend_rules' ) );
$friend_submenu_items = array(
'edit-friend' => __( 'Edit User', 'friends' ),
'edit-friend-feeds' => __( 'Edit Feeds', 'friends' ),
'edit-friend-notifications' => __( 'Edit Notifications', 'friends' ),
'edit-friend-rules' => __( 'Edit Rules', 'friends' ),
'duplicate-remover' => __( 'Duplicates', 'friends' ),
);
if ( isset( $friend_submenu_items[ $current_page ] ) ) {
foreach ( $friend_submenu_items as $slug => $title ) {
$user_param = '';
if ( isset( $_GET['user'] ) ) {
$username = sanitize_user( wp_unslash( $_GET['user'] ) );
$user_param = '&user=' . $username . '&_wpnonce=' . wp_create_nonce( $slug . '-' . $username );
}
$slug_ = strtr( $slug, '-', '_' );

add_submenu_page(
'friends',
$title,
$title,
$required_role,
$slug . ( $slug === $current_page ? '' : $user_param ),
array( $this, 'render_admin_' . $slug_ )
);

add_action(
'load-' . $page_type . '_page_' . $slug,
array( $this, 'process_admin_' . $slug_ )
);
}
}

if ( isset( $_GET['page'] ) && 'friends-logs' === $_GET['page'] ) {
Expand Down Expand Up @@ -2595,6 +2615,117 @@ public function process_admin_import_export() {
}
}

public function process_admin_duplicate_remover() {
$friend = $this->check_admin_duplicate_remover();

// Nonce verification done in check_admin_duplicate_remover.
// phpcs:disable WordPress.Security.NonceVerification.Missing

// We iterate over this array and then we sanitize _id.
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
if ( empty( $_POST['deleteduplicate'] ) || ! is_array( $_POST['deleteduplicate'] ) ) {
return;
}

$deleted = 0;
foreach ( array_keys( wp_unslash( $_POST['deleteduplicate'] ) ) as $_id ) {
if ( ! is_numeric( $_id ) ) {
continue;
}

if ( wp_delete_post( intval( $_id ) ) ) {
++$deleted;
}
}
// phpcs:enable WordPress.Security.NonceVerification.Missing
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

if ( $deleted ) {
wp_safe_redirect( add_query_arg( 'deleted', $deleted ) );
exit;
}
}
public function check_admin_duplicate_remover() {
if ( ! Friends::is_main_user() ) {
wp_die( esc_html__( 'Sorry, you are not allowed to edit the rules.', 'friends' ) );
}

if ( ! isset( $_GET['user'] ) ) {
wp_die( esc_html__( 'Invalid user.', 'friends' ) );
}

if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'duplicate-remover-' . sanitize_user( wp_unslash( $_GET['user'] ) ) ) ) {
wp_die( esc_html__( 'Invalid nonce.', 'friends' ) );
}

$friend = User::get_by_username( sanitize_user( wp_unslash( $_GET['user'] ) ) );
if ( ! $friend || is_wp_error( $friend ) ) {
wp_die( esc_html__( 'Invalid username.', 'friends' ) );
}

if (
! $friend->has_cap( 'friend_request' ) &&
! $friend->has_cap( 'pending_friend_request' ) &&
! $friend->has_cap( 'friend' ) &&
! $friend->has_cap( 'subscription' )
) {
wp_die( esc_html__( 'This is not a user related to this plugin.', 'friends' ) );
}

return $friend;
}
/**
* Render the duplicates remover
*/
public function render_admin_duplicate_remover() {
$friend = $this->check_admin_duplicate_remover();

$this->header_edit_friend( $friend, 'duplicate-remover' );
// phpcs:disable WordPress.Security.NonceVerification
if ( isset( $_GET['deleted'] ) ) {
?>
<div id="message" class="updated notice is-dismissible"><p>
<?php
$deleted = intval( $_GET['deleted'] );
echo esc_html(
sprintf(
// translators: %d is the number of duplicates deleted.
_n( 'Deleted %d selected duplicate.', 'Deleted %d selected duplicates.', $deleted, 'friends' ),
$deleted
)
);
?>
</p></div>
<?php
}
// phpcs:enable WordPress.Security.NonceVerification

$friend_posts = new \WP_Query();

$friend_posts->set( 'post_type', Friends::CPT );
$friend_posts->set( 'post_status', array( 'publish', 'private', 'trash' ) );
$friend_posts->set( 'posts_per_page', 100 );
$friend_posts = $friend->modify_query_by_author( $friend_posts );

$uniques = array();
foreach ( $friend_posts->get_posts() as $_post ) {
$permalink = get_permalink( $_post );
if ( ! isset( $uniques[ $permalink ] ) ) {
$uniques[ $permalink ] = $_post->ID;
}
}

$args = array(
'friend' => $friend,
'friend_posts' => $friend_posts,
'uniques' => array_flip( $uniques ),
'feed' => $this->friends->feed,
);

Friends::template_loader()->get_template_part( 'admin/duplicates', null, $args );
}


public function render_friends_logs() {
Friends::template_loader()->get_template_part(
'admin/settings-header',
Expand Down Expand Up @@ -3320,7 +3451,7 @@ public function render_dashboard_widget_controls( $id, $widget = false ) {
$widgets = array( array() );
}

// phpcs:disable WordPress.Security.NonceVerification.Missing
// phpcs:disable WordPress.Security.NonceVerification
if ( isset( $_SERVER['REQUEST_METHOD'] ) && 'POST' === $_SERVER['REQUEST_METHOD'] && isset( $_POST['widget_id'] ) ) {

$id = intval( str_replace( 'friends_dashboard_widget', '', sanitize_text_field( wp_unslash( $_POST['widget_id'] ) ) ) );
Expand All @@ -3341,10 +3472,10 @@ public function render_dashboard_widget_controls( $id, $widget = false ) {
if ( isset( $_POST['delete'] ) ) {
unset( $widgets[ $id ] );
}
// phpcs:enable WordPress.Security.NonceVerification.Missing

update_user_option( $user_id, 'friends_dashboard_widgets', $widgets );
}
// phpcs:enable WordPress.Security.NonceVerification
$args = array();
if ( isset( $widgets[ $id ] ) ) {
$args = $widgets[ $id ];
Expand Down
76 changes: 76 additions & 0 deletions templates/admin/duplicates.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php
/**
* Remove duplicates from the database
*
* @package Friends
*/

namespace Friends;

?>
<h2><?php esc_html_e( 'Duplicates', 'friends' ); ?></h2>
<form method="post">
<p>
<?php

$duplicate_count = 0;
foreach ( $args['friend_posts']->get_posts() as $_post ) {
if ( ! isset( $args['uniques'][ $_post->ID ] ) ) {
++$duplicate_count;
}
}

echo esc_html(
sprintf(
// translators: %d is the number of duplicates.
_n( '%d post was identified as aduplicate.', '%d posts were identified as duplicate.', $duplicate_count, 'friends' ),
$duplicate_count
)
);
echo ' ';
esc_html_e( 'You can check or uncheck the posts before you click the button to delete them.', 'friends' );
?>

</p>
<p>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Delete selected duplicates', 'friends' ); ?></button>
</p>
<table class="wp-list-table widefat fixed striped" style="margin-top: 2em; margin-bottom: 2em; margin-right: 1em">
<tbody>
<tr>
<th class="check-column"></th>
<th class="column-primary column-title"><?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html_e( 'Title' ); ?></th>
<th class="column-primary column-date"><?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html_e( 'Date' ); ?></th>
</tr>
<?php
foreach ( $args['friend_posts']->get_posts() as $_post ) {
$_title = get_the_title( $_post );
if ( empty( $_title ) ) {
$_title = wp_trim_words( get_the_excerpt( $_post ), 10 );
}

?>
<tr>
<td class="duplicate"><input type="checkbox" name="deleteduplicate[<?php echo esc_attr( $_post->ID ); ?>]" <?php checked( ! isset( $args['uniques'][ $_post->ID ] ) ); ?>></td>
<td class="title column-title column-primary" data-colname="<?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_attr_e( 'Title' ); ?>">
<?php
// show the post format as a label.
$post_format = get_post_format( $_post );
if ( ! empty( $post_format ) ) {
?>
<span class="post-format-icon post-format-<?php echo esc_attr( $post_format ); ?>" title="<?php echo esc_attr( get_post_format_string( $post_format ) ); ?>"></span>
<?php
}
?>
<a href="<?php the_permalink( $_post ); ?>" rel="noopener noreferrer"><?php echo esc_html( $_title ); ?></a>
</td>
<td class="date column-date" data-colname="<?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_attr_e( 'Date' ); ?>"><?php echo esc_html( date_i18n( __( 'F j, Y g:i a' ), strtotime( $_post->post_date ) ) ); ?></td>
</tr>
<?php
}
?>
</tbody>
</table>
<button type="submit" class="button button-primary"><?php esc_html_e( 'Delete selected duplicates', 'friends' ); ?></button>

</form>
3 changes: 1 addition & 2 deletions templates/admin/preview-rules.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ function preview_row( $_post, $args ) {
<?php
}
?>
</td>
</td>
</tr>
<?php
Expand Down Expand Up @@ -80,7 +79,7 @@ function preview_row( $_post, $args ) {
<table class="wp-list-table widefat fixed striped" style="margin-top: 2em; margin-bottom: 2em; margin-right: 1em">
<tbody>
<tr>
<th class="column-primary column-title"><?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html_e( 'Title', 'friends' ); ?></th>
<th class="column-primary column-title"><?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html_e( 'Title' ); ?></th>
<th class="column-author"><?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html_e( 'Author' ); ?></th>
<th class="column-date"><?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html_e( 'Date' ); ?></th>
<th class="column-action"><?php esc_html_e( 'Action', 'friends' ); ?></th>
Expand Down

0 comments on commit 199af50

Please sign in to comment.