Ansico-CPT-pagecontrol/ansico-ln-plugins/ansico-ln-plugins.php
2026-04-17 22:10:27 +02:00

1294 lines
63 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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();