You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ACF自定义字段类型:input_admin_enqueue_scripts回调函数未触发求助

ACF自定义字段:通过YouTube ID调用API填充字段 + 解决input_admin_enqueue_scripts不加载JS问题

一、核心问题解决:input_admin_enqueue_scripts不触发

ACF 5+版本要求自定义字段通过继承ACF_Field基类实现,input_admin_enqueue_scripts是类的内置方法,只要注册逻辑正确就会自动触发。常见错误点:

  • 未正确继承ACF_Field类
  • JS文件使用相对路径(必须用绝对URL)
  • 未调用acf_register_field_type()完成字段注册

二、完整实现代码

1. PHP字段类型注册文件(示例命名:youtube-video-field.php)

<?php
/*
Plugin Name: ACF YouTube Video Field
Description: 自定义ACF字段,通过YouTube ID拉取视频详情
Version: 1.0
*/

if( ! defined( 'ABSPATH' ) ) exit;

class ACF_Field_YouTube_Video extends ACF_Field {

    public function initialize() {
        // 字段基础配置
        $this->name = 'youtube_video';
        $this->label = __('YouTube视频详情', 'acf-youtube-video');
        $this->category = 'content';
        $this->defaults = array(
            'youtube_api_key' => '',
        );
    }

    // 渲染字段设置项(添加API密钥配置)
    public function render_field_settings( $field ) {
        acf_render_field_setting( $field, array(
            'label'			=> __('YouTube API密钥', 'acf-youtube-video'),
            'instructions'	=> __('输入你的YouTube Data API v3密钥', 'acf-youtube-video'),
            'type'			=> 'text',
            'name'			=> 'youtube_api_key',
        ));
    }

    // 渲染字段输入界面
    public function render_field( $field ) {
        ?>
        <div class="acf-youtube-video-field">
            <div class="acf-input-wrap">
                <label><?php _e('YouTube ID', 'acf-youtube-video'); ?></label>
                <input type="text" name="<?php echo esc_attr($field['name']); ?>[youtube_id]" value="<?php echo esc_attr($field['value']['youtube_id'] ?? ''); ?>" class="youtube-id-input" />
            </div>
            
            <button type="button" class="button button-primary fetch-youtube-data" data-api-key="<?php echo esc_attr($field['youtube_api_key']); ?>">
                <?php _e('拉取视频详情', 'acf-youtube-video'); ?>
            </button>

            <div class="youtube-details-fields" style="margin-top: 20px; padding-top: 20px; border-top: 1px solid #eee;">
                <div class="acf-input-wrap">
                    <label><?php _e('标题', 'acf-youtube-video'); ?></label>
                    <input type="text" name="<?php echo esc_attr($field['name']); ?>[title]" value="<?php echo esc_attr($field['value']['title'] ?? ''); ?>" class="youtube-title" readonly />
                </div>
                
                <div class="acf-input-wrap" style="margin-top: 10px;">
                    <label><?php _e('描述', 'acf-youtube-video'); ?></label>
                    <textarea name="<?php echo esc_attr($field['name']); ?>[description]" class="youtube-description" readonly><?php echo esc_textarea($field['value']['description'] ?? ''); ?></textarea>
                </div>
                
                <div class="acf-input-wrap" style="margin-top: 10px;">
                    <label><?php _e('缩略图URL', 'acf-youtube-video'); ?></label>
                    <input type="text" name="<?php echo esc_attr($field['name']); ?>[thumbnail_url]" value="<?php echo esc_attr($field['value']['thumbnail_url'] ?? ''); ?>" class="youtube-thumbnail" readonly />
                </div>
                
                <div class="acf-input-wrap" style="margin-top: 10px;">
                    <label><?php _e('上传日期', 'acf-youtube-video'); ?></label>
                    <input type="text" name="<?php echo esc_attr($field['name']); ?>[upload_date]" value="<?php echo esc_attr($field['value']['upload_date'] ?? ''); ?>" class="youtube-upload-date" readonly />
                </div>
                
                <div style="display: flex; gap: 10px; margin-top: 10px;">
                    <div class="acf-input-wrap">
                        <label><?php _e('时长(分钟)', 'acf-youtube-video'); ?></label>
                        <input type="number" name="<?php echo esc_attr($field['name']); ?>[duration_minutes]" value="<?php echo esc_attr($field['value']['duration_minutes'] ?? 0); ?>" class="youtube-duration-minutes" readonly />
                    </div>
                    
                    <div class="acf-input-wrap">
                        <label><?php _e('时长(秒)', 'acf-youtube-video'); ?></label>
                        <input type="number" name="<?php echo esc_attr($field['name']); ?>[duration_seconds]" value="<?php echo esc_attr($field['value']['duration_seconds'] ?? 0); ?>" class="youtube-duration-seconds" readonly />
                    </div>
                </div>
            </div>
        </div>
        <?php
    }

    // 加载JS/CSS资源
    public function input_admin_enqueue_scripts() {
        // 用绝对URL加载JS,确保路径正确
        $script_url = plugin_dir_url(__FILE__) . 'youtube-video-field.js';
        wp_enqueue_script('acf-youtube-video-field', $script_url, array('acf-input'), '1.0', true);
    }

