从 PHP 和 Timber/Twig 中的高级自定义字段中对转发器字段进行排序



我正在尝试使用Twig 1.34的WordPress Timber插件实现对WordPress插件高级自定义字段(ACF)中中继器字段的输出进行排序。下面从 ACF 排序的基本 PHP 示例来自 https://www.advancedcustomfields.com/resources/how-to-sorting-a-repeater-field/在 ACF 论坛中没有关于我的问题的可用答案。

所以我正在尝试将这个函数从示例中转换为 Timber/Twig:

// get repeater field data
$repeater = get_field('repeater');
// vars
$order = array();
// populate order
foreach( $repeater as $i => $row ) {
$order[ $i ] = $row['id'];
}
// multisort
array_multisort( $order, SORT_DESC, $repeater );
// loop through repeater
if( $repeater ): ?>
<ul>
<?php foreach( $repeater as $i => $row ): ?>
<li><?php echo $row['id']; ?>. <?php echo $row['name']; ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>

我在view.twig文件中实现的内容如下。我的 ACF 转发器字段称为时间线,有两个子字段:日期和描述。

{% set repeater = timeline %}
{% for i, row in repeater %}
{{ row.date}}
{{ row.description}}
{% endfor %}

这将输出 ACF 中继器timeline的现有字段(数组) - 两个字段日期和描述 - 以最旧的日期顺序排列,这是默认值,如下所示:

2010年1月

洛鲁姆·伊普苏姆等等等等

2011年7月

Lorum Ipsumblah blah blah Lorum Ipsum

但我想先按最新日期排序。

根据这个答案Twig_Error_Syntax 对于 Timber 中使用 Twig 过滤器的"未知过滤器",我需要创建一个使用Twig_SimpleFilter并对中继器字段数组进行排序的过滤器函数。

我已经对此进行了测试,该答案中的示例rot13过滤器适用于{{ 'test text'|rot13 }}.

但是当尝试对代码使用相同的Twig_SimpleFilter结构按日期对数组进行排序时,即在我的主题functions.php文件中使用它:

add_filter('timber/twig', function($twig) {
$twig->addExtension(new Twig_Extension_StringLoader());
$twig->addFilter(
new Twig_SimpleFilter(
'sort_timeline', 
function($string) {
$repeater = get_field('timeline');
$order = array();
foreach( $repeater as $i => $row ) {
$order[ $i ] = $row['date'];
}
array_multisort( $order, SORT_DESC, $repeater );
}
)
);
return $twig;
});

像这样调用过滤器{% for i, row in repeater|sort_timeline %}在 for 循环中view.twig

{% set repeater = timeline %}
{% for i, row in repeater|sort_timeline %}
{{ row.date}}
{{ row.description}}
{% endfor %}

我得到的只是一个白屏,php日志中没有错误。

FWIW,使用像{% for i, row in repeater|rot13 %}这样的rot13过滤器也显示白屏,所以整体Twig_SimpleFilter有问题。

(顺便说一句,我也意识到我可能需要将 php 日期格式转换为$row['date']才能正确排序,也许使用strtotime,因为它现在只是月份和年份。

在 Twig 中使用过滤器是尝试此操作的正确方法吗?或者是否可以直接在.twig模板中调整和使用array_multisort( $order, SORT_DESC, $repeater );功能?


编辑 4/17/18

@num8er的代码适用于 php5+。php7 运算符似乎是一个问题。

而且,下面的其他函数将对转发器的后端行进行排序;更改值并添加到主题的functions.php文件中。见 https://support.advancedcustomfields.com/forums/topic/sort-repeater-in-back-end-where-data-is-entered/

要获取要排序的行的 MySQLfield_123456789名称,请转到 ACF 导出页面并导出字段组。 https://support.advancedcustomfields.com/forums/topic/how-to-retrieve-a-group-field-key/

add_filter('acf/load_value/name=timeline', 'my_acf_load_value', 10, 3); //repeater name is timeline
function my_acf_load_value( $rows)
{
foreach( $rows as $key => $row ) {
$column_id[ $key ] = $row['field_5967e7639a09b'];
}
array_multisort( $column_id, SORT_DESC, $rows );
return $rows;
}

直接解决您的问题。

试试这个代码:

add_filter('timber/twig', function($twig) {
$twig->addExtension(new Twig_Extension_StringLoader());
$twig->addFilter(
new Twig_SimpleFilter(
'timeline_latest_first', 
function($timeline) {
usort($timeline, function($a, $b) {
if(strtotime($a['date']) === strtotime($b['date'])) return 0;
return strtotime($a['date']) > strtotime($b['date']) ? -1 : 1; 
// or simply (if php 7.x):
// return -1*(strtotime($a['date']) <=> strtotime($b['date']));
});
return $timeline;
}
)
);
return $twig;
});

{% set timeline_sorted = timeline|timeline_latest_first %}
{% for i, row in timeline_sorted %}
{{ row.date}}
{{ row.description}}
{% endfor %}

在 Twig 中,您可以创建自定义过滤器并将其添加到正在运行的 Twig 环境中。这样,您可以创建自己的multisort筛选器:

$multisort_filter = new Twig_Filter('multisort', function ($repeaters) {
$order = array();

foreach( $repeaters as $i => $row ) {
$order[ $i ] = $row['id'];
}
// multisort
array_multisort( $order, SORT_DESC, $repeaters );
return $repeaters;
});

然后将其添加到树枝上:

$twig = new Twig_Environment($loader);
$twig->addFilter($filter);

现在,您可以从模板调用multisort筛选器。

{% for i, row in repeater|multisort %}
{{ row.date}}
{{ row.description}}
{% endfor %}

有关扩展Twig的更多信息可以在他们的文档中找到:https://twig.symfony.com/doc/2.x/advanced.html

最新更新