Files
hantico/wp-content/themes/hantico/inc/acf.php
T

267 lines
7.1 KiB
PHP

<?php
// Отключить табы в редакторе групп полей ACF
add_filter('acf/field_group/disable_field_settings_tabs', '__return_true');
// Просмотры изменяются автоматически, поле в админке доступно только для просмотра.
add_filter('acf/prepare_field/name=viewers', function ($field) {
if (is_admin()) {
$field['disabled'] = 1;
}
return $field;
});
// Страница опций ACF
if (function_exists('acf_add_options_page')) {
acf_add_options_page(array(
'page_title' => 'Общие блоки страниц',
'menu_title' => 'Блоки страниц',
'menu_slug' => 'common-blocks',
'capability' => 'edit_posts',
'position' => 25,
'redirect' => false
));
}
// Большой редактор ACF
new AcfWysiwygHeight();
class AcfWysiwygHeight {
public function __construct() {
add_action(
'acf/render_field_presentation_settings/type=wysiwyg',
[$this, 'add_height_setting']
);
add_filter(
'acf/prepare_field/type=wysiwyg',
[$this, 'prepare_wysiwyg_field']
);
add_action(
'acf/input/admin_head',
[$this, 'print_admin_css']
);
}
public function add_height_setting(array $field): void {
acf_render_field_setting(
$field,
[
'label' => __('Большой редактор', 'lang'),
'name' => 'wpf_wysiwyg_large',
'type' => 'true_false',
'ui' => 1,
]
);
}
public function prepare_wysiwyg_field(array $field): array {
if (empty($field['wpf_wysiwyg_large'])) {
return $field;
}
$field['wrapper']['class'] = trim(
($field['wrapper']['class'] ?? '') . ' wpf-wysiwyg-large'
);
return $field;
}
public function print_admin_css(): void {
?>
<style>
.acf-field.wpf-wysiwyg-large .acf-editor-wrap iframe,
.acf-field.wpf-wysiwyg-large .acf-editor-wrap textarea {
height: 550px !important;
min-height: 550px !important;
}
</style>
<?php
}
}
// Очистка текста при вставке в визуальный редактор ACF
function theme_clean_tinymce_html_on_paste($init) {
$init['paste_preprocess'] = <<<'JS'
function(plugin, args) {
const wrapper = document.createElement('div');
wrapper.innerHTML = args.content;
const allowedTags = new Set([
'p',
'br',
'strong',
'em',
'a',
'blockquote',
'ul',
'ol',
'li',
'h2',
'h3',
'h4',
'h5',
'h6',
'img',
'table',
'thead',
'tbody',
'tfoot',
'tr',
'th',
'td'
]);
function unwrapElement(element) {
const parent = element.parentNode;
if (!parent) return;
while (element.firstChild) {
parent.insertBefore(element.firstChild, element);
}
parent.removeChild(element);
}
function replaceTag(element, newTagName) {
const newElement = document.createElement(newTagName);
while (element.firstChild) {
newElement.appendChild(element.firstChild);
}
element.parentNode.replaceChild(newElement, element);
return newElement;
}
function isBoldStyle(element) {
const style = (element.getAttribute('style') || '').toLowerCase();
return /font-weight\s*:\s*(bold|[6-9]00)/i.test(style);
}
function isItalicStyle(element) {
const style = (element.getAttribute('style') || '').toLowerCase();
return /font-style\s*:\s*italic/i.test(style);
}
function removeUnsafeHref(element) {
const href = element.getAttribute('href');
if (!href) {
element.removeAttribute('href');
return;
}
const cleanHref = href.trim();
if (!/^(https?:|mailto:|tel:|#|\/)/i.test(cleanHref)) {
element.removeAttribute('href');
}
}
function cleanAttributes(element) {
const tagName = element.tagName.toLowerCase();
[...element.attributes].forEach((attr) => {
const attrName = attr.name.toLowerCase();
if (tagName === 'a' && ['href', 'target', 'rel'].includes(attrName)) {
return;
}
if (tagName === 'img' && ['src', 'alt'].includes(attrName)) {
return;
}
if ((tagName === 'td' || tagName === 'th') && ['colspan', 'rowspan'].includes(attrName)) {
return;
}
if (tagName === 'ol' && attrName === 'start') {
return;
}
element.removeAttribute(attr.name);
});
if (tagName === 'a') {
removeUnsafeHref(element);
if (element.getAttribute('target') === '_blank') {
element.setAttribute('rel', 'noopener');
}
}
}
// Удаляем совсем служебные теги Google Docs / Office.
wrapper.querySelectorAll('script, style, meta, link, xml').forEach((element) => {
element.remove();
});
// b → strong.
wrapper.querySelectorAll('b').forEach((element) => {
replaceTag(element, 'strong');
});
// i → em.
wrapper.querySelectorAll('i').forEach((element) => {
replaceTag(element, 'em');
});
// span разворачиваем с сохранением смысла.
wrapper.querySelectorAll('span').forEach((span) => {
const isBold = isBoldStyle(span);
const isItalic = isItalicStyle(span);
if (isBold && isItalic) {
const strong = replaceTag(span, 'strong');
const em = document.createElement('em');
while (strong.firstChild) {
em.appendChild(strong.firstChild);
}
strong.appendChild(em);
return;
}
if (isBold) {
replaceTag(span, 'strong');
return;
}
if (isItalic) {
replaceTag(span, 'em');
return;
}
unwrapElement(span);
});
// В ячейках таблиц p не нужен — оставляем содержимое.
wrapper.querySelectorAll('th, td').forEach((cell) => {
cell.querySelectorAll('p').forEach((paragraph) => {
unwrapElement(paragraph);
});
});
// Удаляем все теги вне белого списка, но оставляем их содержимое.
[...wrapper.querySelectorAll('*')].reverse().forEach((element) => {
const tagName = element.tagName.toLowerCase();
if (!allowedTags.has(tagName)) {
unwrapElement(element);
}
});
// Чистим атрибуты.
wrapper.querySelectorAll('*').forEach((element) => {
cleanAttributes(element);
});
args.content = wrapper.innerHTML;
}
JS;
return $init;
}
add_filter('tiny_mce_before_init', 'theme_clean_tinymce_html_on_paste');
// Обернуть таблицы во wrapper для скролла
function wrap_tables($html) {
if (trim($html) === '' || ! class_exists('DOMDocument')) {
return $html;
}
$old_errors = libxml_use_internal_errors(true);
$dom = new DOMDocument();
$dom->loadHTML(
'<?xml encoding="utf-8" ?><div id="theme-root">' . $html . '</div>',
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
);
$xpath = new DOMXPath($dom);
$tables = $xpath->query('//table');
foreach ($tables as $table) {
$parent = $table->parentNode;
if (
$parent instanceof DOMElement
&& $parent->tagName === 'div'
&& strpos(' ' . $parent->getAttribute('class') . ' ', ' table-wrapper ') !== false
) {
continue;
}
$wrapper = $dom->createElement('div');
$wrapper->setAttribute('class', 'table-wrapper');
$parent->insertBefore($wrapper, $table);
$wrapper->appendChild($table);
}
$root = $dom->getElementById('theme-root');
$output = '';
if ($root) {
foreach ($root->childNodes as $child) {
$output .= $dom->saveHTML($child);
}
}
libxml_clear_errors();
libxml_use_internal_errors($old_errors);
return $output;
}