在wordpress中,使用ACF,将任何字段设置为只读前面

问题描述 投票:0回答:1

首先让我澄清两件事:

  1. 前面我指的是任何客户端渲染,而不是服务器端操作。例如,它可以是编辑帖子的管理面板。
  2. 所谓只读,其实是指acf字段会被显示,但不能修改。

ACF 建议向支持此属性的输入元素添加“disabled”或“readonly”,但这还不够:

  1. 并非所有 acf 字段都可以自定义为只读或禁用(当然,某些字段不需要此功能,但其他字段可以使用它,例如复选框或范围)

  2. “禁用”不做这项工作:如果您提交一个禁用了复选框 acf 字段的表单,它将删除该字段的数据,因此该字段是可修改的,但方式很糟糕。您只能将其添加到以下字段:

    • with
      $field['disabled']=1;
      :“文本”、“文本区域”、“数字”、“电子邮件”、“网址”、“密码”、“日期选择器”、“时间选择器”、“选择”
    • with
      $field['disabled']=array(<elements to disable>)
      :'复选框','单选按钮'
  3. “只读”在更少的字段上可用,并且不会从发布请求中删除值,因此,如果包含该字段的页面打开并且该字段在其他地方被修改,如果您提交此页面是因为您在其他的,它也会覆盖这个“只读”字段的更改

所以,我尝试了一个解决方案:我在字段更新时进行挂钩,并通过查看 $_POST['acf'] 是否设置来检查它是否来自前面,但我不知道它是否可靠?

function prevent_acf_field_from_updating($null, $value, $post_id, $field) {
  /*
  * if $_POST['acf'] is not set, the update is from server side, so I don't prevent it
  * I suppose ?
  *
  */
  if (!isset($_POST['acf'])) {
    return $null;
  }


  /*
  * to make a field disabled, I use a class
  *
  */
  if (!str_contains($field['wrapper']['class'], 'read_only_acf')) {
    return $null;
  }

  return false;
}
add_filter('acf/pre_update_value', 'prevent_acf_field_from_updating', 10, 4);

我还使用过滤器将

inert
属性添加到包装器
acf/field_wrapper_attributes

但我真的不确定这是一个好方法,检查 $_POST['acf'] 是否可靠?

php wordpress advanced-custom-fields
1个回答
0
投票

经过更多调查,我找到了一个我认为不错的方法,所以我会回答我自己的问题(如果你不想阅读所有推理,请跳到答案末尾的代码)。

正如CBroe在其评论中指出的那样,acf字段仅呈现到管理面板,而不是前端(在wordpress中,“前端”并不意味着通过网络浏览器访问的内容,而是指非管理员访问的内容网络浏览器。管理部分称为后端)

因此,有 2 个地方可以防止特定的 acf 字段从管理员更新:

  1. 检测它们是否来自管理员,并使用过滤器阻止更新
    acf/pre_update_value
    ,正如我在问题中尝试做的那样
  2. 在 html 中禁用它们

使用
acf/pre_update_value
过滤器防止更新:

为了防止此过滤器进行更新,我们需要一种可靠的方法来检测字段更新操作是在管理端还是在服务器端启动。我可以想到 3 种方法来做到这一点:

  1. 通过检查

    $_POST['acf']
    是否已设置,正如我在答案中建议的那样

  2. 通过检测操作是否在管理员中,可以简单地使用

    is_admin()
    完成,但 CBroe 发布的链接显示了更好、更完整的方法:https://florianbrinkmann.com/en/wordpress-backend-request -3815/

    • 这应该可行,但它需要检查很多事情才能在所有情况下正常工作,如文章中所述,所以感觉有点 hacky
  3. 通过将服务器端调用包装在函数中,例如

    my_plugin_acf_field_update()
    ,然后使用函数
    debug_backtrace()
    检查调用是否来自这个函数

    • 它应该是健壮的,但它需要始终在包装函数中包装对
      update_field()
      的服务器端调用,这可能会很痛苦,具体取决于项目的状态和结构(在我的情况下这很好,而且我几乎用过)
    • 而且它还会阻止任何其他插件更新这些 acf 字段,这并不总是合适的,或者相反是一个好点,具体取决于情况

在 html 中禁用:

防止更新的另一种方法是首先防止在 html 中提交字段。

为此,html 为表单元素提供了

disabled
属性,acf 提出了一种将它们添加到某些字段的方法,但效果不佳:

  • 对于某些领域,它似乎有效:

    ['text', 'textarea', 'number', 'email', 'url', 'password', 'date_picker', 'time_picker', 'select']

  • 对于其他一些领域它不起作用:

    ['checkbox', 'radio']
    。为什么 ?实际上,因为 acf 添加了一个带有字段 ref 的隐藏字段,如下所示:
    <input type="hidden" name="acf[field_6617daff359b2]">
    ,因此,如果某个复选框因禁用而未提交,则 acf 无论如何都会接收隐藏输入,然后检查任何复选框值,找不到任何值并推断它们都未被选中,因此它会相应地更新该字段

  • 最后,对于所有其他字段,acf 没有提出任何禁用它们的方法,即使它们由输入元素组成,如范围字段。

但是还有另一种方法,这就是我将在我的项目中使用的方法:您可以使用 acf 内部使用的操作挂钩来渲染每个字段,并在 acf 之前和之后挂钩它,以添加一个

fieldset
元素使用
disabled
属性 -> 它将禁用其中的任何元素,包括隐藏字段。我希望这应该有效并且稳健。

我就是这样做的:

/*
* there is one action hook suitable to open and close the fieldset element :
* 'acf/render_field' -> line 807 in advanced-custom-fields/includes/acf-field-functions.php
*
* acf uses priority 9 for its 'acf/render_field' hook -> see line 64 in advanced-custom-fields/includes/fields/class-acf-field.php
* so we hook before and after
*
* side note : we use a class, 'read_only_acf', to detect if a field should be disabled
*
*/
function open_fieldset_acf_disabled($field) {
  if (str_contains($field['wrapper']['class'], 'read_only_acf')) {
    echo "<fieldset disabled class='acf_disabled_fieldset' style='border:none; margin:0px; padding:0px;'>\n";
  }
}
function close_fieldset_acf_disabled($field) {
  if (str_contains($field['wrapper']['class'], 'read_only_acf')) {
    echo "</fieldset>\n";
  }
}
add_action('acf/render_field', 'open_fieldset_acf_disabled',  8);
add_action('acf/render_field', 'close_fieldset_acf_disabled', 10);
© www.soinside.com 2019 - 2024. All rights reserved.