۵ mahshid
خطا در redirect
جامعه وردپرس (برنامه نویسی) ایجاد شده در ۲۱ آذر ۱۴۰۳

سلام وققتون بخیر من وقتی رو دکه حذف کلیک میکنم کاربر حذف میشه ولی عمل ریدایرکت انجام نمیشه و این خطا رو بهم میده 

Warning: Cannot modify header information - headers already sent by (output started at C:\xampp\htdocs\sample-mp.local\wp-includes\script-loader.php:2938) in C:\xampp\htdocs\sample-mp.local\wp-includes\pluggable.php on line 1438
 

راه حل‌های که به دوستان پیشنهاد داده بودید رو انجام ولی خطا برطرف نشد

این لینک کد من در گیت هاب هست https://github.com/mahshid73/redirect/tree/main

سلام،

خطا میگه قبل از اینکه بتونی headerها (مثل ریدایرکت) رو تغییر بدی یعنی هدری ست کنی، کد HTML یا یک کاراکتر خالی یا یک تکست به مرورگر فرستاده شده. پس باید دقت داشته باشی که قبل از ست کردن هدر، هیچ کاراکتری به مرورگر ارسال نشه حتی یک whitespace هم نباید قبل از تگ استارت php وجود داشته باشه. (معمولاً در فایل‌های php، تگ بسته php برداشته میشه که احیاناً whitespace ای درج نشه مگر در مواردی که فایل به html ختم بشه ...)

این مقاله و راه حل هاش رو هم بخونید تا اطلاعاتتون در این مورد تکمیل شه.

در اینجا میتونی از actionهای وردپرس استفاده کنی و در توابع کدهارو قرار بدی:

<?php
add_action('admin_init', 'handle_user_delete');
function handle_user_delete() {
    if (isset($_GET['action']) && $_GET['action'] === 'delete' && isset($_GET['id']) && is_numeric($_GET['id'])) {
        $user_id = intval($_GET['id']);
        if ($user_id > 0) { // چک کردن معتبر بودن ID کاربر
            $deleted = wp_delete_user($user_id);
            if ($deleted) {
                wp_safe_redirect(admin_url('admin.php?page=user_list'));
                exit; // خیلی مهمه! بعد از ریدایرکت، اجرای اسکریپت رو متوقف کن.
            } else {
                // اگه حذف کاربر ناموفق بود، یه پیغام خطا نشون بده.
                wp_die(__('Error deleting user.', 'text-domain')); // 'text-domain' رو با text domain قالب یا افزونه‌ات عوض کن.
            }
        }
    }
}
function display_user_list() {  // تابعی برای نمایش لیست کاربران
?>
<div class="wrap">
    <h1>لیست کاربران</h1>
    <table class="widefat">
        <!-- ... (بقیه کد HTML) ... -->
            <td>
                <a href="" class="dashicons dashicons-edit"></a>
                <a href="<?php echo add_query_arg(array('action' => 'delete', 'id' => $user->ID), admin_url('admin.php?page=user_list')); ?>" class="dashicons dashicons-trash"></a>
            </td>
        <!-- ... (بقیه کد HTML) ... -->
<?php
}
// نمایش لیست کاربران
display_user_list();
?>

 

محسن موحد ۲۱ آذر ۱۴۰۳، ۱۲:۰۶

من کد شما رو توی فایلم قرار دادم ایدی کاربری که انتخاب کردم توی URL مرورگرم میاد ولی کاربر موردنظرم حذف نمیشه

 

mahshid ۲۱ آذر ۱۴۰۳، ۱۴:۳۶

پروژتون رو کامل رو گیت هاب قرار بدید.

الان اگر کدهای درون تابع handle_user_delete رو خارج از تابع بنویسید قاعدتا کار میکند اما روی هیچ هوکی قرار نگرفته.

محسن موحد ۲۲ آذر ۱۴۰۳، ۰۲:۲۸

این لینک کامل پرژوه من در گیت هاب هست 

https://github.com/mahshid73/redirect

mahshid ۲۲ آذر ۱۴۰۳، ۰۹:۴۱

سلام،

پلاگین رو بررسی کردم،

مشکل پلاگین اینه که قبل ازینکه اسکریپت مخصوص حذف کاربر اجرا بشه، قبلش قالب ادمین رندر شده یعنی ابتدا کدهای قالب سمت خروجی ارسال شدن و شما نمیتونید دیگه هدریو تغییر بدید، مثل ریدایرکت کردن.

برای مثال داخل user-list.php فقط دستور exit رو بنویسید، اگر exit در جایی که ما میخوایم اجرا بشه باید یک صفحه سفید ببینیم و هیچ کد html ای به مرورگر نرسیده باشد ولی شما قالب ادمین رو در صفحه میبینید که قبل از exit در user-list.php اجرا میشه.

این مورد برخلاف توضیحات قبلیمون بوده چون گفته بودیم قبل از ست شدن هدر نباید هیچ echo و خروجی سمت مرورگر ارسال شده باشه و گرنه با خطای can not modify header ... مواجه میشیم. عمل ریدایرکت یعنی (دستور location در php) باید تغییر header انجام میشه. (البته راه جایگزین هم وجود داره مثل ریدایرکت با کد html یا js منتها توصیه میشه دستورات خود فریمورک استفاده بشه و همه چیز استاندارد و اصولی پیش بره.)

 

برای حل این مشکل نیاز داریم از hook درستی برای حذف کاربر استفاده کنیم.

