504 lines
21 KiB
PHP
504 lines
21 KiB
PHP
<?php
|
||
/*
|
||
Plugin Name: ACF Fields Viewer by Post Type
|
||
Description: Показывает все ACF поля для типов постов и таксономий
|
||
Version: 2.0
|
||
Author: Your Name
|
||
*/
|
||
|
||
// Добавляем пункт в главное меню админки
|
||
add_action('admin_menu', 'acf_viewer_add_menu');
|
||
|
||
function acf_viewer_add_menu() {
|
||
add_menu_page(
|
||
'ACF Fields Viewer',
|
||
'ACF Viewer',
|
||
'manage_options',
|
||
'acf-fields-viewer',
|
||
'acf_viewer_main_page',
|
||
'dashicons-list-view',
|
||
30
|
||
);
|
||
}
|
||
|
||
function acf_viewer_main_page() {
|
||
if (!current_user_can('manage_options')) {
|
||
wp_die('Недостаточно прав для доступа к этой странице.');
|
||
}
|
||
|
||
// Получаем текущую вкладку
|
||
$current_tab = isset($_GET['tab']) ? sanitize_text_field($_GET['tab']) : 'post_types';
|
||
|
||
?>
|
||
<div class="wrap">
|
||
<h1>ACF Fields Viewer</h1>
|
||
|
||
<!-- Вкладки навигации -->
|
||
<h2 class="nav-tab-wrapper">
|
||
<a href="?page=acf-fields-viewer&tab=post_types" class="nav-tab <?php echo $current_tab === 'post_types' ? 'nav-tab-active' : ''; ?>">
|
||
Типы постов
|
||
</a>
|
||
<a href="?page=acf-fields-viewer&tab=taxonomies" class="nav-tab <?php echo $current_tab === 'taxonomies' ? 'nav-tab-active' : ''; ?>">
|
||
Таксономии
|
||
</a>
|
||
<a href="?page=acf-fields-viewer&tab=options" class="nav-tab <?php echo $current_tab === 'options' ? 'nav-tab-active' : ''; ?>">
|
||
Options Pages
|
||
</a>
|
||
</h2>
|
||
|
||
<div class="tab-content">
|
||
<?php
|
||
if ($current_tab === 'post_types') {
|
||
acf_viewer_show_post_types();
|
||
} elseif ($current_tab === 'taxonomies') {
|
||
acf_viewer_show_taxonomies();
|
||
} elseif ($current_tab === 'options') {
|
||
acf_viewer_show_options_pages();
|
||
}
|
||
?>
|
||
</div>
|
||
|
||
<style>
|
||
.acf-viewer-container {
|
||
background: #fff;
|
||
padding: 20px;
|
||
margin: 20px 0;
|
||
border: 1px solid #ccd0d4;
|
||
border-radius: 4px;
|
||
box-shadow: 0 1px 1px rgba(0,0,0,.04);
|
||
}
|
||
.acf-viewer-container h2 {
|
||
color: #1d2327;
|
||
margin: 0 0 15px 0;
|
||
padding-bottom: 10px;
|
||
border-bottom: 2px solid #2271b1;
|
||
}
|
||
.acf-viewer-info {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
gap: 10px;
|
||
margin-bottom: 20px;
|
||
padding: 15px;
|
||
background: #f6f7f7;
|
||
border-radius: 4px;
|
||
}
|
||
.acf-viewer-info-item {
|
||
padding: 5px 0;
|
||
}
|
||
.acf-viewer-info-item strong {
|
||
color: #2271b1;
|
||
}
|
||
.acf-viewer-table {
|
||
margin-top: 15px;
|
||
}
|
||
.acf-viewer-table pre {
|
||
max-height: 200px;
|
||
overflow: auto;
|
||
background: #f6f7f7;
|
||
padding: 10px;
|
||
margin: 0;
|
||
font-size: 12px;
|
||
line-height: 1.4;
|
||
border-radius: 3px;
|
||
}
|
||
.acf-empty {
|
||
color: #999;
|
||
font-style: italic;
|
||
}
|
||
.post-type-section {
|
||
margin-bottom: 30px;
|
||
padding: 20px;
|
||
background: #fff;
|
||
border: 1px solid #ccd0d4;
|
||
border-radius: 4px;
|
||
}
|
||
.post-type-section > h2 {
|
||
margin-top: 0;
|
||
color: #2271b1;
|
||
font-size: 24px;
|
||
}
|
||
.tab-content {
|
||
margin-top: 20px;
|
||
}
|
||
code.field-key {
|
||
background: #f0f0f1;
|
||
padding: 2px 6px;
|
||
border-radius: 3px;
|
||
font-size: 11px;
|
||
}
|
||
.field-group-box {
|
||
background: #f9f9f9;
|
||
border-left: 4px solid #2271b1;
|
||
padding: 15px;
|
||
margin: 15px 0;
|
||
}
|
||
.field-group-box h3 {
|
||
margin-top: 0;
|
||
color: #2271b1;
|
||
}
|
||
.field-item {
|
||
padding: 10px;
|
||
background: #fff;
|
||
margin: 5px 0;
|
||
border: 1px solid #ddd;
|
||
border-radius: 3px;
|
||
}
|
||
.field-item:hover {
|
||
background: #f0f0f1;
|
||
}
|
||
.badge {
|
||
display: inline-block;
|
||
padding: 3px 8px;
|
||
background: #2271b1;
|
||
color: #fff;
|
||
border-radius: 3px;
|
||
font-size: 11px;
|
||
margin-left: 5px;
|
||
}
|
||
.badge.required {
|
||
background: #d63638;
|
||
}
|
||
.location-rules {
|
||
background: #fff3cd;
|
||
border: 1px solid #ffc107;
|
||
padding: 10px;
|
||
margin: 10px 0;
|
||
border-radius: 3px;
|
||
}
|
||
</style>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
// Функция для отображения типов постов
|
||
function acf_viewer_show_post_types() {
|
||
// Получаем все зарегистрированные типы постов
|
||
$all_post_types = get_post_types(array(), 'objects');
|
||
|
||
if (empty($all_post_types)) {
|
||
echo '<div class="notice notice-warning"><p>Типы постов не найдены.</p></div>';
|
||
return;
|
||
}
|
||
|
||
foreach ($all_post_types as $post_type_slug => $post_type) {
|
||
// Пропускаем служебные типы
|
||
if (in_array($post_type_slug, array('revision', 'nav_menu_item', 'custom_css', 'customize_changeset', 'oembed_cache', 'user_request', 'wp_block', 'wp_template', 'wp_template_part', 'wp_global_styles', 'wp_navigation', 'acf-field-group', 'acf-field'))) {
|
||
continue;
|
||
}
|
||
|
||
echo '<div class="post-type-section">';
|
||
echo '<h2>' . esc_html($post_type->labels->name) . ' <span style="font-weight: normal; font-size: 18px; color: #666;">(' . esc_html($post_type_slug) . ')</span></h2>';
|
||
|
||
// Информация о типе поста
|
||
echo '<div class="acf-viewer-info">';
|
||
echo '<div class="acf-viewer-info-item"><strong>Slug:</strong> ' . esc_html($post_type_slug) . '</div>';
|
||
echo '<div class="acf-viewer-info-item"><strong>Публичный:</strong> ' . ($post_type->public ? 'Да' : 'Нет') . '</div>';
|
||
echo '<div class="acf-viewer-info-item"><strong>Иерархический:</strong> ' . ($post_type->hierarchical ? 'Да' : 'Нет') . '</div>';
|
||
|
||
// Подсчет постов
|
||
$count = wp_count_posts($post_type_slug);
|
||
$total = 0;
|
||
foreach ($count as $status => $number) {
|
||
$total += $number;
|
||
}
|
||
echo '<div class="acf-viewer-info-item"><strong>Всего постов:</strong> ' . $total . '</div>';
|
||
echo '</div>';
|
||
|
||
// Получаем группы полей для этого типа постов
|
||
$field_groups = acf_get_field_groups(array(
|
||
'post_type' => $post_type_slug
|
||
));
|
||
|
||
if (empty($field_groups)) {
|
||
echo '<div class="notice notice-info inline"><p>ACF группы полей не найдены для этого типа постов.</p></div>';
|
||
} else {
|
||
echo '<p><strong>Найдено групп полей:</strong> ' . count($field_groups) . '</p>';
|
||
|
||
foreach ($field_groups as $field_group) {
|
||
echo '<div class="field-group-box">';
|
||
echo '<h3>' . esc_html($field_group['title']) . '</h3>';
|
||
|
||
// Информация о группе
|
||
echo '<div style="margin-bottom: 15px;">';
|
||
echo '<div><strong>Key:</strong> <code>' . esc_html($field_group['key']) . '</code></div>';
|
||
|
||
// Показываем правила размещения
|
||
if (!empty($field_group['location'])) {
|
||
echo '<div class="location-rules">';
|
||
echo '<strong>Правила размещения:</strong><br>';
|
||
foreach ($field_group['location'] as $group_index => $rules) {
|
||
if ($group_index > 0) echo '<em style="color: #666;">или</em><br>';
|
||
foreach ($rules as $rule_index => $rule) {
|
||
if ($rule_index > 0) echo '<em style="color: #666;">и</em> ';
|
||
$operator_text = ($rule['operator'] == '==') ? 'равно' : 'не равно';
|
||
echo esc_html($rule['param']) . ' ' . $operator_text . ' <strong>' . esc_html($rule['value']) . '</strong><br>';
|
||
}
|
||
}
|
||
echo '</div>';
|
||
}
|
||
|
||
if (!empty($field_group['description'])) {
|
||
echo '<div><strong>Описание:</strong> ' . esc_html($field_group['description']) . '</div>';
|
||
}
|
||
echo '</div>';
|
||
|
||
// Получаем поля группы
|
||
$fields = acf_get_fields($field_group['key']);
|
||
|
||
if ($fields) {
|
||
echo '<table class="wp-list-table widefat fixed striped acf-viewer-table">';
|
||
echo '<thead><tr>';
|
||
echo '<th width="25%">Название поля</th>';
|
||
echo '<th width="20%">Ключ (Name)</th>';
|
||
echo '<th width="15%">Тип</th>';
|
||
echo '<th width="40%">Настройки</th>';
|
||
echo '</tr></thead>';
|
||
echo '<tbody>';
|
||
|
||
acf_viewer_display_fields($fields, 0);
|
||
|
||
echo '</tbody></table>';
|
||
} else {
|
||
echo '<p><em>Поля не найдены в этой группе.</em></p>';
|
||
}
|
||
|
||
echo '</div>';
|
||
}
|
||
}
|
||
|
||
echo '</div>';
|
||
}
|
||
}
|
||
|
||
// Рекурсивная функция для отображения полей (включая вложенные)
|
||
function acf_viewer_display_fields($fields, $level = 0) {
|
||
foreach ($fields as $field) {
|
||
$indent = str_repeat('—', $level);
|
||
|
||
echo '<tr>';
|
||
echo '<td>';
|
||
echo $indent . ' <strong>' . esc_html($field['label']) . '</strong>';
|
||
if (!empty($field['required'])) {
|
||
echo '<span class="badge required">обязательное</span>';
|
||
}
|
||
echo '</td>';
|
||
echo '<td><code class="field-key">' . esc_html($field['name']) . '</code></td>';
|
||
echo '<td>' . esc_html($field['type']) . '</td>';
|
||
echo '<td>';
|
||
|
||
// Показываем ключевые настройки в зависимости от типа
|
||
$settings = array();
|
||
|
||
if (!empty($field['instructions'])) {
|
||
$settings[] = '<strong>Инструкции:</strong> ' . esc_html($field['instructions']);
|
||
}
|
||
|
||
if (!empty($field['default_value'])) {
|
||
$settings[] = '<strong>По умолчанию:</strong> ' . esc_html($field['default_value']);
|
||
}
|
||
|
||
// Специфичные настройки для разных типов
|
||
switch ($field['type']) {
|
||
case 'text':
|
||
case 'textarea':
|
||
if (!empty($field['placeholder'])) {
|
||
$settings[] = '<strong>Placeholder:</strong> ' . esc_html($field['placeholder']);
|
||
}
|
||
if (!empty($field['maxlength'])) {
|
||
$settings[] = '<strong>Макс. длина:</strong> ' . esc_html($field['maxlength']);
|
||
}
|
||
break;
|
||
|
||
case 'select':
|
||
case 'checkbox':
|
||
case 'radio':
|
||
if (!empty($field['choices'])) {
|
||
$choices = is_array($field['choices']) ? implode(', ', array_keys($field['choices'])) : $field['choices'];
|
||
$settings[] = '<strong>Варианты:</strong> ' . esc_html($choices);
|
||
}
|
||
break;
|
||
|
||
case 'image':
|
||
case 'file':
|
||
if (!empty($field['return_format'])) {
|
||
$settings[] = '<strong>Формат возврата:</strong> ' . esc_html($field['return_format']);
|
||
}
|
||
if (!empty($field['mime_types'])) {
|
||
$settings[] = '<strong>Типы файлов:</strong> ' . esc_html($field['mime_types']);
|
||
}
|
||
break;
|
||
|
||
case 'post_object':
|
||
case 'relationship':
|
||
if (!empty($field['post_type'])) {
|
||
$pt = is_array($field['post_type']) ? implode(', ', $field['post_type']) : $field['post_type'];
|
||
$settings[] = '<strong>Типы постов:</strong> ' . esc_html($pt);
|
||
}
|
||
break;
|
||
|
||
case 'taxonomy':
|
||
if (!empty($field['taxonomy'])) {
|
||
$settings[] = '<strong>Таксономия:</strong> ' . esc_html($field['taxonomy']);
|
||
}
|
||
break;
|
||
}
|
||
|
||
if (!empty($settings)) {
|
||
echo implode('<br>', $settings);
|
||
} else {
|
||
echo '<em class="acf-empty">—</em>';
|
||
}
|
||
|
||
echo '</td>';
|
||
echo '</tr>';
|
||
|
||
// Рекурсивно обрабатываем вложенные поля (для repeater, group, flexible content)
|
||
if (in_array($field['type'], array('repeater', 'group', 'flexible_content')) && !empty($field['sub_fields'])) {
|
||
acf_viewer_display_fields($field['sub_fields'], $level + 1);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Функция для отображения таксономий
|
||
function acf_viewer_show_taxonomies() {
|
||
// Получаем все таксономии
|
||
$taxonomies = get_taxonomies(array(), 'objects');
|
||
|
||
if (empty($taxonomies)) {
|
||
echo '<div class="notice notice-warning"><p>Таксономии не найдены.</p></div>';
|
||
return;
|
||
}
|
||
|
||
foreach ($taxonomies as $taxonomy_slug => $taxonomy) {
|
||
// Пропускаем служебные таксономии
|
||
if (in_array($taxonomy_slug, array('nav_menu', 'link_category', 'post_format', 'wp_theme', 'wp_template_part_area'))) {
|
||
continue;
|
||
}
|
||
|
||
echo '<div class="post-type-section">';
|
||
echo '<h2>' . esc_html($taxonomy->labels->name) . ' <span style="font-weight: normal; font-size: 18px; color: #666;">(' . esc_html($taxonomy_slug) . ')</span></h2>';
|
||
|
||
// Информация о таксономии
|
||
echo '<div class="acf-viewer-info">';
|
||
echo '<div class="acf-viewer-info-item"><strong>Slug:</strong> ' . esc_html($taxonomy_slug) . '</div>';
|
||
echo '<div class="acf-viewer-info-item"><strong>Публичная:</strong> ' . ($taxonomy->public ? 'Да' : 'Нет') . '</div>';
|
||
echo '<div class="acf-viewer-info-item"><strong>Иерархическая:</strong> ' . ($taxonomy->hierarchical ? 'Да' : 'Нет') . '</div>';
|
||
echo '<div class="acf-viewer-info-item"><strong>Типы постов:</strong> ' . implode(', ', $taxonomy->object_type) . '</div>';
|
||
|
||
// Подсчет терминов
|
||
$terms_count = wp_count_terms(array('taxonomy' => $taxonomy_slug, 'hide_empty' => false));
|
||
echo '<div class="acf-viewer-info-item"><strong>Всего терминов:</strong> ' . (is_wp_error($terms_count) ? 0 : $terms_count) . '</div>';
|
||
echo '</div>';
|
||
|
||
// Получаем группы полей для этой таксономии
|
||
$field_groups = acf_get_field_groups(array(
|
||
'taxonomy' => $taxonomy_slug
|
||
));
|
||
|
||
if (empty($field_groups)) {
|
||
echo '<div class="notice notice-info inline"><p>ACF группы полей не найдены для этой таксономии.</p></div>';
|
||
} else {
|
||
echo '<p><strong>Найдено групп полей:</strong> ' . count($field_groups) . '</p>';
|
||
|
||
foreach ($field_groups as $field_group) {
|
||
echo '<div class="field-group-box">';
|
||
echo '<h3>' . esc_html($field_group['title']) . '</h3>';
|
||
|
||
echo '<div style="margin-bottom: 15px;">';
|
||
echo '<div><strong>Key:</strong> <code>' . esc_html($field_group['key']) . '</code></div>';
|
||
if (!empty($field_group['description'])) {
|
||
echo '<div><strong>Описание:</strong> ' . esc_html($field_group['description']) . '</div>';
|
||
}
|
||
echo '</div>';
|
||
|
||
// Получаем поля группы
|
||
$fields = acf_get_fields($field_group['key']);
|
||
|
||
if ($fields) {
|
||
echo '<table class="wp-list-table widefat fixed striped acf-viewer-table">';
|
||
echo '<thead><tr>';
|
||
echo '<th width="25%">Название поля</th>';
|
||
echo '<th width="20%">Ключ (Name)</th>';
|
||
echo '<th width="15%">Тип</th>';
|
||
echo '<th width="40%">Настройки</th>';
|
||
echo '</tr></thead>';
|
||
echo '<tbody>';
|
||
|
||
acf_viewer_display_fields($fields, 0);
|
||
|
||
echo '</tbody></table>';
|
||
} else {
|
||
echo '<p><em>Поля не найдены в этой группе.</em></p>';
|
||
}
|
||
|
||
echo '</div>';
|
||
}
|
||
}
|
||
|
||
echo '</div>';
|
||
}
|
||
}
|
||
|
||
// Функция для отображения Options Pages
|
||
function acf_viewer_show_options_pages() {
|
||
// Проверяем, есть ли функция acf_get_options_pages
|
||
if (!function_exists('acf_get_options_pages')) {
|
||
echo '<div class="notice notice-info"><p>ACF Options Pages не зарегистрированы или недоступны.</p></div>';
|
||
return;
|
||
}
|
||
|
||
$options_pages = acf_get_options_pages();
|
||
|
||
if (empty($options_pages)) {
|
||
echo '<div class="notice notice-info"><p>ACF Options Pages не найдены.</p></div>';
|
||
return;
|
||
}
|
||
|
||
foreach ($options_pages as $options_page) {
|
||
echo '<div class="post-type-section">';
|
||
echo '<h2>' . esc_html($options_page['page_title']) . '</h2>';
|
||
|
||
echo '<div class="acf-viewer-info">';
|
||
echo '<div class="acf-viewer-info-item"><strong>Menu Slug:</strong> ' . esc_html($options_page['menu_slug']) . '</div>';
|
||
echo '<div class="acf-viewer-info-item"><strong>Post ID:</strong> ' . esc_html($options_page['post_id']) . '</div>';
|
||
echo '</div>';
|
||
|
||
// Получаем группы полей для этой options page
|
||
$field_groups = acf_get_field_groups(array(
|
||
'options_page' => $options_page['menu_slug']
|
||
));
|
||
|
||
if (empty($field_groups)) {
|
||
echo '<div class="notice notice-info inline"><p>ACF группы полей не найдены для этой страницы опций.</p></div>';
|
||
} else {
|
||
echo '<p><strong>Найдено групп полей:</strong> ' . count($field_groups) . '</p>';
|
||
|
||
foreach ($field_groups as $field_group) {
|
||
echo '<div class="field-group-box">';
|
||
echo '<h3>' . esc_html($field_group['title']) . '</h3>';
|
||
|
||
$fields = acf_get_fields($field_group['key']);
|
||
|
||
if ($fields) {
|
||
echo '<table class="wp-list-table widefat fixed striped acf-viewer-table">';
|
||
echo '<thead><tr>';
|
||
echo '<th width="25%">Название поля</th>';
|
||
echo '<th width="20%">Ключ (Name)</th>';
|
||
echo '<th width="15%">Тип</th>';
|
||
echo '<th width="40%">Настройки</th>';
|
||
echo '</tr></thead>';
|
||
echo '<tbody>';
|
||
|
||
acf_viewer_display_fields($fields, 0);
|
||
|
||
echo '</tbody></table>';
|
||
}
|
||
|
||
echo '</div>';
|
||
}
|
||
}
|
||
|
||
echo '</div>';
|
||
}
|
||
}
|