Adding Template Post Content

时间:2015-11-30 作者:Mike

我试着用各种术语来搜索这个,但我总是会遇到与php模板文件相关的问题。这不是我想要的,所以我要问一个新问题。如果这是重复的,我很抱歉。

基本上,我正在寻找一种创建模板帖子的方法。我在自定义的“Job”帖子类型上使用ACF Pro,并且为“Job Steps”设置了一个Repeater字段

举个例子,“做比萨饼”工作将包含以下步骤:

按照当前的设置方式,用户每次都需要手动定义这些步骤,因此我想做的是创建一个“披萨模板”帖子,用户可以使用它来定义这些步骤,然后添加一个新的“做比萨饼”作业将自动定义步骤,但允许用户填写具体细节,如配料、外皮、送货地址等。

我想做的一件事是添加一个新的“作业模板”帖子类型,它使用与“作业”类型相同的自定义字段定义。然后,当用户创建新作业时,系统会提示他们选择“作业模板”。

如果他们选择“Pizza Template”,它将复制作业模板帖子中的Repeater字段值,并在编辑器中为新作业设置这些值。我怀疑这将是一个非常复杂的过程,所以我希望有人在核心的某个地方知道一种更有效的方法。

编辑根据评论,我发现这个问题的一个方面没有我想的那么清楚,所以要提供更多信息:

我正在尝试创建一个通用的跟踪器插件,用户可以在运行时自定义该插件,以适应各种工作流。Repeater字段为我提供了这种灵活性,但有效使用取决于模板。用户将其工作流定义为模板,然后在创建新作业时使用该模板。

这种方法还允许用户定义多个工作流,而无需多个字段组或多个帖子类型。

我自己也在研究一些可能的解决方案(当我到达那里时,我会发布答案),但我真的希望核心中有一些东西可以让这变得更容易。

3 个回复
最合适的回答,由SO网友:Mike 整理而成

我知道我已经发布了这个问题的答案,但我已经找到了一个更好的解决方案,所以我想花点时间分享一下。

事实证明,在我之前的回答中,JS解决方案存在一个小问题,直到我有一个朋友测试我的正在进行的应用程序时,这个问题才浮出水面。

问题之前,我将作业步骤定义为Repeater Field 有两个子字段:标题和详细信息。“详细信息”子字段是所见即所得字段,使用户可以对格式进行某种控制。

问题是,tinyMCE使用的JavaScript将textarea 用户友好的WYSIWYG中的输入textarea 加载页面后。这导致了问题,因为我的JS解决方案:

function my_loadJobArchetype() {
    $(\'<div>\').load("mysite.com/edit-archetype/?archetypeId=123" 
        + \' \' + "[data-name=\'my_job_steps\']", function() {

            $("[data-name=\'my_job_steps\']").replaceWith(
                $(this).children("[data-name=\'my_job_steps\']")
            );
    });
}
load() 呼叫当我用从原型加载的内容替换空白的工作内容时,我的用户得到的是一个纯文本框,而不是所见即所得编辑器。

所以,与其看到Quantity, 他们看到:

<p><strong>Quantity</strong></p>
不用说,这不是我想要的。

我跟着jgraup\'并研究了一些ACF插件,但事实证明,我可以用插件已经提供的过滤器来解决这个问题。

我们要用于此的筛选器是:acf/load_value/key=[field_key]. 基本上,这是一个动态过滤器,允许您钩住特定自定义字段的加载过程。

步骤1

Redefine my custom fields (slightly).

最初,作业和作业原型使用相同的字段组:wf_jobStepFields, 但要使此过程正常工作,我需要维护字段的两个副本:

wf\\U jobStepFields在每个字段组中都是唯一的转发器字段:wf_job_stepswf_archetype_steps. 子字段键保持不变(step_titlestep_details)

第2步

Hook into the ACF filter

