Ansico-CPT-pagecontrol/ansico-ln-plugins/ansico-ln-plugins.php

1295 lines
63 KiB
PHP
Raw Normal View History

2026-04-17 20:10:27 +00:00
<?php
/**
* Plugin Name: Ansico Lægenoter plugins
* Plugin URI: https://ansico.dk
* Support URI: https://ansico.dk/Ansico/Ansico-LN-plugins
* Description: Plugins til at forbedre lægenoter.
* Version: 1.0.0
* Requires at least: 6.0
* Tested up to: 6.9.4
* Requires PHP: 7.0
* Author: Andreas Andersen (Ansico)
* Author URI: https://ansico.dk
* Author URI: https://ansico.dk
* License: GPL v3 or later
* License URI: https://www.gnu.org/licenses/gpl-3.0.html
* Text Domain: ansico-ln-plugins
*/
if (!defined('ABSPATH')) {
exit;
}
final class Ansico_LN_Plugins {
const VERSION = '1.0.0';
const OPTION_KEY = 'ansico_ln_plugins_settings';
private static $block_replaced = false;
private static $toc_assets_needed = false;
public function __construct() {
add_action('init', array($this, 'ensure_default_settings'));
add_action('init', array($this, 'register_taxonomiliste_block'));
add_action('pre_get_posts', array($this, 'include_post_types_in_search'));
add_filter('template_include', array($this, 'template_include'));
add_filter('render_block', array($this, 'render_block_content'), 10, 2);
add_filter('the_content', array($this, 'inject_table_of_contents'), 20);
add_filter('the_content', array($this, 'inject_citations_list'), 30);
add_filter('author_link', array($this, 'filter_author_link'), 10, 3);
add_filter('get_the_author_posts_link', array($this, 'filter_author_posts_link'));
add_filter('the_author_posts_link', array($this, 'filter_author_posts_link'));
add_filter('get_the_date', array($this, 'filter_the_date'), 10, 3);
add_action('wp_enqueue_scripts', array($this, 'register_frontend_assets'));
add_action('wp_footer', array($this, 'print_toc_assets'), 30);
add_action('wp_head', array($this, 'print_meta_visibility_css'), 99);
add_action('wp_footer', array($this, 'print_meta_visibility_script'), 99);
add_action('admin_menu', array($this, 'register_settings_page'));
add_action('admin_init', array($this, 'register_settings'));
}
public function ensure_default_settings() {
update_option(self::OPTION_KEY, self::get_settings());
}
public function register_frontend_assets() {
wp_register_style('ansico-ln-frontend', false, array(), self::VERSION);
}
public function print_toc_assets() {
if (!self::$toc_assets_needed) {
return;
}
?>
<style id="ansico-ln-toc-style">
.ansico-ln-toc {
margin: 2.1rem 0 1.6rem;
padding: 0.9rem 1rem;
border: 1px solid rgba(0,0,0,.12);
border-radius: 8px;
display: inline-block;
width: fit-content;
max-width: calc(100% - 10px);
background: rgba(0,0,0,.02);
}
.ansico-ln-toc details { display:block; }
.ansico-ln-toc summary {
cursor: pointer;
font-weight: 700;
list-style: none;
display: flex;
align-items: center;
justify-content: space-between;
gap: .75rem;
}
.ansico-ln-toc summary::-webkit-details-marker { display: none; }
.ansico-ln-toc-summary-text { flex: 1 1 auto; }
.ansico-ln-toc-summary-indicator {
margin-left: auto;
font-size: .9em;
flex: 0 0 auto;
}
.ansico-ln-toc-nav { margin-top: 0.6rem; }
.ansico-ln-toc-list { margin: 0; }
.ansico-ln-toc-list--bullets { padding-left: 1.15rem; list-style: disc; }
.ansico-ln-toc-list--numbered { padding-left: 0; list-style: none; }
.ansico-ln-toc-list li { margin: 0.14rem 0; }
.ansico-ln-toc-list a { text-decoration: none; }
.ansico-ln-toc-list a:hover { text-decoration: underline; }
.ansico-ln-toc-level-2 { font-size: 1rem; }
.ansico-ln-toc-level-3 { font-size: .95rem; }
.ansico-ln-toc-level-4 { font-size: .9rem; }
.ansico-ln-toc-level-5 { font-size: .86rem; }
.ansico-ln-toc-level-6 { font-size: .82rem; }
.ansico-ln-toc-link.is-active { font-weight: 700; text-decoration: underline; }
.ansico-ln-taxonomy-list { list-style: none; padding-left: 0; margin: 0; }
.ansico-ln-taxonomy-list li { margin: .18rem 0; }
.ansico-ln-taxonomy-cloud { line-height: 1.75; }
.ansico-ln-taxonomy-cloud a {
display: inline-block;
margin: 0 .28rem .28rem 0;
text-decoration: none;
padding: .08rem .34rem;
border-radius: 999px;
background: rgba(0,0,0,.05);
}
.ansico-ln-taxonomy-cloud a:hover { background: rgba(0,0,0,.09); }
</style>
<script id="ansico-ln-toc-script">
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('.ansico-ln-toc details').forEach(function (details) {
var summary = details.querySelector('summary');
var indicator = summary ? summary.querySelector('.ansico-ln-toc-summary-indicator') : null;
var sync = function () {
if (indicator) indicator.textContent = details.open ? '' : '+';
};
sync();
details.addEventListener('toggle', sync);
});
var links = Array.prototype.slice.call(document.querySelectorAll('.ansico-ln-toc-link[href^="#"]'));
if (!links.length || !('IntersectionObserver' in window)) return;
var byId = {};
links.forEach(function (link) {
byId[decodeURIComponent(link.getAttribute('href').slice(1))] = link;
});
var observer = new IntersectionObserver(function (entries) {
entries.forEach(function (entry) {
var id = entry.target.getAttribute('id');
var link = byId[id];
if (!link) return;
if (entry.isIntersecting) {
links.forEach(function (item) { item.classList.remove('is-active'); });
link.classList.add('is-active');
}
});
}, { rootMargin: '0px 0px -72% 0px', threshold: [0, 1] });
Object.keys(byId).forEach(function (id) {
var target = document.getElementById(id);
if (target) observer.observe(target);
});
});
</script>
<?php
}
public function register_taxonomiliste_block() {
if (!function_exists('register_block_type')) {
return;
}
$script_handle = 'ansico-ln-taxonomiliste-editor';
wp_register_script(
$script_handle,
plugins_url('blocks/taxonomiliste/editor.js', __FILE__),
array('wp-blocks', 'wp-element', 'wp-block-editor', 'wp-components', 'wp-i18n', 'wp-server-side-render'),
self::VERSION,
true
);
$taxonomies = array();
foreach (self::get_available_taxonomies_for_block() as $taxonomy) {
$taxonomies[] = array(
'slug' => $taxonomy->name,
'label' => $taxonomy->labels->name,
);
}
wp_localize_script($script_handle, 'AnsicoLNTaxonomilisteData', array('taxonomies' => $taxonomies));
register_block_type('ansico-ln/taxonomiliste', array(
'editor_script' => $script_handle,
'render_callback' => array($this, 'render_taxonomiliste_block'),
'attributes' => array(
'taxonomy' => array('type' => 'string', 'default' => ''),
'displayType' => array('type' => 'string', 'default' => 'list'),
'showCount' => array('type' => 'boolean', 'default' => false),
'showAll' => array('type' => 'boolean', 'default' => true),
'limit' => array('type' => 'number', 'default' => 20),
'sortBy' => array('type' => 'string', 'default' => 'alphabetical'),
),
));
}
public function render_taxonomiliste_block($attributes) {
$taxonomy = isset($attributes['taxonomy']) ? sanitize_key($attributes['taxonomy']) : '';
if (!$taxonomy || !taxonomy_exists($taxonomy)) {
return '';
}
$show_count = !empty($attributes['showCount']);
$show_all = !empty($attributes['showAll']);
$limit = !empty($attributes['limit']) ? max(1, absint($attributes['limit'])) : 20;
$sort_by = isset($attributes['sortBy']) && $attributes['sortBy'] === 'count' ? 'count' : 'alphabetical';
$display_type = isset($attributes['displayType']) && $attributes['displayType'] === 'cloud' ? 'cloud' : 'list';
$terms = get_terms(array(
'taxonomy' => $taxonomy,
'hide_empty' => false,
'number' => $show_all ? 0 : $limit,
'orderby' => $sort_by === 'count' ? 'count' : 'name',
'order' => $sort_by === 'count' ? 'DESC' : 'ASC',
));
if (is_wp_error($terms) || empty($terms)) {
return '';
}
ob_start();
if ($display_type === 'cloud') {
echo '<div class="ansico-ln-taxonomy-cloud">';
foreach ($terms as $term) {
$min = 0.92;
$max = 1.4;
$count = max(1, (int) $term->count);
$font_size = $sort_by === 'count'
? min($max, $min + (log($count + 1) * 0.16))
: $min + (($count > 1 ? min(3, log($count + 1)) : 0) * 0.08);
echo '<a href="' . esc_url(get_term_link($term)) . '" style="font-size:' . esc_attr(number_format((float) $font_size, 2, '.', '')) . 'rem;">';
echo esc_html($term->name);
if ($show_count) {
echo ' <span>(' . intval($term->count) . ')</span>';
}
echo '</a> ';
}
echo '</div>';
} else {
echo '<div class="ansico-ln-taxonomy-list-wrap"><ul class="ansico-ln-taxonomy-list">';
foreach ($terms as $term) {
echo '<li><a href="' . esc_url(get_term_link($term)) . '">' . esc_html($term->name) . '</a>';
if ($show_count) {
echo ' <span>(' . intval($term->count) . ')</span>';
}
echo '</li>';
}
echo '</ul></div>';
}
self::$toc_assets_needed = true;
return trim(ob_get_clean());
}
public function include_post_types_in_search($query) {
if (is_admin() || !$query->is_main_query() || !$query->is_search()) {
return;
}
$query->set('post_type', self::get_searchable_post_types());
}
public function template_include($template) {
if (self::is_block_theme_active()) {
return $template;
}
if (is_search()) {
$custom_template = plugin_dir_path(__FILE__) . 'templates/search.php';
if (file_exists($custom_template)) return $custom_template;
}
if (is_post_type_archive() && self::is_enabled_post_type_archive(self::get_current_archive_post_type())) {
$custom_template = plugin_dir_path(__FILE__) . 'templates/archive-post-type.php';
if (file_exists($custom_template)) return $custom_template;
}
if ((is_tax() || is_category() || is_tag()) && self::is_enabled_taxonomy_archive(self::get_current_taxonomy_name())) {
$custom_template = plugin_dir_path(__FILE__) . 'templates/archive-taxonomy.php';
if (file_exists($custom_template)) return $custom_template;
}
return $template;
}
public function render_block_content($block_content, $block) {
if (is_admin() || !self::is_block_theme_active() || empty($block['blockName'])) {
return $block_content;
}
if (in_array($block['blockName'], array('core/post-author', 'core/post-author-name', 'core/post-date'), true)) {
$post_id = 0;
if (!empty($block['attrs']['postId'])) {
$post_id = absint($block['attrs']['postId']);
} elseif (get_the_ID()) {
$post_id = get_the_ID();
}
if ($post_id) {
$post_type = get_post_type($post_id);
if (in_array($block['blockName'], array('core/post-author', 'core/post-author-name'), true) && self::should_hide_author_for_post_type($post_type)) {
return '';
}
if ($block['blockName'] === 'core/post-date' && self::should_hide_date_for_post_type($post_type)) {
return '';
}
}
}
if (!self::should_replace_block_results()) {
self::$block_replaced = false;
return $block_content;
}
if (
(is_post_type_archive() || is_tax() || is_category() || is_tag()) &&
in_array($block['blockName'], array('core/query-title', 'core/archive-title', 'core/term-description'), true)
) {
return '';
}
if (!self::$block_replaced && $block['blockName'] === 'core/post-template') {
self::$block_replaced = true;
return self::get_block_theme_markup();
}
if (self::$block_replaced && in_array($block['blockName'], array('core/query-pagination', 'core/query-no-results'), true)) {
return '';
}
return $block_content;
}
public function print_meta_visibility_css() {
if (is_admin() || !is_singular()) {
return;
}
$post_type = self::get_context_post_type();
if (!$post_type) {
return;
}
$css = '';
if (self::should_hide_author_for_post_type($post_type)) {
$css .= '.author,.byline,.entry-author,.post-author,.wp-block-post-author,.wp-block-post-author-name,[class*="author-meta"],[class*="post-author"],[class*="byline"],[rel="author"],.wp-block-post-author__name,.wp-block-post-author__content{display:none !important;}';
$css .= '.wp-block-post-author:has(a),.wp-block-post-author:has([rel="author"]),.byline:has(a),.entry-meta:has([rel="author"]),[class*="author"]:has(a[href*="/author/"]){display:none !important;}';
$css .= '.meta-separator,.entry-meta .separator,.post-meta .separator,.wp-block-post-date + .separator,.wp-block-post-date + .meta-separator,.wp-block-post-date + span.separator,.wp-block-post-date + span.meta-separator,.wp-block-post-date + p,.wp-block-post-date + .wp-block-post-author::before,.wp-block-post-date + .wp-block-post-author-name::before{display:none !important;}';
}
if (self::should_hide_date_for_post_type($post_type)) {
$css .= '.posted-on,.entry-date,.post-date,.wp-block-post-date,time.entry-date,time.published,[class*="post-date"],[class*="entry-date"]{display:none !important;}';
}
if ($css !== '') {
echo '<style id="ansico-ln-meta-visibility">' . $css . '</style>';
}
}
public function print_meta_visibility_script() {
if (is_admin() || !is_singular()) {
return;
}
$post_type = self::get_context_post_type();
if (!$post_type || !self::should_hide_author_for_post_type($post_type)) {
return;
}
$author_archive = '';
$custom_url = trim((string) self::get_setting('author_custom_url', ''));
$author_id = get_post_field('post_author', get_the_ID());
if ($author_id) {
$author_archive = get_author_posts_url($author_id);
}
?>
<script id="ansico-ln-hide-author-script">
document.addEventListener('DOMContentLoaded', function () {
var selectors = [
'.wp-block-post-author',
'.wp-block-post-author-name',
'.author',
'.byline',
'.entry-author',
'.post-author',
'[class*="author-meta"]',
'[class*="post-author"]',
'[class*="byline"]'
];
selectors.forEach(function (selector) {
document.querySelectorAll(selector).forEach(function (el) {
el.style.display = 'none';
});
});
var possibleLinks = [];
document.querySelectorAll('a').forEach(function (link) {
var href = link.getAttribute('href') || '';
var rel = link.getAttribute('rel') || '';
if (rel.indexOf('author') !== -1) {
possibleLinks.push(link);
return;
}
var authorArchive = "";
var customUrl = "";
if ((authorArchive && href === authorArchive) || (customUrl && href === customUrl) || href.indexOf('/author/') !== -1) {
possibleLinks.push(link);
}
});
possibleLinks.forEach(function (link) {
var el = link;
for (var i = 0; i < 4 && el; i++) {
var cls = (el.className || '').toString();
if (
cls.indexOf('author') !== -1 ||
cls.indexOf('byline') !== -1 ||
cls.indexOf('meta') !== -1 ||
el.matches('span,p,div,li')
) {
el.style.display = 'none';
if (el.previousElementSibling) {
var prev = el.previousElementSibling;
var prevText = (prev.textContent || '').trim();
var prevCls = (prev.className || '').toString();
if (prevText === '•' || prevCls.indexOf('separator') !== -1 || prevCls.indexOf('meta-separator') !== -1) {
prev.style.display = 'none';
}
}
if (el.nextElementSibling) {
var next = el.nextElementSibling;
var nextText = (next.textContent || '').trim();
var nextCls = (next.className || '').toString();
if (nextText === '•' || nextCls.indexOf('separator') !== -1 || nextCls.indexOf('meta-separator') !== -1) {
next.style.display = 'none';
}
}
return;
}
el = el.parentElement;
}
link.style.display = 'none';
});
document.querySelectorAll('.separator, .meta-separator, .wp-block-post-date + p').forEach(function (sep) {
var text = (sep.textContent || '').trim();
if (text === '•') {
var prevVisible = sep.previousElementSibling && getComputedStyle(sep.previousElementSibling).display !== 'none';
var nextVisible = sep.nextElementSibling && getComputedStyle(sep.nextElementSibling).display !== 'none';
if (!prevVisible || !nextVisible || (sep.previousElementSibling && sep.previousElementSibling.classList.contains('wp-block-post-date'))) {
sep.style.display = 'none';
}
}
});
});
</script>
<?php
}
public function register_settings_page() {
add_options_page(__('Ansico LN plugins', 'ansico-ln-plugins'), __('Ansico LN plugins', 'ansico-ln-plugins'), 'manage_options', 'ansico-ln-plugins', array($this, 'render_settings_page'));
}
public function register_settings() {
register_setting('ansico_ln_plugins_settings_group', self::OPTION_KEY, array($this, 'sanitize_settings'));
}
public function sanitize_settings($input) {
$existing = self::get_settings();
$sanitized = $existing;
$sanitized['hidden_post_types'] = array();
$sanitized['archive_post_types'] = array();
$sanitized['archive_taxonomies'] = array();
$sanitized['post_type_order'] = array();
$sanitized['toc_enabled'] = !empty($input['toc_enabled']) ? 1 : 0;
$sanitized['toc_title'] = isset($input['toc_title']) ? sanitize_text_field($input['toc_title']) : 'INDHOLD';
$sanitized['toc_post_types'] = array();
$sanitized['toc_min_headings'] = isset($input['toc_min_headings']) ? max(1, absint($input['toc_min_headings'])) : 3;
$sanitized['toc_list_type'] = (isset($input['toc_list_type']) && $input['toc_list_type'] === 'numbers') ? 'numbers' : 'bullets';
$sanitized['toc_collapsible'] = !empty($input['toc_collapsible']) ? 1 : 0;
$sanitized['toc_scrollspy'] = !empty($input['toc_scrollspy']) ? 1 : 0;
$sanitized['author_link_mode'] = (isset($input['author_link_mode']) && $input['author_link_mode'] === 'custom') ? 'custom' : 'archive';
$sanitized['author_custom_url'] = isset($input['author_custom_url']) ? esc_url_raw($input['author_custom_url']) : '';
$sanitized['hide_author_post_types'] = array();
$sanitized['hide_date_post_types'] = array();
$sanitized['modified_date_post_types'] = array();
$sanitized['citation_post_types'] = array();
foreach (self::get_available_post_types() as $post_type_name => $post_type_object) {
if (!empty($input['hidden_post_types']) && in_array($post_type_name, (array) $input['hidden_post_types'], true)) {
$sanitized['hidden_post_types'][] = $post_type_name;
}
if (!empty($input['archive_post_types']) && in_array($post_type_name, (array) $input['archive_post_types'], true)) {
$sanitized['archive_post_types'][] = $post_type_name;
}
if (!empty($input['toc_post_types']) && in_array($post_type_name, (array) $input['toc_post_types'], true)) {
$sanitized['toc_post_types'][] = $post_type_name;
}
if (!empty($input['hide_author_post_types']) && in_array($post_type_name, (array) $input['hide_author_post_types'], true)) {
$sanitized['hide_author_post_types'][] = $post_type_name;
}
if (!empty($input['hide_date_post_types']) && in_array($post_type_name, (array) $input['hide_date_post_types'], true)) {
$sanitized['hide_date_post_types'][] = $post_type_name;
}
if (!empty($input['modified_date_post_types']) && in_array($post_type_name, (array) $input['modified_date_post_types'], true)) {
$sanitized['modified_date_post_types'][] = $post_type_name;
}
if (!empty($input['citation_post_types']) && in_array($post_type_name, (array) $input['citation_post_types'], true)) {
$sanitized['citation_post_types'][] = $post_type_name;
}
$order = isset($input['post_type_order'][$post_type_name]) ? absint($input['post_type_order'][$post_type_name]) : 9999;
$sanitized['post_type_order'][$post_type_name] = $order;
}
foreach (self::get_available_taxonomies_for_settings() as $taxonomy_name => $taxonomy_object) {
if (!empty($input['archive_taxonomies']) && in_array($taxonomy_name, (array) $input['archive_taxonomies'], true)) {
$sanitized['archive_taxonomies'][] = $taxonomy_name;
}
}
return $sanitized;
}
public function render_settings_page() {
if (!current_user_can('manage_options')) return;
$settings = self::get_settings();
$post_types = self::get_ordered_available_post_types();
$taxonomies = self::get_available_taxonomies_for_settings();
?>
<div class="wrap">
<h1><?php echo esc_html__('Ansico LN plugins', 'ansico-ln-plugins'); ?></h1>
<form method="post" action="options.php">
<?php settings_fields('ansico_ln_plugins_settings_group'); ?>
<h2><?php echo esc_html__('Custom post types', 'ansico-ln-plugins'); ?></h2>
<table class="widefat striped" id="ansico-ln-post-types-table">
<thead><tr>
<th><?php echo esc_html__('Rækkefølge', 'ansico-ln-plugins'); ?></th>
<th><?php echo esc_html__('Post type', 'ansico-ln-plugins'); ?></th>
<th><?php echo esc_html__('Skjul i søgning', 'ansico-ln-plugins'); ?></th>
<th><?php echo esc_html__('Alfabetisk arkivside', 'ansico-ln-plugins'); ?></th>
<th><?php echo esc_html__('Skjul forfatter', 'ansico-ln-plugins'); ?></th>
<th><?php echo esc_html__('Skjul dato', 'ansico-ln-plugins'); ?></th>
<th><?php echo esc_html__('Brug opdateringsdato', 'ansico-ln-plugins'); ?></th>
<th><?php echo esc_html__('Indsæt citater', 'ansico-ln-plugins'); ?></th>
</tr></thead>
<tbody>
<?php $row_index = 1; foreach ($post_types as $post_type_name => $post_type_object) : ?>
<tr>
<td>
<button type="button" class="button ansico-ln-move-up" aria-label="Flyt op"></button>
<button type="button" class="button ansico-ln-move-down" aria-label="Flyt ned"></button>
<input type="hidden" name="<?php echo esc_attr(self::OPTION_KEY); ?>[post_type_order][<?php echo esc_attr($post_type_name); ?>]" value="<?php echo esc_attr($row_index); ?>" class="ansico-ln-order-input" />
</td>
<td><strong><?php echo esc_html($post_type_object->labels->name); ?></strong><br><code><?php echo esc_html($post_type_name); ?></code></td>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[hidden_post_types][]" value="<?php echo esc_attr($post_type_name); ?>" <?php checked(in_array($post_type_name, $settings['hidden_post_types'], true)); ?>> <?php echo esc_html__('Skjul', 'ansico-ln-plugins'); ?></label></td>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[archive_post_types][]" value="<?php echo esc_attr($post_type_name); ?>" <?php checked(in_array($post_type_name, $settings['archive_post_types'], true)); ?>> <?php echo esc_html__('Aktiver', 'ansico-ln-plugins'); ?></label></td>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[hide_author_post_types][]" value="<?php echo esc_attr($post_type_name); ?>" <?php checked(in_array($post_type_name, $settings['hide_author_post_types'], true)); ?>> <?php echo esc_html__('Skjul', 'ansico-ln-plugins'); ?></label></td>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[hide_date_post_types][]" value="<?php echo esc_attr($post_type_name); ?>" <?php checked(in_array($post_type_name, $settings['hide_date_post_types'], true)); ?>> <?php echo esc_html__('Skjul', 'ansico-ln-plugins'); ?></label></td>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[modified_date_post_types][]" value="<?php echo esc_attr($post_type_name); ?>" <?php checked(in_array($post_type_name, $settings['modified_date_post_types'], true)); ?>> <?php echo esc_html__('Vis opdateret', 'ansico-ln-plugins'); ?></label></td>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[citation_post_types][]" value="<?php echo esc_attr($post_type_name); ?>" <?php checked(in_array($post_type_name, $settings['citation_post_types'], true)); ?>> <?php echo esc_html__('Aktiver', 'ansico-ln-plugins'); ?></label></td>
</tr>
<?php $row_index++; endforeach; ?>
</tbody>
</table>
<h2 style="margin-top:2rem;"><?php echo esc_html__('Forfatter og dato', 'ansico-ln-plugins'); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><?php echo esc_html__('Link på forfatternavn', 'ansico-ln-plugins'); ?></th>
<td>
<fieldset>
<label style="display:block;margin:.2rem 0;">
<input type="radio" name="<?php echo esc_attr(self::OPTION_KEY); ?>[author_link_mode]" value="archive" <?php checked($settings['author_link_mode'], 'archive'); ?>>
<?php echo esc_html__('Link til forfatterarkiv', 'ansico-ln-plugins'); ?>
</label>
<label style="display:block;margin:.2rem 0;">
<input type="radio" name="<?php echo esc_attr(self::OPTION_KEY); ?>[author_link_mode]" value="custom" <?php checked($settings['author_link_mode'], 'custom'); ?>>
<?php echo esc_html__('Link til bestemt side', 'ansico-ln-plugins'); ?>
</label>
<p style="margin:.5rem 0 0;">
<input type="url" class="regular-text" name="<?php echo esc_attr(self::OPTION_KEY); ?>[author_custom_url]" value="<?php echo esc_attr($settings['author_custom_url']); ?>" placeholder="https://example.com/forfattere/">
</p>
</fieldset>
</td>
</tr>
</table>
<h2 style="margin-top:2rem;"><?php echo esc_html__('Taxonomier', 'ansico-ln-plugins'); ?></h2>
<table class="widefat striped">
<thead><tr><th><?php echo esc_html__('Taxonomi', 'ansico-ln-plugins'); ?></th><th><?php echo esc_html__('Alfabetisk arkivside', 'ansico-ln-plugins'); ?></th></tr></thead>
<tbody>
<?php foreach ($taxonomies as $taxonomy_name => $taxonomy_object) : ?>
<tr>
<td><strong><?php echo esc_html($taxonomy_object->labels->name); ?></strong><br><code><?php echo esc_html($taxonomy_name); ?></code></td>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[archive_taxonomies][]" value="<?php echo esc_attr($taxonomy_name); ?>" <?php checked(in_array($taxonomy_name, $settings['archive_taxonomies'], true)); ?>> <?php echo esc_html__('Aktiver', 'ansico-ln-plugins'); ?></label></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h2 style="margin-top:2rem;"><?php echo esc_html__('Indholdsfortegnelse', 'ansico-ln-plugins'); ?></h2>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><?php echo esc_html__('Aktivér automatisk indholdsfortegnelse', 'ansico-ln-plugins'); ?></th>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[toc_enabled]" value="1" <?php checked(!empty($settings['toc_enabled'])); ?>> <?php echo esc_html__('Aktiver', 'ansico-ln-plugins'); ?></label></td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Overskrift', 'ansico-ln-plugins'); ?></th>
<td><input type="text" class="regular-text" name="<?php echo esc_attr(self::OPTION_KEY); ?>[toc_title]" value="<?php echo esc_attr($settings['toc_title']); ?>"></td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Liste-type', 'ansico-ln-plugins'); ?></th>
<td>
<select name="<?php echo esc_attr(self::OPTION_KEY); ?>[toc_list_type]">
<option value="bullets" <?php selected($settings['toc_list_type'], 'bullets'); ?>><?php echo esc_html__('Punktopstilling', 'ansico-ln-plugins'); ?></option>
<option value="numbers" <?php selected($settings['toc_list_type'], 'numbers'); ?>><?php echo esc_html__('Talnummereret', 'ansico-ln-plugins'); ?></option>
</select>
</td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Mindste antal overskrifter', 'ansico-ln-plugins'); ?></th>
<td><input type="number" min="1" name="<?php echo esc_attr(self::OPTION_KEY); ?>[toc_min_headings]" value="<?php echo esc_attr($settings['toc_min_headings']); ?>"></td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Gælder for post types', 'ansico-ln-plugins'); ?></th>
<td>
<?php foreach ($post_types as $post_type_name => $post_type_object) : ?>
<label style="display:block;margin:.2rem 0;"><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[toc_post_types][]" value="<?php echo esc_attr($post_type_name); ?>" <?php checked(in_array($post_type_name, $settings['toc_post_types'], true)); ?>> <?php echo esc_html($post_type_object->labels->name); ?></label>
<?php endforeach; ?>
</td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Foldbar indholdsfortegnelse', 'ansico-ln-plugins'); ?></th>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[toc_collapsible]" value="1" <?php checked(!empty($settings['toc_collapsible'])); ?>> <?php echo esc_html__('Aktiver fold ud/fold sammen', 'ansico-ln-plugins'); ?></label></td>
</tr>
<tr>
<th scope="row"><?php echo esc_html__('Markér aktiv sektion under scroll', 'ansico-ln-plugins'); ?></th>
<td><label><input type="checkbox" name="<?php echo esc_attr(self::OPTION_KEY); ?>[toc_scrollspy]" value="1" <?php checked(!empty($settings['toc_scrollspy'])); ?>> <?php echo esc_html__('Aktiver scrollspy', 'ansico-ln-plugins'); ?></label></td>
</tr>
</table>
<?php submit_button(); ?>
</form>
</div>
<script>
document.addEventListener('DOMContentLoaded', function () {
const table = document.getElementById('ansico-ln-post-types-table');
if (!table) return;
const updateOrder = function () {
table.querySelectorAll('tbody tr').forEach(function (row, index) {
const input = row.querySelector('.ansico-ln-order-input');
if (input) input.value = index + 1;
});
};
table.addEventListener('click', function (event) {
if (event.target.classList.contains('ansico-ln-move-up')) {
const row = event.target.closest('tr');
if (row && row.previousElementSibling) {
row.parentNode.insertBefore(row, row.previousElementSibling);
updateOrder();
}
}
if (event.target.classList.contains('ansico-ln-move-down')) {
const row = event.target.closest('tr');
if (row && row.nextElementSibling) {
row.parentNode.insertBefore(row.nextElementSibling, row);
updateOrder();
}
}
});
updateOrder();
});
</script>
<?php
}
public function inject_table_of_contents($content) {
if (is_admin() || !is_singular() || !in_the_loop() || !is_main_query()) {
return $content;
}
$settings = self::get_settings();
if (empty($settings['toc_enabled'])) {
return $content;
}
$post = get_post();
if (!$post || !in_array($post->post_type, $settings['toc_post_types'], true)) {
return $content;
}
$headings = self::extract_headings($content);
if (count($headings) < (int) $settings['toc_min_headings']) {
return $content;
}
$content_with_ids = self::add_heading_ids($content, $headings);
$toc_markup = self::build_toc_markup($headings, $settings);
if (!$toc_markup) {
return $content;
}
self::$toc_assets_needed = true;
$first_id = $headings[0]['id'];
$pattern = '/(<h[2-6][^>]*id="' . preg_quote($first_id, '/') . '"[^>]*>)/i';
return preg_replace($pattern, $toc_markup . '$1', $content_with_ids, 1);
}
public static function extract_headings($content) {
$headings = array();
if (!preg_match_all('/<h([2-6])([^>]*)>(.*?)<\/h\1>/is', $content, $matches, PREG_SET_ORDER)) {
return $headings;
}
$used_ids = array();
foreach ($matches as $index => $match) {
$level = (int) $match[1];
$text = trim(wp_strip_all_tags($match[3]));
if ($text === '') continue;
$base_id = sanitize_title($text);
if ($base_id === '') $base_id = 'overskrift-' . ($index + 1);
$id = $base_id;
$suffix = 2;
while (isset($used_ids[$id])) {
$id = $base_id . '-' . $suffix;
$suffix++;
}
$used_ids[$id] = true;
$headings[] = array('level' => $level, 'text' => $text, 'id' => $id);
}
return $headings;
}
public static function add_heading_ids($content, $headings) {
$i = 0;
return preg_replace_callback('/<h([2-6])([^>]*)>(.*?)<\/h\1>/is', function ($match) use ($headings, &$i) {
if (!isset($headings[$i])) return $match[0];
$heading = $headings[$i];
$attrs = $match[2];
if (preg_match('/\sid=("|\")(.*?)(\1)/i', $attrs)) {
$i++;
return $match[0];
}
$i++;
return '<h' . $match[1] . $attrs . ' id="' . esc_attr($heading['id']) . '">' . $match[3] . '</h' . $match[1] . '>';
}, $content);
}
public static function build_toc_markup($headings, $settings) {
if (empty($headings)) return '';
$title = !empty($settings['toc_title']) ? $settings['toc_title'] : 'INDHOLD';
$is_numbered = isset($settings['toc_list_type']) && $settings['toc_list_type'] === 'numbers';
$collapsible = !empty($settings['toc_collapsible']);
$scrollspy = !empty($settings['toc_scrollspy']);
$items = array();
$counters = array(2 => 0, 3 => 0, 4 => 0, 5 => 0, 6 => 0);
foreach ($headings as $heading) {
$level = (int) $heading['level'];
$counters[$level]++;
for ($reset = $level + 1; $reset <= 6; $reset++) {
$counters[$reset] = 0;
}
$number = '';
if ($is_numbered) {
$parts = array();
for ($l = 2; $l <= $level; $l++) {
if ($counters[$l] > 0) $parts[] = $counters[$l];
}
$number = implode('.', $parts);
}
$items[] = array_merge($heading, array('number' => $number));
}
ob_start();
echo '<nav class="ansico-ln-toc" aria-label="Indholdsfortegnelse">';
if ($collapsible) {
echo '<details open><summary><span class="ansico-ln-toc-summary-text">' . esc_html($title) . '</span><span class="ansico-ln-toc-summary-indicator" aria-hidden="true"></span></summary><div class="ansico-ln-toc-nav">';
} else {
echo '<div class="ansico-ln-toc-title" style="font-weight:700;">' . esc_html($title) . '</div><div class="ansico-ln-toc-nav">';
}
echo $is_numbered ? '<ol class="ansico-ln-toc-list ansico-ln-toc-list--numbered">' : '<ul class="ansico-ln-toc-list ansico-ln-toc-list--bullets">';
foreach ($items as $item) {
$level = (int) $item['level'];
$indent = max(0, $level - 2) * 1.1;
echo '<li class="ansico-ln-toc-level-' . intval($level) . '" style="margin-left:' . esc_attr(number_format((float) $indent, 2, '.', '')) . 'rem;">';
echo '<a class="ansico-ln-toc-link' . ($scrollspy ? ' ansico-ln-toc-link--spy' : '') . '" href="#' . esc_attr($item['id']) . '">';
if ($is_numbered && $item['number'] !== '') {
echo '<span class="ansico-ln-toc-number">' . esc_html($item['number']) . '</span> ';
}
echo esc_html($item['text']) . '</a></li>';
}
echo $is_numbered ? '</ol>' : '</ul>';
echo '</div>';
if ($collapsible) echo '</details>';
echo '</nav>';
return trim(ob_get_clean());
}
public function inject_citations_list($content) {
if (is_admin() || !is_singular() || !in_the_loop() || !is_main_query()) {
return $content;
}
$post = get_post();
if (!$post || !self::should_insert_citations_for_post_type($post->post_type)) {
return $content;
}
$sources = self::extract_external_sources_from_content($content);
if (empty($sources)) {
return $content;
}
$items = array();
foreach ($sources as $source) {
$items[] = '<a href="' . esc_url($source['url']) . '" target="_blank" rel="noopener noreferrer">' . esc_html($source['label']) . '</a>';
}
$markup = '<div class="ansico-ln-citations" style="margin-top:1.5rem;">';
$markup .= '<strong>' . esc_html__('Citerede kilder:', 'ansico-ln-plugins') . '</strong> ';
$markup .= implode(', ', $items) . '.';
$markup .= '</div>';
return $content . $markup;
}
public static function extract_external_sources_from_content($content) {
$sources = array();
$home_host = wp_parse_url(home_url(), PHP_URL_HOST);
$home_host = $home_host ? preg_replace('/^www\./i', '', strtolower($home_host)) : '';
if (trim($content) === '') {
return $sources;
}
if (!class_exists('DOMDocument')) {
if (preg_match_all('/<a[^>]+href=["\']([^"\']+)["\'][^>]*>/i', $content, $matches)) {
foreach ($matches[1] as $href) {
$parsed = self::normalize_external_source($href, $home_host);
if ($parsed && !empty($parsed['url'])) {
$sources[$parsed['url']] = $parsed;
}
}
}
return array_values($sources);
}
$internal_errors = libxml_use_internal_errors(true);
$doc = new DOMDocument();
$html = '<?xml encoding="utf-8" ?><div>' . $content . '</div>';
if ($doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)) {
foreach ($doc->getElementsByTagName('a') as $link) {
$href = $link->getAttribute('href');
$parsed = self::normalize_external_source($href, $home_host);
if ($parsed && !empty($parsed['url'])) {
$sources[$parsed['url']] = $parsed;
}
}
}
libxml_clear_errors();
libxml_use_internal_errors($internal_errors);
return array_values($sources);
}
public static function normalize_external_source($url, $home_host = '') {
$url = trim((string) $url);
if ($url === '' || strpos($url, '#') === 0) {
return null;
}
if (preg_match('/^(mailto:|tel:|javascript:)/i', $url)) {
return null;
}
if (strpos($url, '//') === 0) {
$url = is_ssl() ? 'https:' . $url : 'http:' . $url;
}
if (!preg_match('#^https?://#i', $url)) {
return null;
}
$host = wp_parse_url($url, PHP_URL_HOST);
if (!$host) {
return null;
}
$normalized_host = preg_replace('/^www\./i', '', strtolower($host));
if ($home_host && $normalized_host === $home_host) {
return null;
}
return array(
'url' => esc_url_raw($url),
'label' => $normalized_host,
);
}
public function filter_author_link($link, $author_id, $author_nicename) {
if (is_admin()) {
return $link;
}
$settings = self::get_settings();
if (($settings['author_link_mode'] ?? 'archive') === 'custom' && !empty($settings['author_custom_url'])) {
return esc_url($settings['author_custom_url']);
}
return $link;
}
public function filter_author_posts_link($link_html) {
if (is_admin()) {
return $link_html;
}
$post_type = self::get_context_post_type();
if ($post_type && self::should_hide_author_for_post_type($post_type)) {
return '';
}
return $link_html;
}
public function filter_the_date($the_date, $format, $post) {
if (is_admin()) {
return $the_date;
}
$post_obj = $post ? get_post($post) : get_post();
if (!$post_obj) {
return $the_date;
}
if (self::should_hide_date_for_post_type($post_obj->post_type)) {
return '';
}
if (self::should_use_modified_date_for_post_type($post_obj->post_type)) {
$format = $format ? $format : get_option('date_format');
return get_the_modified_date($format, $post_obj);
}
return $the_date;
}
public static function get_context_post_type() {
$post = get_post();
if ($post && !empty($post->post_type)) {
return $post->post_type;
}
if (is_singular()) {
$queried = get_queried_object();
if ($queried && !empty($queried->post_type)) {
return $queried->post_type;
}
}
return '';
}
public static function should_hide_author_for_post_type($post_type) {
$settings = self::get_settings();
return !empty($post_type) && in_array($post_type, (array) $settings['hide_author_post_types'], true);
}
public static function should_hide_date_for_post_type($post_type) {
$settings = self::get_settings();
return !empty($post_type) && in_array($post_type, (array) $settings['hide_date_post_types'], true);
}
public static function should_use_modified_date_for_post_type($post_type) {
$settings = self::get_settings();
return !empty($post_type) && in_array($post_type, (array) $settings['modified_date_post_types'], true);
}
public static function should_insert_citations_for_post_type($post_type) {
$settings = self::get_settings();
return !empty($post_type) && in_array($post_type, (array) $settings['citation_post_types'], true);
}
public static function get_settings() {
$saved = get_option(self::OPTION_KEY, array());
$defaults = array(
'post_type_order' => array(),
'hidden_post_types' => array(),
'archive_post_types' => array(),
'archive_taxonomies' => array(),
'toc_enabled' => 0,
'toc_title' => 'INDHOLD',
'toc_post_types' => array('post', 'page'),
'toc_min_headings' => 3,
'toc_list_type' => 'bullets',
'toc_collapsible' => 1,
'toc_scrollspy' => 1,
'author_link_mode' => 'archive',
'author_custom_url' => '',
'hide_author_post_types' => array(),
'hide_date_post_types' => array(),
'modified_date_post_types'=> array(),
'citation_post_types' => array(),
);
$settings = wp_parse_args(is_array($saved) ? $saved : array(), $defaults);
foreach (self::get_available_post_types() as $post_type_name => $object) {
if (!isset($settings['post_type_order'][$post_type_name])) {
$settings['post_type_order'][$post_type_name] = count($settings['post_type_order']) + 1;
}
}
return $settings;
}
public static function get_available_post_types() {
$post_types = get_post_types(array('public' => true), 'objects');
foreach ($post_types as $name => $obj) {
if ($name === 'attachment' || (!$obj->publicly_queryable && !$obj->show_ui)) {
unset($post_types[$name]);
}
}
return $post_types;
}
public static function get_ordered_available_post_types() {
$post_types = self::get_available_post_types();
$settings = self::get_settings();
uasort($post_types, function ($a, $b) use ($settings) {
$order_a = isset($settings['post_type_order'][$a->name]) ? (int) $settings['post_type_order'][$a->name] : 9999;
$order_b = isset($settings['post_type_order'][$b->name]) ? (int) $settings['post_type_order'][$b->name] : 9999;
if ($order_a === $order_b) return strnatcasecmp($a->labels->name, $b->labels->name);
return $order_a - $order_b;
});
return $post_types;
}
public static function get_available_taxonomies_for_settings() {
$taxonomies = get_taxonomies(array('public' => true), 'objects');
foreach ($taxonomies as $taxonomy_name => $taxonomy_object) {
if (in_array($taxonomy_name, array('post_format', 'nav_menu', 'link_category'), true)) {
unset($taxonomies[$taxonomy_name]);
}
}
uasort($taxonomies, function ($a, $b) { return strnatcasecmp($a->labels->name, $b->labels->name); });
return $taxonomies;
}
public static function get_available_taxonomies_for_block() {
return self::get_available_taxonomies_for_settings();
}
public static function get_searchable_post_types() {
$settings = self::get_settings();
$post_types = self::get_ordered_available_post_types();
$searchable = array();
foreach ($post_types as $post_type_name => $obj) {
if (in_array($post_type_name, $settings['hidden_post_types'], true)) continue;
if (!empty($obj->exclude_from_search)) continue;
$searchable[] = $post_type_name;
}
return $searchable;
}
public static function get_grouped_search_results() {
$search_term = get_search_query();
$grouped_results = array();
$ordered_post_types = self::get_ordered_available_post_types();
$selected_post_types = self::get_searchable_post_types();
if (empty($selected_post_types) || $search_term === '') return array();
foreach ($ordered_post_types as $post_type_name => $post_type_object) {
if (in_array($post_type_name, $selected_post_types, true)) {
$grouped_results[$post_type_name] = array('label' => $post_type_object->labels->name, 'results' => array());
}
}
$search_query = new WP_Query(array(
'post_type' => $selected_post_types,
'post_status' => 'publish',
's' => $search_term,
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
));
foreach ($search_query->posts as $post) {
if (isset($grouped_results[$post->post_type])) {
$grouped_results[$post->post_type]['results'][] = array('title' => get_the_title($post), 'url' => get_permalink($post));
}
}
wp_reset_postdata();
foreach ($grouped_results as $post_type_name => $group) {
if (empty($group['results'])) unset($grouped_results[$post_type_name]);
}
return $grouped_results;
}
public static function get_total_results_count($grouped_results = null) {
if (!is_array($grouped_results)) $grouped_results = self::get_grouped_search_results();
$total = 0; foreach ($grouped_results as $group) $total += count($group['results']);
return $total;
}
public static function get_total_results_text($total_results) {
return ((int) $total_results === 1) ? 'Fandt i alt 1 resultat.' : sprintf('Fandt i alt %d resultater.', (int) $total_results);
}
public static function render_group_results_list($results) {
if (empty($results)) return '';
$visible_results = array_slice($results, 0, 10);
$hidden_results = array_slice($results, 10);
ob_start();
echo '<ul>';
foreach ($visible_results as $result) echo '<li><a href="' . esc_url($result['url']) . '">' . esc_html($result['title']) . '</a></li>';
echo '</ul>';
if (!empty($hidden_results)) {
echo '<details class="ansico-ln-more-results"><summary>' . esc_html(sprintf('Vis alle %d resultater', count($results))) . '</summary><ul>';
foreach ($hidden_results as $result) echo '<li><a href="' . esc_url($result['url']) . '">' . esc_html($result['title']) . '</a></li>';
echo '</ul></details>';
}
return trim(ob_get_clean());
}
public static function render_simple_results_list($results) {
if (empty($results)) return '';
ob_start();
echo '<ul>';
foreach ($results as $result) echo '<li><a href="' . esc_url($result['url']) . '">' . esc_html($result['title']) . '</a></li>';
echo '</ul>';
return trim(ob_get_clean());
}
public static function get_current_archive_post_type() {
return is_post_type_archive() ? get_query_var('post_type') : '';
}
public static function get_current_taxonomy_name() {
if (is_tax() || is_category() || is_tag()) {
$term = get_queried_object();
if ($term && !empty($term->taxonomy)) return $term->taxonomy;
}
return '';
}
public static function is_enabled_post_type_archive($post_type) {
$settings = self::get_settings();
return !empty($post_type) && in_array($post_type, $settings['archive_post_types'], true);
}
public static function is_enabled_taxonomy_archive($taxonomy) {
$settings = self::get_settings();
return !empty($taxonomy) && in_array($taxonomy, $settings['archive_taxonomies'], true);
}
public static function get_post_type_label($post_type) {
$object = get_post_type_object($post_type);
return $object && !empty($object->labels->name) ? $object->labels->name : $post_type;
}
public static function get_archive_results($post_type) {
if (empty($post_type)) return array();
$query = new WP_Query(array('post_type' => $post_type, 'post_status' => 'publish', 'posts_per_page' => -1, 'orderby' => 'title', 'order' => 'ASC', 'ignore_sticky_posts' => true, 'no_found_rows' => true));
$results = array();
foreach ($query->posts as $post) $results[] = array('title' => get_the_title($post), 'url' => get_permalink($post));
wp_reset_postdata();
return $results;
}
public static function group_archive_results_by_letter($results) {
$alphabet = array_merge(array('#'), range('A', 'Z'), array('Æ', 'Ø', 'Å'));
$grouped = array();
foreach ($alphabet as $letter) $grouped[$letter] = array();
foreach ($results as $result) {
$title = isset($result['title']) ? $result['title'] : '';
$first = function_exists('mb_substr') ? mb_strtoupper(mb_substr(ltrim($title), 0, 1, 'UTF-8'), 'UTF-8') : strtoupper(substr(ltrim($title), 0, 1));
if (!in_array($first, $alphabet, true) || preg_match('/^[0-9\W]/u', $first)) $first = '#';
$grouped[$first][] = $result;
}
return array_filter($grouped);
}
public static function render_archive_results_by_letter($results) {
$groups = self::group_archive_results_by_letter($results);
if (empty($groups)) return '';
$all_letters = array_merge(array('#'), range('A', 'Z'), array('Æ', 'Ø', 'Å'));
ob_start();
echo '<nav class="ansico-ln-letter-nav" aria-label="Bogstavnavigation" style="margin:0 0 1.5rem;display:flex;flex-wrap:wrap;gap:.45rem;">';
foreach ($all_letters as $letter) {
if (isset($groups[$letter])) {
echo '<a href="#ansico-letter-' . esc_attr(sanitize_title($letter)) . '">' . esc_html($letter) . '</a>';
} else {
echo '<span style="opacity:.45;">' . esc_html($letter) . '</span>';
}
}
echo '</nav>';
foreach ($groups as $letter => $items) {
echo '<section id="ansico-letter-' . esc_attr(sanitize_title($letter)) . '" style="margin:0 0 1.5rem;">';
echo '<h2>' . esc_html($letter) . '</h2><ul>';
foreach ($items as $item) echo '<li><a href="' . esc_url($item['url']) . '">' . esc_html($item['title']) . '</a></li>';
echo '</ul></section>';
}
return trim(ob_get_clean());
}
public static function get_taxonomy_archive_grouped_results() {
$term = get_queried_object();
if (!$term || empty($term->taxonomy) || empty($term->term_id)) return array();
$taxonomy_object = get_taxonomy($term->taxonomy);
$post_types = !empty($taxonomy_object->object_type) ? (array) $taxonomy_object->object_type : array('post');
$query = new WP_Query(array(
'post_type' => $post_types,
'post_status' => 'publish',
'posts_per_page' => -1,
'orderby' => 'title',
'order' => 'ASC',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'tax_query' => array(array('taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => $term->term_id)),
));
$ordered_post_types = self::get_ordered_available_post_types();
$groups = array();
foreach ($ordered_post_types as $post_type_name => $pt_obj) {
if (in_array($post_type_name, $post_types, true)) {
$groups[$post_type_name] = array('label' => $pt_obj->labels->name, 'results' => array());
}
}
foreach ($query->posts as $post) {
if (!isset($groups[$post->post_type])) {
$groups[$post->post_type] = array('label' => self::get_post_type_label($post->post_type), 'results' => array());
}
$groups[$post->post_type]['results'][] = array('title' => get_the_title($post), 'url' => get_permalink($post));
}
wp_reset_postdata();
return array_filter($groups, function ($group) { return !empty($group['results']); });
}
public static function get_current_taxonomy_description() {
$description = term_description();
return is_string($description) ? $description : '';
}
private static function should_replace_block_results() {
if (is_search()) return true;
if (is_post_type_archive() && self::is_enabled_post_type_archive(self::get_current_archive_post_type())) return true;
if ((is_tax() || is_category() || is_tag()) && self::is_enabled_taxonomy_archive(self::get_current_taxonomy_name())) return true;
return false;
}
public static function get_block_theme_markup() {
ob_start();
if (is_search()) {
$grouped_results = self::get_grouped_search_results();
$total_results = self::get_total_results_count($grouped_results);
?>
<div class="wp-block-post-template ansico-ln-search-results-block">
<header class="ansico-ln-search-header" style="margin-bottom:2rem;">
<h1 style="margin-bottom:0.5rem;"><?php echo esc_html__('Søgeresultater', 'ansico-ln-plugins'); ?></h1>
<p style="margin-top:0;"><?php echo esc_html(self::get_total_results_text($total_results)); ?></p>
</header>
<?php if (!empty($grouped_results)) : foreach ($grouped_results as $group) : ?>
<section class="ansico-ln-search-group" style="margin-bottom:2rem;">
<p><strong><?php echo esc_html($group['label']); ?></strong></p>
<?php echo self::render_group_results_list($group['results']); ?>
</section>
<?php endforeach; else : ?><p><?php echo esc_html__('Der blev ikke fundet nogen resultater.', 'ansico-ln-plugins'); ?></p><?php endif; ?>
</div>
<?php
} elseif (is_post_type_archive()) {
$post_type = self::get_current_archive_post_type();
$results = self::get_archive_results($post_type);
?>
<div class="wp-block-post-template ansico-ln-archive-results-block">
<header style="margin-bottom:2rem;"><h1 style="margin-bottom:0.5rem;"><?php echo esc_html(self::get_post_type_label($post_type)); ?></h1></header>
<?php echo !empty($results) ? self::render_archive_results_by_letter($results) : '<p>' . esc_html__('Der blev ikke fundet nogen resultater.', 'ansico-ln-plugins') . '</p>'; ?>
</div>
<?php
} elseif (is_tax() || is_category() || is_tag()) {
$grouped = self::get_taxonomy_archive_grouped_results();
$description = self::get_current_taxonomy_description();
?>
<div class="wp-block-post-template ansico-ln-taxonomy-results-block">
<header style="margin-bottom:2rem;"><h1 style="margin-bottom:0.5rem;"><?php echo esc_html(single_term_title('', false)); ?></h1></header>
<?php if (!empty($description)) : ?><div class="ansico-ln-taxonomy-description" style="margin-bottom:1.5rem;"><?php echo wp_kses_post($description); ?></div><?php endif; ?>
<?php if (!empty($grouped)) : foreach ($grouped as $group) : ?>
<section class="ansico-ln-taxonomy-group" style="margin-bottom:2rem;">
<p><strong><?php echo esc_html($group['label']); ?></strong></p>
<?php echo self::render_simple_results_list($group['results']); ?>
</section>
<?php endforeach; else : ?><p><?php echo esc_html__('Der blev ikke fundet nogen resultater.', 'ansico-ln-plugins'); ?></p><?php endif; ?>
</div>
<?php
}
return trim(ob_get_clean());
}
private static function is_block_theme_active() {
return function_exists('wp_is_block_theme') && wp_is_block_theme();
}
}
new Ansico_LN_Plugins();