Я пытаюсь отсортировать вывод поля повторителя из расширенных настраиваемых полей (ACF) плагина WordPress, используя реализацию плагина WordPress Timber Twig 1.34. Базовый пример PHP для сортировки из ACF ниже взят из 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 - дату и описание двух полей - в порядке дат, начиная с самых старых, что является значением по умолчанию, например:
Jan 2010
Lorum Ipsum blah blah blah
Jul 2011
Lorum Ipsum blah blah blah Lorum Ipsum
Но сначала я хочу отсортировать по самой новой дате.
Согласно этому ответу Twig_Error_Syntax для "Неизвестного фильтра" с фильтром Twig в Timber мне нужно создать функцию фильтра, которая использует 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, использование фильтра rot13, такого как {% for i, row in repeater|rot13 %}, также показывает белый экран, так что что-то не так с общим Twig_SimpleFilter.
(Кстати, я также понимаю, что мне может потребоваться преобразовать формат даты php в $row['date'] для правильной сортировки, возможно, используя strtotime, поскольку теперь это просто месяц и год.)
Правильно ли использовать фильтр в Twig? Или можно адаптировать и использовать функцию array_multisort( $order, SORT_DESC, $repeater ); прямо в шаблоне .twig?
Изменить 17.04.18
Код @num8er работает на php5 +. Оператор php7 кажется проблемой.
И эта другая функция, представленная ниже, будет отсортировать внутренние строки ретранслятора; измените значения и добавьте в файл темы functions.php. См. https://support.advancedcustomfields.com/forums/topic/sort-repeater-in-back-end-where-data-is-entered/
Чтобы получить имя MySQL field_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;
}






В 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
Проверьте свою версию Twig, если это версия 1.x, вам может потребоваться Twig_SimpleFilter.
Я использую 1.34; как мне использовать Twig_SimpleFilter? Использование простейшего примера фильтра rot13 на twig.symfony.com/doc/1.x/advanced.html дает мне фатальную ошибку: неперехваченное исключение 'Twig_Error_Syntax' с сообщением 'Неизвестный фильтр rot13
Извините, я думаю, что ошибся там по поводу Twig_SimpleFilter, давно не трогал версию 1.x. Документ, который я опубликовал, относится к версии 2.x, вы можете проверить версию 1.x здесь: twig.symfony.com/doc/1.x/advanced_legacy.html.
Прямое решение на Ваш вопрос.
Попробуйте этот код:
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 %}
Работает! Мне пришлось сменить > на <, чтобы сначала отсортировать самые новые для php5 +. А для php7, насколько я могу судить, usort работает по-другому, и я не понимаю, почему код php7 не работает. stackoverflow.com/questions/44542089/…
@BlueDogRanch, как я знаю, оператор космического корабля возвращает -1; 0; 1, а usort требует, чтобы второй аргумент был функцией или закрытием, которое возвращает это -1; 0; 1. Похоже, что в той ссылке, которую вы добавили в комментарий, пользователь каждый раз возвращает -1 - это неверно. Подумайте о стопке карт, которую вы просто берете и кладете на место. Наконец, вы получите результат, в котором первая карта, которую вы возьмете, снова окажется на вершине стопки)
Не знаю про php7; Я посмотрю еще раз. но он отлично работает для php5 +. Спасибо!
Спасибо, это интересно; Я видел примеры настраиваемых фильтров, но не мог заставить их работать. С вашим фильтром я получаю ошибку «Невозможно создать экземпляр абстрактного класса Twig_Filter». Кажется, это связано с новым способом добавления фильтров с использованием Twig_SimpleFunction, но я не знаю.