توابع وردپرس برای ایجاد و حذف نوشته
راهنمای کاربردی توابع ایجاد، ویرایش و حذف نوشته در وردپرس؛ از wp_insert_post تا متادیتا، اعتبارسنجی، امنیت و اشتباهات رایج بر پایه تجربه پروژههای واق
هفت سال پیش، یک مشتری از من خواست که برایش یک سیستم ورود انبوه محصولات بسازم. فایل CSV داشت با هزار محصول و میخواست در چند دقیقه همه وارد شوند. من بهجای استفاده از توابع استاندارد وردپرس، مستقیماً کوئری SQL نوشتم. سه ساعت بعد، سایت با خطای حافظه از دسترس خارج شد. وقتی با phpMyAdmin دیتابیس را باز کردم، جدول wp_posts پر بود از ردیفهای ناقص و متادیتاهای یتیم. آن روز درس گرفتم که wp_insert_post فقط یک تابع ساده نیست؛ لایهای از امنیت، اعتبارسنجی و اعمال hookهاست که SQL خام از آن بیبهره است. از آن روز، هیچ نوشتهای را با SQL خام نساختهام و هیچ نوشتهای را هم بدون بررسی دسترسی حذف نکردهام.
در این مقاله، تجربهام از کار با توابع ایجاد و حذف نوشته را با شما به اشتراک میگذارم. اگر با مفاهیم پایه آشنا نیستید، وردپرس چیست و چگونه شروع کنیم و نحوه استفاده از توابع وردپرس در پروژهها پیشنیاز است. این مقاله مکمل توابع وردپرس برای دادههای نوشته است که روی خواندن تمرکز دارد؛ اینجا روی نوشتن، ویرایش و حذف.
چرا توابع استاندارد مهماند؟
وردپرس در جدول wp_posts، تمام نوشتهها، برگهها، CPTها، و ضمیمهها را نگه میدارد. اگر این جدول را با کوئری خام تغییر دهید، سه لایه حیاتی را از دست میدهید:
- لایه Hookها: توابع استاندارد، هوکهایی مثل
save_post،wp_insert_post، وtransition_post_statusرا فعال میکنند. این هوکها، ستون اصلی اکوسیستم افزونهها هستند. اگر با SQL خام بنویسید، افزونههای امنیتی، سئو، و کش شما از تغییر باخبر نمیشوند. - لایه اعتبارسنجی:
wp_insert_post، پاکسازی محتوا، مدیریت slug، تعیین نویسنده، و مدیریت revisionها را خودکار انجام میدهد. اگر با SQL خام بنویسید، باید همه اینها را دستی پیاده کنید. - لایه کش: وردپرس کش داخلی دارد که با SQL خام، بهروز نمیشود. راهنمای کامل در افزایش سرعت سایت وردپرسی و بهینهسازی کد وردپرس.
راهنمای جزئی این مباحث در ساختار هسته وردپرس و توابع دادههای نوشته آمده است.
نوشتن با SQL خام در وردپرس، مثل رانندگی با چراغ خاموش است؛ ممکن است برسید، ولی نه سالم و نه بدون آسیب.
ساخت نوشته با wp_insert_post
تابع اصلی ساخت نوشته، wp_insert_post است. این تابع، هم نوشته جدید میسازد و هم نوشته موجود را بهروزرسانی میکند:
$post_id = wp_insert_post( array(
"post_title" => "عنوان نوشته",
"post_content" => "محتوای نوشته",
"post_excerpt" => "خلاصه نوشته",
"post_status" => "publish",
"post_type" => "post",
"post_author" => get_current_user_id(),
"post_category" => array( 5, 12 ),
"tags_input" => array( "وردپرس", "آموزش" ),
), true );
if ( is_wp_error( $post_id ) ) {
error_log( $post_id->get_error_message() );
} else {
// نوشته ساخته شد
}
پارامتر دوم true، باعث میشود در صورت خطا، WP_Error برگردد بهجای 0. همیشه این پارامتر را بگذارید و is_wp_error را بررسی کنید. راهنمای کامل در توابع دادههای نوشته.
پارامترهای پرکاربرد wp_insert_post:
| پارامتر | توضیح |
|---|---|
| post_title | عنوان نوشته |
| post_content | محتوا (HTML مجاز) |
| post_excerpt | خلاصه |
| post_status | publish، draft، private، pending |
| post_type | post، page، یا CPT سفارشی |
| post_author | شناسه نویسنده |
| post_name | نامک (slug) |
| post_date | تاریخ انتشار (فرمت MySQL) |
| post_category | آرایه شناسه دستهها |
| tags_input | آرایه برچسبها |
| meta_input | آرایه متادیتا |
ساخت نوشته با متادیتا
از وردپرس ۴.۴، میتوانید متادیتا را هم در همان درخواست wp_insert_post پاس دهید:
$post_id = wp_insert_post( array(
"post_title" => "محصول جدید",
"post_type" => "product",
"post_status" => "publish",
"meta_input" => array(
"_price" => 250000,
"_sku" => "SKU-2024-001",
"_in_stock" => "yes",
"_gallery" => array( 101, 102, 103 ),
),
), true );
مزیت این روش: تمام متادیتا در یک عملیات نوشته میشود و هوکها یک بار اجرا میشوند. اگر بعد از ساخت نوشته، متادیتا را جداگانه اضافه کنید، هر متا یک نوشتن جداگانه است و در سایتهای بزرگ، فشار محسوسی روی دیتابیس وارد میکند. راهنمای کامل در کار با متاباکسها، توابع متادیتا، و کار با Options API.
بهروزرسانی نوشته موجود
همان تابع wp_insert_post، اگر پارامتر ID داشته باشد، نوشته را بهروزرسانی میکند:
wp_insert_post( array(
"ID" => $post_id,
"post_title" => "عنوان جدید",
"post_content" => "محتوای جدید",
) );
نکته مهم: اگر میخواهید فقط یک فیلد را تغییر دهید، باید همه فیلدهای دیگر را هم بفرستید، چون wp_insert_post فیلدهای غایب را از دیتابیس نمیخواند و فیلدهای موجود را پاک میکند. راهحل بهتر: از wp_update_post استفاده کنید که همین تابع است ولی بهعنوان wrapper تمیزتر بهکار میرود:
wp_update_post( array(
"ID" => $post_id,
"post_title" => "عنوان جدید",
) );
راهنمای کامل نوشته و برگه در توابع دادههای نوشته.
ساخت برگه و CPT
برای ساخت برگه، همان wp_insert_post استفاده میشود ولی post_type را روی page میگذارید. برای CPT سفارشی، باید post_type را با نام CPT ثبتشده تطبیق دهید:
// ساخت برگه
wp_insert_post( array(
"post_title" => "درباره ما",
"post_type" => "page",
"post_status" => "publish",
) );
// ساخت CPT سفارشی
wp_insert_post( array(
"post_title" => "پروژه اول",
"post_type" => "project",
"post_status" => "publish",
) );
نکته: اگر CPT سفارشی دارید، نام آن باید در سراسر پروژه یکسان باشد. راهنمای کامل در ساخت نوع نوشته سفارشی در وردپرس و کار با CPT در وردپرس.
ساخت نوشته از فرم front-end
یکی از کاربردهای رایج، اجازه دادن به کاربران برای ساخت نوشته از front-end است. اینجا امنیت حیاتی است:
function myplugin_handle_frontend_submit() {
if ( ! isset( $_POST["myplugin_nonce"] ) ||
! wp_verify_nonce( $_POST["myplugin_nonce"], "myplugin_submit" ) ) {
wp_die( "درخواست نامعتبر" );
}
if ( ! is_user_logged_in() ) {
wp_die( "برای ارسال نوشته باید وارد شوید" );
}
if ( ! current_user_can( "publish_posts" ) ) {
wp_die( "شما اجازه ارسال ندارید" );
}
$title = sanitize_text_field( wp_unslash( $_POST["post_title"] ) );
$content = wp_kses_post( wp_unslash( $_POST["post_content"] ) );
if ( empty( $title ) || empty( $content ) ) {
wp_die( "عنوان و محتوا الزامی است" );
}
$post_id = wp_insert_post( array(
"post_title" => $title,
"post_content" => $content,
"post_status" => "pending",
"post_author" => get_current_user_id(),
), true );
if ( is_wp_error( $post_id ) ) {
wp_die( "خطا در ساخت نوشته" );
}
wp_safe_redirect( get_permalink( $post_id ) );
exit;
}
add_action( "template_redirect", "myplugin_handle_frontend_submit" );
سه اصل امنیتی: نانس، بررسی دسترسی، و پاکسازی ورودی. راهنمای کامل در نانس وردپرس، پاکسازی دادهها، اعتبارسنجی دادهها، و PHP امن در وردپرس.
حذف نوشته: wp_delete_post و wp_trash_post
برای حذف نوشته، سه تابع در اختیار دارید:
// انتقال به زبالهدان (قابل بازیابی)
wp_trash_post( $post_id );
// حذف کامل (بدون بازگشت)
wp_delete_post( $post_id, true );
// حذف موقت (بدون انتقال به زبالهدان، بدون پاک کردن متادیتا)
wp_delete_post( $post_id, false );
نکته مهم: پارامتر دوم wp_delete_post تعیین میکند آیا نوشته بهطور کامل حذف شود (true) یا فقط به زبالهدان منتقل شود (false). همیشه در پروژههای مشتریمحور، از wp_trash_post استفاده کنید تا اگر مشتری پشیمان شد، قابل بازیابی باشد. راهنمای زبالهدان در پاکسازی دیتابیس وردپرس و افزونههای بهینهسازی دیتابیس.
حذف نوشته با بررسی دسترسی
حذف نوشته، در هر پروژهای باید با دو لایه محافظت شود:
function myplugin_handle_delete() {
$post_id = isset( $_GET["post_id"] ) ? absint( $_GET["post_id"] ) : 0;
if ( ! $post_id ) {
wp_die( "شناسه نامعتبر" );
}
if ( ! isset( $_GET["_wpnonce"] ) ||
! wp_verify_nonce( $_GET["_wpnonce"], "delete_post_" . $post_id ) ) {
wp_die( "درخواست نامعتبر" );
}
if ( ! current_user_can( "delete_post", $post_id ) ) {
wp_die( "دسترسی غیرمجاز" );
}
wp_trash_post( $post_id );
wp_safe_redirect( admin_url( "edit.php" ) );
exit;
}
add_action( "admin_post_myplugin_delete", "myplugin_handle_delete" );
سه لایه امنیت: بررسی شناسه، نانس و بررسی دسترسی. نکته مهم: هیچ لینک حذفی نباید بدون نانس باشد، حتی برای ادمین. اگر یک مهاجم بتواند ادمین لاگینشده را فریب دهد که روی یک لینک خارجی کلیک کند، بدون نانس، نوشته حذف میشود. راهنمای کامل در حمله CSRF و نانس وردپرس.
حذف انبوه نوشتهها
در پروژههای واقعی، اغلب نیاز به حذف انبوه داریم. مثال: حذف تمام نوشتههای پیشنویس قدیمی:
function myplugin_delete_old_drafts() {
$args = array(
"post_type" => "post",
"post_status" => "draft",
"date_query" => array(
array(
"before" => "6 months ago",
),
),
"posts_per_page" => 100,
"fields" => "ids",
);
$query = new WP_Query( $args );
if ( ! empty( $query->posts ) ) {
foreach ( $query->posts as $post_id ) {
wp_delete_post( $post_id, true );
}
}
}
// این تابع باید در cron روزانه اجرا شود
add_action( "myplugin_daily_cleanup", "myplugin_delete_old_drafts" );
نکته: برای حذف انبوه، همیشه در cron استفاده کنید، نه در هر لود سایت. برای cron واقعی، راهنمای عیبیابی cron وردپرس و زمانبندی cron در وردپرس را ببینید. راهنمای بهینهسازی کوئریهای انبوه در بهینهسازی کوئریها.
هوکهای مهم در ساخت و حذف
سه هوک حیاتی که در ساخت و حذف نوشته بهکار میآیند:
save_post
پس از ذخیره یا بهروزرسانی نوشته اجرا میشود. مناسب برای ذخیره متادیتا و پاکسازی کش:
add_action( "save_post", function( $post_id, $post, $update ) {
if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
return;
}
if ( ! current_user_can( "edit_post", $post_id ) ) {
return;
}
// ذخیره متادیتای اضافی
}, 10, 3 );
before_delete_post
پیش از حذف نوشته اجرا میشود. مناسب برای پاکسازی متادیتا یا داده مرتبط:
add_action( "before_delete_post", function( $post_id ) {
// حذف داده مرتبط
} );
trashed_post و untrashed_post
هنگام انتقال به زبالهدان و بازگشت از آن اجرا میشود. مناسب برای لاگ یا اعلان:
add_action( "trashed_post", function( $post_id ) {
error_log( "نوشته {$post_id} به زبالهدان منتقل شد" );
} );
راهنمای کامل هوکها در هوکهای وردپرس، استفاده صحیح از هوکها، و هوکهای محتوای نوشته.
حذف نوشته در ووکامرس
در ووکامرس، محصولات با wp_delete_post حذف میشوند ولی توصیه میشود از توابع ووکامرس استفاده کنید:
$product = wc_get_product( $product_id );
if ( $product ) {
$product->delete( true ); // true = حذف کامل
}
راهنمای کامل در قالب مناسب ووکامرس، مدیریت سفارشهای ووکامرس، و امنیت فروشگاه ووکامرس.
بازبینی نسخهها (Revisions)
وردپرس بهطور خودکار از هر نوشته، نسخههای قبلی را نگه میدارد. این ویژگی مفید است ولی در سایتهای بزرگ، میتواند دیتابیس را سنگین کند:
// محدودسازی تعداد revisionها در wp-config.php
define( "WP_POST_REVISIONS", 5 );
// حذف نسخههای قدیمی
wp_delete_post_revision( $revision_id );
راهنمای کامل در تأثیر revisionها بر دیتابیس و پاکسازی دیتابیس وردپرس.
ساخت و حذف در مالتیسایت
در وردپرس مالتیسایت، wp_insert_post و wp_delete_post باید با switch_to_blog و restore_current_blog استفاده شوند:
switch_to_blog( $blog_id );
$post_id = wp_insert_post( array( "post_title" => "نوشته در سایت دیگر" ) );
restore_current_blog();
راهنمای کامل در وردپرس مالتیسایت.
اشتباهات رایج
- نبود
is_wp_errorپس ازwp_insert_post: خطای خاموش در ساخت نوشته. اعتبارسنجی دادهها. - نبود پاکسازی در ساخت از فرم: خطر XSS و SQL Injection. PHP امن و پاکسازی دادهها.
- نبود نانس در لینک حذف: خطر CSRF. نانس وردپرس.
- نبود
current_user_canدر حذف: خطر دسترسی غیرمجاز. نقش و دسترسی. - استفاده از
wp_delete_post( $id, true )بدون بکاپ: از دست رفتن دائمی داده. بکاپ سایت. - نادیدهگرفتن هوکهای
save_postوbefore_delete_post: باقیماندن داده یتیم. هوکها. - ساخت نوشته در
initبدون بررسی: ساخت نوشته تکراری در هر لود. هوکها. - حذف انبوه در front-end: فشار دیتابیس و کندی سایت. بهینهسازی کوئریها.
- نبود محدودسازی revision: دیتابیس سنگین در بلندمدت. تأثیر revision.
- استفاده از SQL خام برای حذف: باقیماندن متادیتا و term relationships. پاکسازی دیتابیس.
جمعبندی
توابع ایجاد و حذف نوشته در وردپرس، چهار گروه اصلی دارند: ساخت (wp_insert_post)، بهروزرسانی (wp_update_post)، انتقال به زبالهدان (wp_trash_post)، و حذف کامل (wp_delete_post). سه اصل را در پایان تاکید میکنم: اول، همیشه با توابع استاندارد کار کنید، نه SQL خام. دوم، ساخت و حذف را با نانس و بررسی دسترسی محافظت کنید. سوم، هوکهای save_post و before_delete_post را برای پاکسازی داده مرتبط جدی بگیرید.
اگر تجربهای از یک باگ در ساخت یا حذف نوشته دارید که با تابع استاندارد حل شد، در دیدگاهها بنویسید — همان گزارشهای واقعی، این راهنما را برای توسعهدهنده بعدی دقیقتر میکند. 📝