منطق حذف کاربرو میبریم داخل menu.php و بعد از دستورات منو قرار میدیم و نمایش لیست کاربران رو در user-list.php قرار میدیم.

ابتدا کدهای نمایش کاربران رو میذارم، دستورات شما مشکلی ندارن بجز اینکه فقط لینک حذف به صفحه admin-post.php باید ارسال بشن منتها من تغییراتی داخلش اعمال کردم:

<div class="wrap">
    <h1>لیست کاربران</h1>
    <?php
    if (isset($_GET['message'])) {
        if ($_GET['message'] == 'deleted') {
            echo '<div class="notice notice-success is-dismissible"><p>کاربر با موفقیت حذف شد.</p></div>';
        } elseif ($_GET['message'] == 'error') {
            echo '<div class="notice notice-error"><p>خطا در حذف کاربر.</p></div>';
        }
    }
    ?>
    <table class="widefat">
        <thead>
            <tr>
                <th>آیدی</th>
                <th>نام کاربری</th>
                <th>ایمیل</th>
                <th>عملیات</th>
            </tr>
        </thead>
        <tbody>
            <?php
            $users = get_users();
            foreach ($users as $user) {
                // ایجاد لینک حذف با نانس و اکشن مناسب
                $delete_url = wp_nonce_url(
                    admin_url('admin-post.php?action=ua_delete_user&user_id=' . $user->ID),
                    'ua_delete_user_' . $user->ID
                );
                ?>
                <tr>
                    <td><?php echo esc_html($user->ID); ?></td>
                    <td><?php echo esc_html($user->user_login); ?></td>
                    <td><?php echo esc_html($user->user_email); ?></td>
                    <td>
                        <a href="<?php echo esc_url($delete_url); ?>" class="button button-danger" onclick="return confirm('آیا مطمئن هستید که می‌خواهید این کاربر را حذف کنید؟');">حذف</a>
                    </td>
                </tr>
            <?php } ?>
        </tbody>
    </table>
</div>

nonce: واسه جلوگیری از حملات csrf اضافه شده.

esc_html: برای escape و جلوگیری از xss اضافه شده تا کدهای احتمالی تعبیه شده توسط کاربران، خنثی بشه.

 

اما منطق حذف کاربرو در انتهای فایل menu.php میبرم:

add_action('admin_post_ua_delete_user', 'ua_delete_user');
function ua_delete_user() {
    // بررسی دسترسی کاربر
    if (!current_user_can('manage_options')) {
        wp_die('شما مجوز کافی برای انجام این عملیات را ندارید.');
    }
    // بررسی وجود نانس و آی‌دی کاربر
    if (isset($_GET['user_id']) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'ua_delete_user_' . $_GET['user_id'])) {
        $user_id = intval($_GET['user_id']);
        // حذف کاربر
        $deleted = wp_delete_user($user_id);
        if ($deleted) {
            // ریدایرکت با پیام موفقیت
            wp_redirect(admin_url('admin.php?page=user_list&message=deleted'));
            exit;
        } else {
            // ریدایرکت با پیام خطا
            wp_redirect(admin_url('admin.php?page=user_list&message=error'));
            exit;
        }
    } else {
        wp_die('درخواست نامعتبر است.');
    }
}

+ admin-post.php که بعنوان لینک در user-list.php اوردیم چیه؟ 

+ همینطور admin_post و admin_post_ua_delete_user چیه؟

admin-post.php یه فایل تو هسته وردپرسه که تو مسیر wp-admin/admin-post.php قرار گرفته. کارش چیه؟

مدیریت درخواست‌هایی که از سمت بخش مدیریت (همون Admin) ارسال میشن، مثل فرم‌هایی که پر می‌کنی یا لینک‌هایی که یه سری پارامتر خاص دارن. حالا وقتی یک فرم رو از بخش مدیریت میفرستی یا یه لینک با پارامترهایی که به admin-post.php وصل میشن رو دنبال میکنی، وردپرس میاد بر اساس اون پارامترها، اکشن لازم رو اجرا میکنه.

چی کار میکنه دقیق؟

این فایل دنبال یه پارامتر به اسم action می‌گرده که تو URL یا درخواست فرم هست. بعدش بر اساس اون، یه هوک اکشن (یه جور دستور) رو صدا می‌زنه:

اگه کاربر وارد شده باشه و دسترسی داشته باشه، هوک admin_post_{action} اجرا میشه.
اگه کاربر لاگین نکرده باشه یا دسترسی نداشته باشه، هوک admin_post_nopriv_{action} اجرا میشه.
یه مثال بزنم:
فرض کن لینک درخواستت این شکلی باشه:

/wp-admin/admin-post.php?action=ua_delete_user&user_id=123

اینجا وردپرس میاد هوک admin_post_ua_delete_user رو اجرا میکنه.

خلاصه اینکه admin_post_ua_delete_user یه هوک اکشن داینامیک تو وردپرسه که بر اساس پارامتر action توو درخواستت ساخته میشه. اگه یک درخواست به admin-post.php بفرستی و داخلش پارامتر action=ua_delete_user باشه، وردپرس خودش میفهمه که باید هوک admin_post_ua_delete_user رو اجرا کنه. اینطوری میتونی به راحتی اکشن‌های خودت رو در وردپرس مدیریت کنی. 

محسن موحد ۲۶ آذر ۱۴۰۳، ۰۳:۰۳