Создание дополнительных Meta Boxes по необходимости
Я хочу, чтобы пользователи могли создавать и удалять дополнительные поля meta box по мере необходимости.
Например, для музыкального подкаста с переменным количеством песен в каждом эпизоде. Пользователь должен иметь возможность нажать кнопку, которая добавит дополнительные поля для ввода каждой песни по мере необходимости.
В идеале это должно быть реализовано без использования плагина, а закодировано в файле functions.php.

Значит, вы имеете в виду что-то вроде этого?
И когда вы нажимаете "Добавить треки", это превращается в:
Если это то, что вам нужно, это реализуется через создание метабокса с простой jQuery-функцией для добавления и удаления полей, а данные сохраняются как массив в одной строке метаданных. Вот решение:
add_action( 'add_meta_boxes', 'dynamic_add_custom_box' );
/* Обрабатываем введенные данные */
add_action( 'save_post', 'dynamic_save_postdata' );
/* Добавляем блок в основную колонку на страницах редактирования постов и страниц */
function dynamic_add_custom_box() {
add_meta_box(
'dynamic_sectionid',
__( 'Мои треки', 'myplugin_textdomain' ),
'dynamic_inner_custom_box',
'post');
}
/* Выводим содержимое блока */
function dynamic_inner_custom_box() {
global $post;
// Используем nonce для верификации
wp_nonce_field( plugin_basename( __FILE__ ), 'dynamicMeta_noncename' );
?>
<div id="meta_inner">
<?php
// Получаем сохраненные метаданные как массив
$songs = get_post_meta($post->ID,'songs',false);
$c = 0;
if ( count( $songs ) > 0 ) {
foreach( $songs as $track ) {
if ( isset( $track['title'] ) || isset( $track['track'] ) ) {
printf( '<p>Название песни <input type="text" name="songs[%1$s][title]" value="%2$s" /> -- Номер трека : <input type="text" name="songs[%1$s][track]" value="%3$s" /><span class="remove">%4$s</span></p>', $c, $track['title'], $track['track'], __( 'Удалить трек' ) );
$c = $c +1;
}
}
}
?>
<span id="here"></span>
<span class="add"><?php _e('Добавить треки'); ?></span>
<script>
var $ =jQuery.noConflict();
$(document).ready(function() {
var count = <?php echo $c; ?>;
$(".add").click(function() {
count = count + 1;
$('#here').append('<p> Название песни <input type="text" name="songs['+count+'][title]" value="" /> -- Номер трека : <input type="text" name="songs['+count+'][track]" value="" /><span class="remove">Удалить трек</span></p>' );
return false;
});
// Метод live() устарел в jQuery версии 1.7 и удален в версии 1.9. Вместо него используйте метод on().
$(".remove").live('click', function() {
$(this).parent().remove();
});
});
</script>
</div><?php
}
/* Сохраняем наши данные при сохранении поста */
function dynamic_save_postdata( $post_id ) {
// Проверяем автосохранение
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
// Проверяем права доступа
if ( !isset( $_POST['dynamicMeta_noncename'] ) )
return;
if ( !wp_verify_nonce( $_POST['dynamicMeta_noncename'], plugin_basename( __FILE__ ) ) )
return;
// Все проверки пройдены - сохраняем данные
$songs = $_POST['songs'];
update_post_meta($post_id,'songs',$songs);
}

Похоже, что при использовании этого кода отображается только "array(0) { } Add Tracks".

Круто, это исправило проблему, но теперь данные, кажется, не сохраняются при обновлении. Или, по крайней мере, они не отображаются как поля под "My Track", ни в "Custom Fields". Однако, если я верну var_dump обратно, он выводит "array(1) { [0]=> array(1) { [1]=> array(2) { ["title"]=> string(4) "test" ["track"]=> string(5) "teste" } } } Add Tracks"

Итак, я попробовал новый код, и теперь он правильно отображает сохраненные данные. Однако теперь я получаю ошибку на любом посте без сохраненных песен: "Invalid argument supplied for foreach()" на строке "foreach($songs as $track ){". Также, когда я удаляю песни из поста, в блоке произвольных полей появляется пустое поле "Song".

Есть идеи? Я готов заплатить кому-то, чтобы эта функциональность заработала, кажется, что осталось не так уж много работы для завершения.

Не совсем уверен, в чем проблема, это не точный код, а пример, и у меня он работает нормально. Попробуйте заменить if (count($songs) > 0){
на if(is_array($songs)){

Спасибо! Сработало отлично. Я смог использовать этот код для создания более динамичных полей, но осталась проблема с созданием пустых мета-ключей. Если я добавляю песню, но не добавляю ссылку на шоу или заметку к шоу, в итоге создаются пустые мета-ключи для них. Или если я удаляю все элементы в группе, пустой мета-ключ все равно остается. Полагаю, это не такая уж большая проблема — иметь пустые ключи в базе данных?

Вот код, кстати, если кому-то интересно, как я его реализовал.
http://www.leschinskidesign.com.php5-10.websitetestlink.com/test/songs-function.txt http://www.leschinskidesign.com.php5-10.websitetestlink.com/test/showlinks-function.txt http://www.leschinskidesign.com.php5-10.websitetestlink.com/test/shownotes-function.txt

@Picard102 и @Bainternet - Я попробовал ваш код, и он работает нормально по одному, но у меня не получается сохранить данные метабоксов, если я добавляю второй, не связанный метабокс. Я изменил nonce-поля и все ID и классы. Не понимаю, что я делаю не так?

@Amanda Мне нужно увидеть ваш код, чтобы понять, в чем проблема.

@Bainternet: http://wordpress.stackexchange.com/questions/23344/why-wont-my-metabox-data-save/

Привет, я планирую добавить такую же функцию для своего пользовательского типа записи, но на этот раз поле для фотографий, при этом фотографии должны загружаться или выбираться из медиатеки. Какой код мне нужно отредактировать? Спасибо.

Метод live() был объявлен устаревшим в jQuery версии 1.7 и удален в версии 1.9. Вместо него используйте метод on().

Это делается через пользовательские поля, НО вам никогда не следует использовать что-либо, что позволяет пользователям добавлять создавать или удалять метабоксы. Такие записи напрямую попадают в базу данных, поэтому вы потенциально можете создать множество проблем для своего сайта, если предоставите пользователям такой уровень контроля. Гораздо безопаснее создать максимальное количество пользовательских полей, которые могут понадобиться, и позволить оставлять некоторые из них пустыми, если они не нужны.
Это также относится к области плагинов. Файл функций специфичен для темы, тогда как плагины предназначены для функций, которые применяются к контенту сайта, особенно если вы хотите, чтобы этот контент был доступен независимо от используемой темы.
Некоторые рекомендации:

НО вам никогда не следует использовать что-либо, что позволяет пользователям добавлять или удалять метабоксы
Почему?

Моя единственная озабоченность в том, что с любым плагином существует вероятность, что его поддержка может прекратиться в будущем. Я чувствую, что скорее всего смогу разобраться, как починить простое добавление в файл functions, чем разобраться, как починить плагин.

Плагины по сути являются функциями, которые находятся вне темы. Вы можете взять плагин, скопировать код в functions.php, и он будет работать. Аналогично, вы можете взять функции из functions.php, добавить необходимый заголовок для плагина, и он будет работать точно так же, как только вы его активируете.