function my_loadArchetypeValue($value, $post_id, $field) {

}
add_filter(\'acf/load_value/key=wf_job_steps\', \'my_loadArchetypeValue\', 10, 3);
"acf/load_value/key={$field_key}" 是一个灵活的过滤器挂钩,允许我们锁定单个字段的加载过程。在这种情况下,我们将锁定wf_job_steps Repeater Field

步骤3

Override values on the New Job Form

我在前端有一个页面,用户可以访问该页面提交新工作。默认情况下,此页面包含定义了单个作业步骤的空白作业,但使用此挂钩,我们可以使用选定的原型模板覆盖该作业:

 function my_loadArchetypeValue($value, $post_id, $field) {
    // FIRST:    Check to make sure we are on the NEW JOB page.
    if (is_page(\'new-job\')) {

        // Check to see if the "archetypeId" query variable is defined.
        if (get_query_var("archetypeId")) {
            // If it is, grab the VALUE of the ARCHETYPE STEPS for the selected Archetype
            return get_field(\'wf_archetype_steps\',get_query_var("archetypeId"));
        }
    }
}

步骤4

Override values on the Admin screen

虽然我有一个用于添加新作业的前端表单,但我希望确保后端屏幕提供相同的功能,以便也可以从管理区域利用原型。

// First, check to make sure that the get_current_screen() function is defined.
// It is not defined on every admin page, but it is defined on the 
// ADD NEW pages, which is where we want to be.
if (function_exists("get_current_screen")) {
    // Grab the current screen OBJECT and save it
    $screen = get_current_screen();

    // This statement checks to make sure that we are on the 
    // ADD NEW screen for the JOB post type
    if ($screen->action == \'add\' && $screen->post_type == wf-job) {
        $archetypeId = $_GET["archetypeId"];
        /* NOTE: the global WP_Query object has no query vars here,
        /        so we need to get a little "creative to pull the
        /        variable from the URL.

           Technically, $_GET["archetypeId"] will also work on the
           Add Job form as well, but we have access to the WP_Query
           query vars there, and I think that using the WP core whenever
           possible makes WordPress related functions easier to follow
        */

        if ($archetypeId) {
            return get_field(\'wf_archetype_steps\', $archetypeId);
        }
    }
}
最终结果

Put it all together, and the final function looks like this:

function my_loadArchetypeValue($value, $post_id, $field) {
    if (is_page(\'new-job\')) {
        $archetypeId = get_query_var("archetypeId");

        if ($archetypeId) {
            return get_field(\'wf_archetype_steps\',$archetypeId);
        }
    } elseif (function_exists("get_current_screen")) {
        $screen = get_current_screen();

        if ($screen->action == \'add\' && $screen->post_type == wf-job) {
            $archetypeId = $_GET["archetypeId"];
            if ($archetypeId) {
                return get_field(\'wf_archetype_steps\', $archetypeId);
            }
        }
    }

    return $value;
}
add_filter(\'acf/load_value/key=wf_job_steps\', \'my_loadArchetypeValue\', 10, 3);
<小时>NOTE: 通常,我不太喜欢定义第二个字段组。在本例中,这几乎是复制/粘贴代码的教科书定义,因为字段组除了几个键之外,在功能上是相同的。

但是,在这种情况下这样做有很好的理由。

我们钩住的过滤器锁定特定字段的加载事件(由字段的键定义)。在这种情况下,我们将锁定wf\\u job\\u步骤。

如果我继续使用单个字段组,那么这个过滤器挂钩会将进程抛出到infinite loop, 因为每次我的过滤函数get_field() 调用时,将再次触发筛选器。

为中继器字段定义具有唯一键的第二个字段组可以防止无限循环,但由于子字段仍然具有相同的键值,因此允许它们无缝地转移到新作业。

SO网友:jgraup

您可能需要定义自己的ACF Custom Field Type 它保存您的模板。选择模板后,您可以通过编程将字段复制到repeater. Awesome ACF 有很多例子,WordPress有很多plugins 还有一个User Submitted Add-Ons 支持论坛。

SO网友:Mike

我能够通过第二种帖子类型和一点JavaScript实现这一点。

步骤1:分配ACF字段组Job Steps 字段组已定义,因此我稍微修改了设置,并将其分配给作业和作业原型:

// [...] This is a snip from the full custom field setup
\'location\' => array (
    array (
        array (
            \'param\' => \'post_type\',
            \'operator\' => \'==\',
            \'value\' => \'my-job\',
        ),
    ),

    array (
        array (
            \'param\' => \'post_type\',
            \'operator\' => \'==\',
            \'value\' => \'my-job-archetype\',
        ),
    ),
),
现在,我可以用同样的方式访问poth内容类型的作业步骤。

步骤2:注册一个自定义查询变量接下来我做的是为原型post ID添加一个自定义查询变量:

function my_registerArchetypeQueryVar($vars) {
    $vars[] = \'archetypeId;
    return $vars;
}
add_filter(\'query_vars\', \'my_registerArchetypeQueryVar\');
步骤3:前端表单-编辑原型接下来,我创建了一个包含以下内容的编辑原型页面:

if(get_query_var(\'archetypeId\')) {
    $id = get_query_var(\'archetypeId\');

    $jobArchetype = get_post($id);

    if ($jobArchetype) {
        acf_form(array(
            "id" => "editJobForm",
            "post_id" => $id,
            "post_title" => true,
            \'field_groups\' => array(\'my_jobStepFields\'),
            "return" => "%post_url%",
            "submit_value" => __("Update Archetype", \'acf\'),
        ));
    } else {
        acf_form(array(
            "id" => "addJobForm",
            "post_id" => \'new_post\',
            \'new_post\' => array(
                \'post_type\' => \'my-job-archetype\',
                \'post_status\' => \'publish\'
            ),
            "post_title" => true,
            \'field_groups\' => array(\'my_jobStepFields\'),
            "return" => "%post_url%",
            "submit_value" => __("Add Archetype", \'acf\'),
        ));
    }
}
在这一页上,我抓取archetypeId 查询var并使用它为指定职位调出ACF表单。(如果没有archetypeId 如果提供了,我将呈现一个新的原型形式。

步骤4:前端表单-新工作接下来,我创建了一个新工作页面,其中包含以下内容:

$id = get_query_var(\'archetypeId\');
$jobArchetype = get_post($id);


if ($jobArchetype) { ?>
    <script>
        $(document).ready(function() {
            my_loadJobArchetype();
        });

        function my_loadJobArchetype() {
            $(\'<div>\').load("<?php echo get_page_by_path(\'edit-archetype\') 
                . "?archetypeId=" . $jobArchetype->ID; ?>" 
                + \' \' + "[data-name=\'wf_job_steps\']", function() {

                    $("[data-name=\'wf_job_steps\']").replaceWith(
                        $(this).children("[data-name=\'wf_job_steps\']")
                    );
            });
        }
    </script>
<?php }
当“新建作业”页面收到原型ID时,它会加载一个自定义脚本,该脚本基本上用编辑原型表单中作业步骤部分的副本替换了新作业表单中的空白作业步骤部分。

脚本在客户端浏览器中呈现页面时,其外观如下所示:

<script>
    $(document).ready(function() {
        my_loadJobArchetype();
    });

    function my_loadJobArchetype() {
        $(\'<div>\').load("mysite.com/edit-archetype/?archetypeId=123" 
            + \' \' + "[data-name=\'my_job_steps\']", function() {

                $("[data-name=\'my_job_steps\']").replaceWith(
                    $(this).children("[data-name=\'my_job_steps\']")
                );
        });
    }
</script>
下面是正在发生的事情的细目:

$(ducument).ready() 呼叫my_loadJobArchetype() 一旦页面加载完毕。

接下来,我们加载portion 将“编辑原型”页面的<div> 元素具有:

$(\'<div>\').load("mysite.com/edit-archetype/?archetypeId=123" 
    + \' \' + "[data-name=\'my_job_steps\']" // ...
);
我们实际上是在给两个参数传递类似的东西。这个url jQuery的参数load() 函数还可以包含一个jQuery选择器字符串(用空格分隔),该字符串将只加载目标页面的一部分,而不是整个文档。

我检查了编辑原型和新作业页面的源,发现作业步骤字段组包含在<div> 使用属性标记:data-name="my-job-steps" (该属性的值恰好是我为自定义字段组定义的键)。

知道了这一点,我基于该属性构建了一个jQuery选择器:[data-name=\'my_job_steps\'] 我和url 的参数load() 呼叫

然后,在回调函数中,我获取页面的现有作业步骤部分,并将其替换为我从编辑模板页面加载的部分。

function() {
    $("[data-name=\'my_job_steps\']").replaceWith(
        $(this).children("[data-name=\'my_job_steps\']")
    );
}
The$(this) 本例中的元素是新的<div> 我们创建用于存储响应的元素load().

最终的结果是一个功能模板特性。我对现在依靠JavaScript来实现这一点并不满意,但这只是一个开始。

当我知道如何在没有JS的情况下实现这一点时,我一定会与大家分享。