如何从WordPress数据库中获取高级自定义字段的字段键?

24

我正在使用高级自定义字段与文章类型。我有一些选择性的自定义字段,我想显示每个字段的所有标签选项。

我尝试了以下方式:

$field = get_field_object('hair_color');
$hair = $field["choices"];
    foreach($hair as $value){

执行

var_dump($field)

后发现它是空的:

array(18) { 
   ["key"] => string(16) "field_hair_color" 
   ["label"] => string(0) "" 
   ["name"] => string(10) "hair_color" 
   ["_name"] => string(10) "hair_color" 
   ["type"]=> string(4) "text" 
   ["order_no"]=> int(1) 
   ["instructions"]=> string(0) "" 
   ["required"]=> int(0) 
   ["id"] => string(20) "acf-field-hair_color" 
   ["class"] => string(4) "text" 
   ["conditional_logic"] => array(3) { 
        ["status"] => int(0) 
        ["allorany"]=> string(3) "all" 
        ["rules"]=> int(0) 
   } 
   ["default_value"] => string(0) "" 
   ["formatting"] => string(4) "html" 
   ["maxlength"] => string(0) "" 
   ["placeholder"] => string(0) "" 
   ["prepend"] => string(0) "" 
   ["append"] => string(0) "" 
   ["value"] => bool(false) 
}

获取完整的方法是:

get_field_object('field_51ac9d333d704');

array(17) { 
   ["key"] => string(19) "field_51ac9d333d704" 
   ["label"] => string(13) "Color de pelo" 
   ["name"] => string(10) "hair_color" 
   ["_name"] => string(10) "hair_color" 
   ["type"] => string(6) "select" 
   ["order_no"] => int(9) 
   ["instructions"] => string(27) "Selecciona el color de pelo" 
   ["required"] => int(0) 
   ["id"] => string(20) "acf-field-hair_color" 
   ["class"] => string(6) "select" 
   ["conditional_logic"] => array(3) { 
       ["status"] => int(0) 
       ["rules"] => array(1) { 
           [0] => array(3) { 
               ["field"] => string(19) "field_5195ef9879361" 
               ["operator"] => string(2) "==" 
               ["value"] => string(5) "small" 
           } 
       } 
       ["allorany"] => string(3) "all" 
   } 
   ["choices"] => array(5) { 
        ["bald"] => string(5) "Calvo" 
        ["brown"] => string(8) "Castaño" 
        ["brunette"] => string(6) "Moreno" 
        ["red"] => string(9) "Pelirrojo" 
        ["blonde"] => string(5) "Rubio" 
    } 
    ["default_value"] => string(0) "" 
    ["allow_null"] => int(1) 
    ["multiple"] => int(0) 
    ["field_group"] => int(90679) 
    ["value"]=> bool(false) 
}

但是我有三个环境,我不想硬编码字段键。

有什么解决方案吗? 提前致谢。


1
我是这样做的:`$pageme = get_page_by_title('post_title', OBJECT, 'post_type' );$field = get_field_object('hair_color', $pageme->ID); $pais = $field["choices"];`它运行良好。 - user1432966
8个回答

8

这是@BFDatabaseAdmin提供的答案的修改版本,可以匹配“LIKE”中的确切meta_value。

function get_acf_key($field_name) {
  global $wpdb;
  $length = strlen($field_name);
  $sql = "
    SELECT `meta_key`
    FROM {$wpdb->postmeta}
    WHERE `meta_key` LIKE 'field_%' AND `meta_value` LIKE '%\"name\";s:$length:\"$field_name\";%';
    ";
  return $wpdb->get_var($sql);
}

8

我试着自己完成这个任务,做了一些调查。似乎ACF的每个字段和字段组都作为自定义文章类型存储在数据库中的wp_posts表中。字段为“acf-field”,字段组为“acf-field-group”。

我能够使用这个函数获取字段键,然后在没有该字段的帖子上使用update_field($field_key, $value)。

function get_acf_key($field_name){
    global $wpdb;

    return $wpdb->get_var("
        SELECT post_name
        FROM $wpdb->posts
        WHERE post_type='acf-field' AND post_excerpt='$field_name';
    ");
}

然后我能够使用:

update_field(get_acf_key('my_field_name'), 'some value', $post_id);

要么更新已经拥有该字段的帖子,要么添加该字段及其关键引用到尚未拥有该字段的帖子中。


我认为你正在使用旧版本的高级自定义字段 - 字段不再保存在文章表中,所以很遗憾这样做行不通。 - Sinister Beard
2
我正在使用最新版本。用于描述字段的数据存储在帖子表中作为自定义帖子类型。与其相关数据的字段存储在postmeta表中。最初的问题只是如何获取命名字段的键。 - aaron.cimolini
这些字段绝对不在文章中。只有字段组保留在文章中。 - Sinister Beard
3
版本 5.3.7(2016年4月)(专业版)在 wp_posts 中包括 acf-field 作为 post_type。 - Tom Auger
1
这有点离题,但如果您想要验证/检测 ACF update_field 是否已经生效(它默认不提供此功能),您可以执行以下操作:$field_key = get_acf_key('my_field_name') update_field($field_key, 'some value', $post_id); $verified_value = get_field($field_key, $post_id); if ($value !== $verified_value) : $errors[] = 'Error updating field'; endif; - Davey
谢谢!你的解决方案对我很有用,而其他人的都没有。 - user2662680

6
我想给大家提供另一种选择。我认为现有的答案不错,但是如果您不查看父组,则永远无法获得可靠的字段键,因为字段名称可能存在于多个组中。
例如,假设您有两个自定义组 - 一个用于帖子类型“书籍”,另一个用于自定义帖子类型“电影”。这两个组都添加了一个名为标题的字段。
在数据库中,两者都存储为 post_except ='title'post_type ='acf-field'。具有相同 post_except 的两个条目,因此任何仅依赖于 post_except 的查询都将是错误的,无论通配符如何。
依赖于帖子ID的任何查询也不是很好,因为帖子可能并不存在以传递。因此,您需要通过字段和组合来从名称获取字段键。这个片段对我很有效。
if (! function_exists('acf_field_from_name')) {

    function acf_field_from_name($field, $group)
    {
        global $wpdb;

        return $wpdb->get_var($wpdb->prepare("
            SELECT post.post_name as field_name
            FROM $wpdb->posts AS post
            LEFT JOIN $wpdb->posts AS parent
                ON post.post_parent = parent.id
            WHERE post.post_excerpt = %s
                AND post.post_type = 'acf-field'
                AND parent.post_excerpt = %s
                AND parent.post_type = 'acf-field-group'
        ", $field, $group));
    }
}

将返回名称和组的字段键,如果不存在,则返回 null。

用法:

acf_field_from_name('title', 'movie-fields'); // returns field_3333333333333

acf_field_from_name('title', 'book-fields'); // returns field_4444444444444

acf_field_from_name('plumbus', 'movie'); // returns null

5

ACF提供了一些简单的方法来帮助保持多个环境的同步 - 您可以使用PHP或本地JSON文件注册您的字段。这样做可以让您在多个环境中使用一个字段键继续使用get_field_object()。请参见:

http://www.advancedcustomfields.com/resources/register-fields-via-php/

http://www.advancedcustomfields.com/resources/local-json/

我通常使用用户界面进行ACF开发,然后将所有字段组导出为PHP以在多个环境中部署。 更新一个简单的例子: 您可以将此添加到functions.php或自定义插件中,以编程方式将您的字段添加到多个环境中...然后通过公共field_key在所有环境中调用get_field_object()函数。
add_action('acf/init', 'wp123_add_local_acf_fields');
function wp123_add_local_acf_fields() {

    acf_add_local_field_group(array(
        'key' => 'group_1',
        'title' => 'My Group',
        'fields' => array (
            array (
                'key' => 'field_51ac9d333d704',
                'label' => 'Color de pelo',
                'name' => 'hair_color',
                'type' => 'select',
                'instructions' => 'Selecciona el color de pelo'
                'required' => 0,
                'choices' => array (
                    'bald' => 'Calvo',
                    'brown' => 'Castaño',
                    'brunette' => 'Moreno',
                    'red' => 'Pelirrojo',
                    'blonde' => 'Rubio',
                ),
                'default_value' => array (
                ),
                'allow_null' => 1,
                'multiple' => 0,
            )
        ),
        'location' => array (
            array (
                array (
                    'param' => 'post_type',
                    'operator' => '==',
                    'value' => 'post',
                ),
            ),
        ),
    ));

}

仅包含链接的答案可能会被删除;我建议您从这些链接中提供具体的代码示例来完善您的答案。 - markratledge
当然 - 我已经添加了一个如何使用PHP注册字段的示例。 - locomo

3

正确的方法是使用acf_maybe_get_field函数,就像这样:

acf_maybe_get_field('field_name',false,false);

参数包括:字段名称文章ID(默认为当前文章),最重要的是strict,默认为true,但在此处我们将其设置为false,以便在该文章尚未存在该字段对象时仍然可以获取该字段对象。

参见通过字段名编程方式获取ACF字段键


1
是的,这个方法可行。但请记住,您正在针对一个字段名称进行操作,该名称可能适用于各种自定义字段(例如,Movies和Books自定义文章类型的“评分”字段 - 其中一个可以将1到10个选择字段分配给“评分”字段名称,而另一个可以有“好/坏”复选框),因此这有一定风险。我所做的是硬编码字段键,然后如果没有结果,我使用了acf_maybe_get_field - Chris Trynkiewicz
请查看我在同一参考主题下的评论。 - Mindaugas Jakubauskas

3
ACF的工作方式是需要使用键值的。
来源 (http://www.advancedcustomfields.com/resources/get_field_object/)
"您可以并且应该在所有情况下都使用 $field_key 。 使用 $field_name 的问题在于,如果引用不存在,则ACF将无法找到字段对象并无法保存该值。如果您使用代码插入了一个帖子,就会出现这种情况。 此外,在 update_field 函数中使用 field_key 作为第一个参数更加有效率,因为它可以绕过引用查找。"

4
必须有一种方法可以通过字段名称找到field_key。我不使用field_keys,因为它们在我的不同数据库中是不同的。 - Phil
1
没有可靠的方法,因为插件是从键获取名称而不是相反的方式;我已经发布了一个解决方案,它可以在一些(沉重的)警告下工作。 - Sinister Beard
1
@Phil_1984_ 我们使用WP Sync DB来同步我们的不同环境,以保持密钥相同,供您参考。 - Nick Pickering

2

使用名称无法可靠地检索密钥,因为名称是元数据,因此容易更改,而密钥(至少不手动编辑数据库的情况下)则不会。

但是,这个函数将与最新版本的ACF一起使用,有几个注意事项。ACF在帖子中创建字段组作为ACF的自定义帖子类型,但是有关字段本身的所有数据都保存在post_meta表中。

function get_acf_key($field_name) {

    global $wpdb;

    return $wpdb->get_var("
        SELECT `meta_key`
        FROM $wpdb->postmeta
        WHERE `meta_key` LIKE 'field_%' AND `meta_value` LIKE '%$field_name%';
    ");

}

警告:因为字段名存储在数组的一部分,所以通过SQL查找时必须依赖通配符搜索,这可能存在错误。只要所有字段的名称完全不同,那么就没有问题了,但是如果例如有一个名为“farm”的字段和另一个名为“farmer”的字段,那么就会出错,因为它会找到这两个字段。

更新字段的唯一可靠方式是手动编写键,尽管这显然很笨重,这也是我来这里的原因。


谢谢您 - 是否有更新的方法可以做到这一点? - dama_do_bling
据我所知,没有。ACF的官方说法(也是最安全的方式)是使用键而不是名称。 - Sinister Beard
1
请注意,如果您在PHP中使用导出功能硬编码您的ACF字段(而不是使用DB字段定义),则此方法将无法工作。但是,如果该字段是硬编码的,则假定该键不会更改,并且将在多个环境中保持相同。 - Tom Auger

-1

我曾经遇到过同样的问题,最终使用了一个键,但是这只让我陷入了另一个死胡同,没有正常的方法来获取键值,但幸运的是我遇到了这个。

摘自 - https://wordpress.stackexchange.com/questions/248006/acf-add-fields-values-to-newly-inserted-post

function acf_getValue($fieldname, $post_id){
    if(($value = get_field($fieldname, $post_id)))
        return $value;
    $value = get_post_meta($post_id, $fieldname);
    return $value[0];
}
function acf_updateValue($fieldname, $value, $post_id){
    $field_key = 'field_' . uniqid();
    update_post_meta($post_id, $fieldname, $value);
    update_post_meta($post_id, '_'.$fieldname, $field_key);
    update_field($field_key, $value, $post_id);
}

acf_updateValue 模拟了 ACF 手动保存时的操作方式。因为仅使用 update_field 对于 ACF 列来说是不够的。


嗨,是获取还是更新?500 可能意味着打错了,你有哪一行的确切日志信息吗? - Jiro Matchonson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接