    // 保存字段数据
    public function update_value( $value, $post_id, $field ) {
        return array(
            'youtube_id' => sanitize_text_field($value['youtube_id'] ?? ''),
            'title' => sanitize_text_field($value['title'] ?? ''),
            'description' => sanitize_textarea_field($value['description'] ?? ''),
            'thumbnail_url' => esc_url_raw($value['thumbnail_url'] ?? ''),
            'upload_date' => sanitize_text_field($value['upload_date'] ?? ''),
            'duration_minutes' => intval($value['duration_minutes'] ?? 0),
            'duration_seconds' => intval($value['duration_seconds'] ?? 0),
        );
    }
}

// 注册字段类型
add_action('acf/include_field_types', function() {
    new ACF_Field_YouTube_Video();
});

// AJAX处理:拉取YouTube视频数据
add_action('wp_ajax_acf_fetch_youtube_video', 'acf_fetch_youtube_video_data');
function acf_fetch_youtube_video_data() {
    check_ajax_referer('acf_nonce', 'nonce');
    
    $youtube_id = sanitize_text_field($_POST['youtube_id']);
    $api_key = sanitize_text_field($_POST['api_key']);
    
    if( empty($youtube_id) || empty($api_key) ) {
        wp_send_json_error(array('message' => '缺少YouTube ID或API密钥'));
    }
    
    // 调用YouTube API
    $api_url = "https://www.googleapis.com/youtube/v3/videos?id={$youtube_id}&key={$api_key}&part=snippet,contentDetails";
    $response = wp_remote_get($api_url);
    
    if( is_wp_error($response) ) {
        wp_send_json_error(array('message' => '拉取视频数据失败'));
    }
    
    $body = wp_remote_retrieve_body($response);
    $data = json_decode($body, true);
    
    if( empty($data['items']) ) {
        wp_send_json_error(array('message' => '未找到该ID对应的视频'));
    }
    
    $video = $data['items'][0];
    $snippet = $video['snippet'];
    $content_details = $video['contentDetails'];
    
    // 解析ISO 8601格式时长为分钟和秒
    preg_match('/PT(\d+H)?(\d+M)?(\d+S)?/', $content_details['duration'], $matches);
    $hours = isset($matches[1]) ? intval(str_replace('H', '', $matches[1])) : 0;
    $minutes = isset($matches[2]) ? intval(str_replace('M', '', $matches[2])) : 0;
    $seconds = isset($matches[3]) ? intval(str_replace('S', '', $matches[3])) : 0;
    $total_minutes = $hours * 60 + $minutes;
    
    wp_send_json_success(array(
        'title' => $snippet['title'],
        'description' => $snippet['description'],
        'thumbnail_url' => $snippet['thumbnails']['high']['url'],
        'upload_date' => date('Y-m-d H:i:s', strtotime($snippet['publishedAt'])),
        'duration_minutes' => $total_minutes,
        'duration_seconds' => $seconds,
    ));
}

2. JS交互文件(youtube-video-field.js)

(function($) {
    $(document).on('click', '.fetch-youtube-data', function(e) {
        e.preventDefault();
        
        var $button = $(this);
        var $fieldWrap = $button.closest('.acf-youtube-video-field');
        var youtubeId = $fieldWrap.find('.youtube-id-input').val().trim();
        var apiKey = $button.data('api-key');
        
        if( !youtubeId ) {
            alert('请输入YouTube ID');
            return;
        }
        
        if( !apiKey ) {
            alert('请在字段设置中配置YouTube API密钥');
            return;
        }
        
        // 加载状态处理
        $button.prop('disabled', true).text('拉取中...');
        
        // 发送AJAX请求
        $.ajax({
            url: acf.get('ajaxurl'),
            type: 'POST',
            data: {
                action: 'acf_fetch_youtube_video',
                youtube_id: youtubeId,
                api_key: apiKey,
                nonce: acf.get('nonce')
            },
            success: function(response) {
                if( response.success ) {
                    var data = response.data;
                    // 填充字段
                    $fieldWrap.find('.youtube-title').val(data.title);
                    $fieldWrap.find('.youtube-description').val(data.description);
                    $fieldWrap.find('.youtube-thumbnail').val(data.thumbnail_url);
                    $fieldWrap.find('.youtube-upload-date').val(data.upload_date);
                    $fieldWrap.find('.youtube-duration-minutes').val(data.duration_minutes);
                    $fieldWrap.find('.youtube-duration-seconds').val(data.duration_seconds);
                } else {
                    alert(response.data.message || '拉取视频数据失败');
                }
            },
            error: function() {
                alert('拉取数据时发生错误');
            },
            complete: function() {
                $button.prop('disabled', false).text('拉取视频详情');
            }
        });
    });
})(jQuery);

三、关键注意事项

  1. API密钥配置:需在Google Cloud控制台创建并启用YouTube Data API v3密钥,确保密钥权限正确。
  2. 路径正确性:input_admin_enqueue_scripts中必须使用绝对URL加载JS,避免因相对路径导致的404错误。
  3. 版本兼容:代码基于ACF 5+版本,若使用ACF 4需改用旧版字段注册方式。
  4. 安全验证:AJAX请求使用ACF内置nonce验证,避免恶意请求。

内容的提问来源于stack exchange,提问作者luna moonfang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 16:34:57