基于日期自动更新ACF字段及关联课时状态的技术求助
问题描述
需求:当当前日期达到或超过文章设定的日期时,自动关闭该文章的True/False类型Advanced Custom Fields(ACF)选项;同时关闭该文章关联课程下课时的Sample Lesson True/False选项。
最初仅使用init钩子调用update_sample_child_lessons函数,但仅在手动点击文章更新按钮时生效。后尝试通过Cron任务实现自动执行,但未能成功运行,附上相关代码寻求可行解决方案。
原代码
//CRON JOB TO RUN EVERYDAY function myprefix_custom_cron_schedule( $schedules ) { $schedules['every_day'] = array( 'interval' => 86400, //24 HOURS IN SECONDS 'display' => __( 'Every 24 hours' ), ); return $schedules; } add_filter( 'cron_schedules', 'myprefix_custom_cron_schedule' ); if ( ! wp_next_scheduled( 'myprefix_cron_hook' ) ) { wp_schedule_event( time(), 'every_day', 'myprefix_cron_hook' ); } //AUTOMATICALLY ADJUSTS SAMPLE LESSON FREE OPTIONS AND FREE BANNER IF DATE IS PASSED add_action( 'myprefix_cron_hook', 'update_sample_child_lessons' ); function update_sample_child_lessons() { $allcourses = array( 'post_type' => 'sfwd-courses', //CUSTOM POST TYPE: COURSES 'posts_per_page' => -1 //QUERY ALL OF THEM ); $query = new WP_Query($allcourses); if ($query->have_posts()) { global $post; if ( ( in_array( $post->post_type, array( 'sfwd-courses' ), true ) )) { //ONLY DO ACTION IF ON CPT OF COURSES while ($query->have_posts()) { $query->the_post(); $course_id = learndash_get_course_id( $post->ID ); //GET THE COURSE ID $free = get_field('display_free_lessons', $course_id); //GET THE FREE COURSE OPTION (TRUE/FALSE TICKER) if (!empty($free)) { //ONLY DO REST OF CODE IF FREE OPTION IS TURNED ON $freeDate = get_field('free_until', $course_id); //GET THE DATE FIELD THAT THE COURSE IS FREE UNTIL $currentDate = date('Ymd'); //GET CURRENT DATE $diff = strtotime($freeDate) - strtotime($currentDate); //GET THE DIFFERENCE BETWEEN THE TWO DATES if ($diff <= 0) { //ONLY DO REST OF CODE IF DATE DIFFERENCE IS LESS THAN OR EQUAL TO ZERO $value = ''; update_field('display_free_lessons', $value, $course_id); //UPDATES THE FREE OPTION FIELD TO FALSE(OR NOTHING) //LESSON CODE $lessons = array_slice(learndash_course_get_lessons($course_id), 1); //GET ALL THE LESSONS FROM THE COURSE EXCEPT FOR THE FIRST ONE foreach ($lessons as $lesson) { $lessonID = $lesson->ID; //GET THE LESSON ID $lesson_meta = get_post_meta($lessonID); //GET THE METADATA FOR THE LESSON if ( is_array( $lesson_meta ) ) { foreach ( $lesson_meta as $meta_key => $meta_value ) { if ( '_sfwd-lessons' === $meta_key ) { $lesson_settings = maybe_unserialize( $meta_value[0] ); //SOME OF THE ARRAYS ARE SERIALIZED, SO UNSERIALIZE IF NEEDED if ( isset( $lesson_settings['sfwd-lessons_sample_lesson'] ) ) { $lesson_settings['sfwd-lessons_sample_lesson'] = ''; //TURN OFF THE SAMPLE LESSON OPTION ON THE LESSONS } update_post_meta( $lessonID, $meta_key, $lesson_settings ); } } } } //END FOREACH } //END IF DIFF IS 0 wp_reset_postdata(); } } } } }
问题分析
原代码存在几个关键问题导致Cron任务失效或逻辑错误:
- Cron事件调度时机错误:直接在全局作用域执行
wp_schedule_event,可能在WordPress核心初始化完成前触发,导致调度失败 - 全局
$post判断无效:在WP_Query循环外判断$post->post_type,此时$post并非当前循环的课程文章,逻辑无意义 wp_reset_postdata()位置错误:放在了if (!empty($free))代码块内,导致循环未完成就重置了查询上下文,后续循环无法正常获取文章数据- 日期处理兼容性问题:
strtotime($freeDate)若ACF日期字段格式非标准,可能解析失败导致日期判断错误 - Lesson元数据更新逻辑冗余:无需遍历所有post meta,可直接获取并更新LearnDash的Lesson设置
修复后的完整代码
// 注册每日执行的Cron调度 function myprefix_custom_cron_schedule( $schedules ) { $schedules['every_day'] = array( 'interval' => 86400, // 24小时对应的秒数 'display' => __( '每24小时执行一次' ), ); return $schedules; } add_filter( 'cron_schedules', 'myprefix_custom_cron_schedule' ); // 在WordPress初始化完成后调度Cron事件 function myprefix_schedule_daily_cron() { if ( ! wp_next_scheduled( 'myprefix_cron_hook' ) ) { // 设置每天凌晨0点执行,避免随机时间影响 $midnight = strtotime( 'today midnight' ); wp_schedule_event( $midnight, 'every_day', 'myprefix_cron_hook' ); } } add_action( 'init', 'myprefix_schedule_daily_cron' ); // 自动处理过期课程的免费选项和Sample Lesson设置 add_action( 'myprefix_cron_hook', 'update_sample_child_lessons' ); function update_sample_child_lessons() { // 查询所有课程自定义文章类型 $allcourses = array( 'post_type' => 'sfwd-courses', 'posts_per_page' => -1, 'post_status' => 'publish' // 仅处理已发布的课程 ); $query = new WP_Query( $allcourses ); if ( $query->have_posts() ) { while ( $query->have_posts() ) { $query->the_post(); $course_id = get_the_ID(); // 直接获取课程ID,无需额外函数 // 获取ACF的免费显示选项 $free_enabled = get_field( 'display_free_lessons', $course_id ); if ( ! $free_enabled ) { continue; // 免费选项未开启,跳过当前课程 } // 获取ACF的免费截止日期,统一格式为Ymd $free_until_date = get_field( 'free_until', $course_id ); if ( empty( $free_until_date ) ) { continue; // 未设置截止日期,跳过 } $current_date = date( 'Ymd' ); // 转换日期为时间戳进行比较 $free_until_timestamp = strtotime( $free_until_date ); $current_timestamp = strtotime( $current_date ); if ( $free_until_timestamp <= $current_timestamp ) { // 关闭课程的免费显示选项 update_field( 'display_free_lessons', false, $course_id ); // 获取课程下的所有课时(排除第一个) $lessons = array_slice( learndash_course_get_lessons( $course_id ), 1 ); foreach ( $lessons as $lesson ) { $lesson_id = $lesson->ID; // 直接获取LearnDash的Lesson设置 $lesson_settings = get_post_meta( $lesson_id, '_sfwd-lessons', true ); if ( is_array( $lesson_settings ) && isset( $lesson_settings['sfwd-lessons_sample_lesson'] ) ) { // 关闭Sample Lesson选项 $lesson_settings['sfwd-lessons_sample_lesson'] = false; update_post_meta( $lesson_id, '_sfwd-lessons', $lesson_settings ); } } } } // 循环结束后重置查询上下文 wp_reset_postdata(); } }
关键修复说明
- Cron调度时机修正:将Cron事件调度放在
init钩子内,确保WordPress完全初始化后再执行,避免调度失败 - 移除无效判断:删除了循环外的全局
$post类型判断,直接通过WP_Query循环处理课程文章 - 调整重置位置:将
wp_reset_postdata()移到循环结束后,保证整个循环的查询上下文正常 - 日期处理优化:统一日期格式转换逻辑,确保ACF日期字段能正确解析为时间戳,避免比较错误
- 简化Lesson更新逻辑:直接获取
_sfwd-lessons元数据,无需遍历所有post meta,提升执行效率 - 增加容错处理:添加了对未设置截止日期、免费选项未开启的课程的跳过逻辑,避免无效操作
内容的提问来源于stack exchange,提问作者iamgroot
相关产品推荐
相关产品推荐

