1346 lines
53 KiB
PHP
1346 lines
53 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Name: Ansico WP Basic
|
||
* Plugin URI: https://ansico.dk
|
||
* Description: Basic SEO fields for posts, pages, custom post types, author archives, taxonomy archives, and special archive pages, including meta title, meta description, and a live search result preview.
|
||
* Version: 0.0.0.4
|
||
* Author: Andreas Andersen (Ansico)
|
||
* Author URI: https://ansico.dk
|
||
* License: GPL-3.0-or-later
|
||
* License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||
* Text Domain: ansico-wp-basic
|
||
* Requires at least: 6.0
|
||
* Requires PHP: 7.4
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
|
||
register_activation_hook(__FILE__, ['Ansico_WP_Basic', 'activate']);
|
||
register_deactivation_hook(__FILE__, ['Ansico_WP_Basic', 'deactivate']);
|
||
|
||
final class Ansico_WP_Basic {
|
||
const OPTION_KEY = 'ansico_wp_basic_settings';
|
||
const META_TITLE_KEY = '_ansico_wp_basic_meta_title';
|
||
const META_DESC_KEY = '_ansico_wp_basic_meta_description';
|
||
const HIDE_TITLE_KEY = '_ansico_wp_basic_hide_title';
|
||
const NONCE_KEY = 'ansico_wp_basic_meta_box_nonce';
|
||
const TERM_NONCE_KEY = 'ansico_wp_basic_term_nonce';
|
||
const USER_NONCE_KEY = 'ansico_wp_basic_user_nonce';
|
||
|
||
public static function activate() {
|
||
$plugin = new self();
|
||
$plugin->register_sitemap_rewrites();
|
||
flush_rewrite_rules();
|
||
}
|
||
|
||
public static function deactivate() {
|
||
flush_rewrite_rules();
|
||
}
|
||
|
||
public function __construct() {
|
||
add_action('admin_menu', [$this, 'register_admin_menu']);
|
||
add_action('admin_init', [$this, 'register_settings']);
|
||
|
||
add_action('add_meta_boxes', [$this, 'register_meta_boxes']);
|
||
add_action('save_post', [$this, 'save_meta_box']);
|
||
add_filter('wp_insert_post_data', [$this, 'maybe_switch_post_type'], 10, 2);
|
||
|
||
add_action('show_user_profile', [$this, 'render_user_fields']);
|
||
add_action('edit_user_profile', [$this, 'render_user_fields']);
|
||
add_action('personal_options_update', [$this, 'save_user_fields']);
|
||
add_action('edit_user_profile_update', [$this, 'save_user_fields']);
|
||
|
||
add_action('created_term', [$this, 'save_term_fields'], 10, 3);
|
||
add_action('edited_term', [$this, 'save_term_fields'], 10, 3);
|
||
|
||
add_action('admin_enqueue_scripts', [$this, 'enqueue_admin_assets']);
|
||
add_filter('pre_get_document_title', [$this, 'filter_document_title'], 20);
|
||
add_action('wp_head', [$this, 'output_meta_description'], 1);
|
||
add_filter('the_title', [$this, 'maybe_hide_page_title'], 10, 2);
|
||
add_filter('single_post_title', [$this, 'maybe_hide_single_post_title'], 10, 2);
|
||
add_action('admin_notices', [$this, 'settings_notice_if_no_types']);
|
||
add_action('init', [$this, 'register_taxonomy_hooks']);
|
||
add_action('init', [$this, 'register_sitemap_rewrites']);
|
||
add_action('template_redirect', [$this, 'maybe_render_sitemap']);
|
||
add_filter('query_vars', [$this, 'register_query_vars']);
|
||
}
|
||
|
||
public function get_settings() {
|
||
$defaults = [
|
||
'enable_meta_module' => 1,
|
||
'enable_sitemap_module' => 1,
|
||
'enabled_post_types' => $this->get_default_post_types(),
|
||
'enable_author_fields' => 1,
|
||
'enable_taxonomy_fields'=> 1,
|
||
'special_pages' => [
|
||
'date' => ['title' => '', 'description' => ''],
|
||
'search'=> ['title' => '', 'description' => ''],
|
||
'404' => ['title' => '', 'description' => ''],
|
||
'home' => ['title' => '', 'description' => ''],
|
||
],
|
||
'post_type_archives' => [],
|
||
];
|
||
|
||
$settings = get_option(self::OPTION_KEY, []);
|
||
if (!is_array($settings)) {
|
||
$settings = [];
|
||
}
|
||
|
||
$settings = wp_parse_args($settings, $defaults);
|
||
$settings['enable_meta_module'] = empty($settings['enable_meta_module']) ? 0 : 1;
|
||
$settings['enable_sitemap_module'] = empty($settings['enable_sitemap_module']) ? 0 : 1;
|
||
$settings['enabled_post_types'] = array_values(array_filter(array_map('sanitize_key', (array) $settings['enabled_post_types'])));
|
||
$settings['enable_author_fields'] = empty($settings['enable_author_fields']) ? 0 : 1;
|
||
$settings['enable_taxonomy_fields'] = empty($settings['enable_taxonomy_fields']) ? 0 : 1;
|
||
$settings['special_pages'] = $this->sanitize_special_pages($settings['special_pages']);
|
||
$settings['post_type_archives'] = $this->sanitize_post_type_archive_settings($settings['post_type_archives']);
|
||
|
||
return $settings;
|
||
}
|
||
|
||
private function get_public_post_types() {
|
||
$post_types = get_post_types([
|
||
'public' => true,
|
||
'show_ui' => true,
|
||
], 'objects');
|
||
|
||
unset($post_types['attachment']);
|
||
|
||
return $post_types;
|
||
}
|
||
|
||
private function get_default_post_types() {
|
||
return array_keys($this->get_public_post_types());
|
||
}
|
||
|
||
private function get_public_taxonomies() {
|
||
return get_taxonomies([
|
||
'public' => true,
|
||
'show_ui' => true,
|
||
], 'objects');
|
||
}
|
||
|
||
private function get_archive_post_types() {
|
||
$post_types = $this->get_public_post_types();
|
||
foreach ($post_types as $key => $post_type) {
|
||
if (empty($post_type->has_archive)) {
|
||
unset($post_types[$key]);
|
||
}
|
||
}
|
||
return $post_types;
|
||
}
|
||
|
||
private function sanitize_special_pages($special_pages) {
|
||
$defaults = [
|
||
'date' => ['title' => '', 'description' => ''],
|
||
'search' => ['title' => '', 'description' => ''],
|
||
'404' => ['title' => '', 'description' => ''],
|
||
'home' => ['title' => '', 'description' => ''],
|
||
];
|
||
|
||
$special_pages = is_array($special_pages) ? $special_pages : [];
|
||
|
||
foreach ($defaults as $key => $value) {
|
||
$page = isset($special_pages[$key]) && is_array($special_pages[$key]) ? $special_pages[$key] : [];
|
||
$defaults[$key] = [
|
||
'title' => isset($page['title']) ? sanitize_text_field($page['title']) : '',
|
||
'description' => isset($page['description']) ? sanitize_textarea_field($page['description']) : '',
|
||
];
|
||
}
|
||
|
||
return $defaults;
|
||
}
|
||
|
||
private function sanitize_post_type_archive_settings($archives) {
|
||
$clean = [];
|
||
$allowed = array_keys($this->get_archive_post_types());
|
||
$archives = is_array($archives) ? $archives : [];
|
||
|
||
foreach ($allowed as $post_type) {
|
||
$archive = isset($archives[$post_type]) && is_array($archives[$post_type]) ? $archives[$post_type] : [];
|
||
$clean[$post_type] = [
|
||
'title' => isset($archive['title']) ? sanitize_text_field($archive['title']) : '',
|
||
'description' => isset($archive['description']) ? sanitize_textarea_field($archive['description']) : '',
|
||
];
|
||
}
|
||
|
||
return $clean;
|
||
}
|
||
|
||
public function register_admin_menu() {
|
||
add_menu_page(
|
||
__('Ansico WP Basic', 'ansico-wp-basic'),
|
||
__('Ansico WP Basic', 'ansico-wp-basic'),
|
||
'manage_options',
|
||
'ansico-wp-basic',
|
||
[$this, 'render_settings_page'],
|
||
'dashicons-search',
|
||
81
|
||
);
|
||
|
||
add_submenu_page(
|
||
'ansico-wp-basic',
|
||
__('Settings', 'ansico-wp-basic'),
|
||
__('Settings', 'ansico-wp-basic'),
|
||
'manage_options',
|
||
'ansico-wp-basic',
|
||
[$this, 'render_settings_page']
|
||
);
|
||
}
|
||
|
||
public function register_settings() {
|
||
register_setting(
|
||
'ansico_wp_basic_settings_group',
|
||
self::OPTION_KEY,
|
||
[$this, 'sanitize_settings']
|
||
);
|
||
|
||
add_settings_section(
|
||
'ansico_wp_basic_main_section',
|
||
__('General settings', 'ansico-wp-basic'),
|
||
function () {
|
||
echo '<p>' . esc_html__('Choose where the SEO fields should be available.', 'ansico-wp-basic') . '</p>';
|
||
},
|
||
'ansico-wp-basic'
|
||
);
|
||
|
||
add_settings_field(
|
||
'enable_meta_module',
|
||
__('SEO module', 'ansico-wp-basic'),
|
||
[$this, 'render_meta_module_toggle'],
|
||
'ansico-wp-basic',
|
||
'ansico_wp_basic_main_section'
|
||
);
|
||
|
||
add_settings_field(
|
||
'enable_sitemap_module',
|
||
__('XML sitemap module', 'ansico-wp-basic'),
|
||
[$this, 'render_sitemap_module_toggle'],
|
||
'ansico-wp-basic',
|
||
'ansico_wp_basic_main_section'
|
||
);
|
||
|
||
add_settings_field(
|
||
'enabled_post_types',
|
||
__('Enable for post types', 'ansico-wp-basic'),
|
||
[$this, 'render_post_types_field'],
|
||
'ansico-wp-basic',
|
||
'ansico_wp_basic_main_section'
|
||
);
|
||
|
||
add_settings_field(
|
||
'enable_author_fields',
|
||
__('Author archive SEO fields', 'ansico-wp-basic'),
|
||
[$this, 'render_author_field_toggle'],
|
||
'ansico-wp-basic',
|
||
'ansico_wp_basic_main_section'
|
||
);
|
||
|
||
add_settings_field(
|
||
'enable_taxonomy_fields',
|
||
__('Taxonomy archive SEO fields', 'ansico-wp-basic'),
|
||
[$this, 'render_taxonomy_field_toggle'],
|
||
'ansico-wp-basic',
|
||
'ansico_wp_basic_main_section'
|
||
);
|
||
|
||
add_settings_section(
|
||
'ansico_wp_basic_archives_section',
|
||
__('Archives and special pages', 'ansico-wp-basic'),
|
||
function () {
|
||
echo '<p>' . esc_html__('Set SEO title and description for archive-style pages that do not have a normal editor screen.', 'ansico-wp-basic') . '</p>';
|
||
},
|
||
'ansico-wp-basic'
|
||
);
|
||
|
||
add_settings_field(
|
||
'special_pages',
|
||
__('Global archive pages', 'ansico-wp-basic'),
|
||
[$this, 'render_special_pages_fields'],
|
||
'ansico-wp-basic',
|
||
'ansico_wp_basic_archives_section'
|
||
);
|
||
|
||
add_settings_field(
|
||
'post_type_archives',
|
||
__('Post type archives', 'ansico-wp-basic'),
|
||
[$this, 'render_post_type_archive_fields'],
|
||
'ansico-wp-basic',
|
||
'ansico_wp_basic_archives_section'
|
||
);
|
||
}
|
||
|
||
public function sanitize_settings($input) {
|
||
$public_post_types = array_keys($this->get_public_post_types());
|
||
|
||
$enabled_post_types = [];
|
||
if (!empty($input['enabled_post_types']) && is_array($input['enabled_post_types'])) {
|
||
foreach ($input['enabled_post_types'] as $post_type) {
|
||
$post_type = sanitize_key($post_type);
|
||
if (in_array($post_type, $public_post_types, true)) {
|
||
$enabled_post_types[] = $post_type;
|
||
}
|
||
}
|
||
}
|
||
|
||
return [
|
||
'enable_meta_module' => empty($input['enable_meta_module']) ? 0 : 1,
|
||
'enable_sitemap_module' => empty($input['enable_sitemap_module']) ? 0 : 1,
|
||
'enabled_post_types' => array_values(array_unique($enabled_post_types)),
|
||
'enable_author_fields' => empty($input['enable_author_fields']) ? 0 : 1,
|
||
'enable_taxonomy_fields' => empty($input['enable_taxonomy_fields']) ? 0 : 1,
|
||
'special_pages' => $this->sanitize_special_pages(isset($input['special_pages']) ? $input['special_pages'] : []),
|
||
'post_type_archives' => $this->sanitize_post_type_archive_settings(isset($input['post_type_archives']) ? $input['post_type_archives'] : []),
|
||
];
|
||
}
|
||
|
||
|
||
public function render_meta_module_toggle() {
|
||
$settings = $this->get_settings();
|
||
printf(
|
||
'<label><input type="checkbox" name="%1$s[enable_meta_module]" value="1" %2$s> %3$s</label><p class="description">%4$s</p>',
|
||
esc_attr(self::OPTION_KEY),
|
||
checked($settings['enable_meta_module'], 1, false),
|
||
esc_html__('Enable Meta title and Meta description fields and frontend output.', 'ansico-wp-basic'),
|
||
esc_html__('Turn this off to hide the SEO editor UI and stop custom SEO output on the frontend, while preserving saved values.', 'ansico-wp-basic')
|
||
);
|
||
}
|
||
|
||
public function render_sitemap_module_toggle() {
|
||
$settings = $this->get_settings();
|
||
printf(
|
||
'<label><input type="checkbox" name="%1$s[enable_sitemap_module]" value="1" %2$s> %3$s</label><p class="description">%4$s</p>',
|
||
esc_attr(self::OPTION_KEY),
|
||
checked($settings['enable_sitemap_module'], 1, false),
|
||
esc_html__('Enable XML sitemap generation.', 'ansico-wp-basic'),
|
||
esc_html__('When enabled, the sitemap index is available at /ansico-sitemap.xml.', 'ansico-wp-basic')
|
||
);
|
||
}
|
||
|
||
public function render_post_types_field() {
|
||
$settings = $this->get_settings();
|
||
$public_post_types = $this->get_public_post_types();
|
||
|
||
echo '<fieldset>';
|
||
foreach ($public_post_types as $post_type) {
|
||
printf(
|
||
'<label style="display:block;margin-bottom:8px;"><input type="checkbox" name="%1$s[enabled_post_types][]" value="%2$s" %3$s> %4$s <code>(%2$s)</code></label>',
|
||
esc_attr(self::OPTION_KEY),
|
||
esc_attr($post_type->name),
|
||
checked(in_array($post_type->name, $settings['enabled_post_types'], true), true, false),
|
||
esc_html($post_type->labels->singular_name)
|
||
);
|
||
}
|
||
echo '</fieldset>';
|
||
}
|
||
|
||
public function render_author_field_toggle() {
|
||
$settings = $this->get_settings();
|
||
printf(
|
||
'<label><input type="checkbox" name="%1$s[enable_author_fields]" value="1" %2$s> %3$s</label><p class="description">%4$s</p>',
|
||
esc_attr(self::OPTION_KEY),
|
||
checked($settings['enable_author_fields'], 1, false),
|
||
esc_html__('Allow SEO fields on user profile pages for author archives.', 'ansico-wp-basic'),
|
||
esc_html__('When enabled, each user profile gets Meta title and Meta description fields for that author archive.', 'ansico-wp-basic')
|
||
);
|
||
}
|
||
|
||
public function render_taxonomy_field_toggle() {
|
||
$settings = $this->get_settings();
|
||
printf(
|
||
'<label><input type="checkbox" name="%1$s[enable_taxonomy_fields]" value="1" %2$s> %3$s</label><p class="description">%4$s</p>',
|
||
esc_attr(self::OPTION_KEY),
|
||
checked($settings['enable_taxonomy_fields'], 1, false),
|
||
esc_html__('Allow SEO fields on taxonomy term pages.', 'ansico-wp-basic'),
|
||
esc_html__('Works for categories, tags, and public custom taxonomies.', 'ansico-wp-basic')
|
||
);
|
||
}
|
||
|
||
public function render_special_pages_fields() {
|
||
$settings = $this->get_settings();
|
||
if (empty($settings['enable_meta_module'])) {
|
||
echo '<p class="description">' . esc_html__('The SEO module is currently disabled.', 'ansico-wp-basic') . '</p>';
|
||
return;
|
||
}
|
||
$pages = [
|
||
'home' => __('Blog home / posts page', 'ansico-wp-basic'),
|
||
'date' => __('Date archives', 'ansico-wp-basic'),
|
||
'search' => __('Search results pages', 'ansico-wp-basic'),
|
||
'404' => __('404 page', 'ansico-wp-basic'),
|
||
];
|
||
|
||
echo '<div class="ansico-wp-basic-settings-grid">';
|
||
foreach ($pages as $key => $label) {
|
||
$title = $settings['special_pages'][$key]['title'] ?? '';
|
||
$description = $settings['special_pages'][$key]['description'] ?? '';
|
||
printf(
|
||
'<div class="ansico-wp-basic-settings-card"><h3>%1$s</h3><p><label><strong>%2$s</strong></label><input type="text" class="widefat" name="%3$s[special_pages][%4$s][title]" value="%5$s" placeholder="%6$s"></p><p><label><strong>%7$s</strong></label><textarea class="widefat" rows="3" name="%3$s[special_pages][%4$s][description]" placeholder="%8$s">%9$s</textarea></p></div>',
|
||
esc_html($label),
|
||
esc_html__('Meta title', 'ansico-wp-basic'),
|
||
esc_attr(self::OPTION_KEY),
|
||
esc_attr($key),
|
||
esc_attr($title),
|
||
esc_attr__('Enter a custom meta title', 'ansico-wp-basic'),
|
||
esc_html__('Meta description', 'ansico-wp-basic'),
|
||
esc_attr__('Enter a custom meta description', 'ansico-wp-basic'),
|
||
esc_textarea($description)
|
||
);
|
||
}
|
||
echo '</div>';
|
||
}
|
||
|
||
public function render_post_type_archive_fields() {
|
||
$settings = $this->get_settings();
|
||
if (empty($settings['enable_meta_module'])) {
|
||
echo '<p class="description">' . esc_html__('The SEO module is currently disabled.', 'ansico-wp-basic') . '</p>';
|
||
return;
|
||
}
|
||
$archives = $this->get_archive_post_types();
|
||
|
||
if (empty($archives)) {
|
||
echo '<p>' . esc_html__('No public post type archives were found.', 'ansico-wp-basic') . '</p>';
|
||
return;
|
||
}
|
||
|
||
echo '<div class="ansico-wp-basic-settings-grid">';
|
||
foreach ($archives as $post_type) {
|
||
$title = $settings['post_type_archives'][$post_type->name]['title'] ?? '';
|
||
$description = $settings['post_type_archives'][$post_type->name]['description'] ?? '';
|
||
printf(
|
||
'<div class="ansico-wp-basic-settings-card"><h3>%1$s <code>(%2$s)</code></h3><p><label><strong>%3$s</strong></label><input type="text" class="widefat" name="%4$s[post_type_archives][%2$s][title]" value="%5$s" placeholder="%6$s"></p><p><label><strong>%7$s</strong></label><textarea class="widefat" rows="3" name="%4$s[post_type_archives][%2$s][description]" placeholder="%8$s">%9$s</textarea></p></div>',
|
||
esc_html($post_type->labels->name),
|
||
esc_attr($post_type->name),
|
||
esc_html__('Meta title', 'ansico-wp-basic'),
|
||
esc_attr(self::OPTION_KEY),
|
||
esc_attr($title),
|
||
esc_attr__('Enter a custom meta title', 'ansico-wp-basic'),
|
||
esc_html__('Meta description', 'ansico-wp-basic'),
|
||
esc_attr__('Enter a custom meta description', 'ansico-wp-basic'),
|
||
esc_textarea($description)
|
||
);
|
||
}
|
||
echo '</div>';
|
||
}
|
||
|
||
public function render_settings_page() {
|
||
if (!current_user_can('manage_options')) {
|
||
return;
|
||
}
|
||
?>
|
||
<div class="wrap ansico-wp-basic-settings-page">
|
||
<h1><?php echo esc_html__('Ansico WP Basic', 'ansico-wp-basic'); ?></h1>
|
||
<p><?php echo esc_html__('Basic SEO fields for WordPress content, archives, special pages, title visibility, post type switching, and optional XML sitemaps.', 'ansico-wp-basic'); ?></p>
|
||
<?php $settings = $this->get_settings(); ?>
|
||
<p><strong><?php echo esc_html__('XML sitemap:', 'ansico-wp-basic'); ?></strong> <?php echo !empty($settings['enable_sitemap_module']) ? '<code>' . esc_html(home_url('/ansico-sitemap.xml')) . '</code>' : esc_html__('Disabled', 'ansico-wp-basic'); ?></p>
|
||
<form method="post" action="options.php">
|
||
<?php
|
||
settings_fields('ansico_wp_basic_settings_group');
|
||
do_settings_sections('ansico-wp-basic');
|
||
submit_button(__('Save Settings', 'ansico-wp-basic'));
|
||
?>
|
||
</form>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
public function register_meta_boxes() {
|
||
$settings = $this->get_settings();
|
||
foreach ($settings['enabled_post_types'] as $post_type) {
|
||
if (!empty($settings['enable_meta_module'])) {
|
||
add_meta_box(
|
||
'ansico_wp_basic_seo',
|
||
__('Ansico WP Basic SEO', 'ansico-wp-basic'),
|
||
[$this, 'render_meta_box'],
|
||
$post_type,
|
||
'normal',
|
||
'default'
|
||
);
|
||
}
|
||
|
||
add_meta_box(
|
||
'ansico_wp_basic_tools',
|
||
__('Ansico WP Basic Tools', 'ansico-wp-basic'),
|
||
[$this, 'render_tools_meta_box'],
|
||
$post_type,
|
||
'side',
|
||
'default'
|
||
);
|
||
}
|
||
}
|
||
|
||
|
||
private function get_switchable_post_types() {
|
||
$post_types = $this->get_public_post_types();
|
||
return array_filter($post_types, function($post_type) {
|
||
return !empty($post_type->show_ui);
|
||
});
|
||
}
|
||
|
||
public function render_tools_meta_box($post) {
|
||
wp_nonce_field('ansico_wp_basic_save_meta_box', self::NONCE_KEY);
|
||
$post_type = get_post_type($post);
|
||
$switchable_types = $this->get_switchable_post_types();
|
||
$hide_title = (int) get_post_meta($post->ID, self::HIDE_TITLE_KEY, true);
|
||
echo '<div class="ansico-wp-basic-tools-box">';
|
||
if ($post_type === 'page') {
|
||
echo '<p><label><input type="checkbox" name="ansico_wp_basic_hide_title" value="1" ' . checked($hide_title, 1, false) . '> ' . esc_html__('Hide page title on the frontend for this page', 'ansico-wp-basic') . '</label></p>';
|
||
}
|
||
echo '<p><label for="ansico_wp_basic_change_post_type"><strong>' . esc_html__('Change post type', 'ansico-wp-basic') . '</strong></label>';
|
||
echo '<select id="ansico_wp_basic_change_post_type" name="ansico_wp_basic_change_post_type" class="ansico-post-type-select">';
|
||
foreach ($switchable_types as $type_obj) {
|
||
printf('<option value="%1$s" %2$s>%3$s</option>', esc_attr($type_obj->name), selected($type_obj->name, $post_type, false), esc_html($type_obj->labels->singular_name . ' (' . $type_obj->name . ')'));
|
||
}
|
||
echo '</select>';
|
||
echo '</div>';
|
||
}
|
||
|
||
private function render_snippet_box($args) {
|
||
$meta_title = isset($args['meta_title']) ? (string) $args['meta_title'] : '';
|
||
$meta_description = isset($args['meta_description']) ? (string) $args['meta_description'] : '';
|
||
$fallback_title = isset($args['fallback_title']) ? (string) $args['fallback_title'] : '';
|
||
$permalink = isset($args['permalink']) ? (string) $args['permalink'] : home_url('/');
|
||
$site_name = get_bloginfo('name');
|
||
?>
|
||
<div class="ansico-wp-basic-metabox">
|
||
<p>
|
||
<label for="ansico_wp_basic_meta_title"><strong><?php echo esc_html__('Meta title', 'ansico-wp-basic'); ?></strong></label>
|
||
<input type="text" id="ansico_wp_basic_meta_title" name="ansico_wp_basic_meta_title" class="widefat" value="<?php echo esc_attr($meta_title); ?>" placeholder="<?php echo esc_attr__('Enter a custom meta title', 'ansico-wp-basic'); ?>">
|
||
<span class="description"><?php echo esc_html__('Recommended: around 50–60 characters.', 'ansico-wp-basic'); ?></span>
|
||
<span class="ansico-wp-basic-counter" data-counter-for="title"></span>
|
||
</p>
|
||
<p>
|
||
<label for="ansico_wp_basic_meta_description"><strong><?php echo esc_html__('Meta description', 'ansico-wp-basic'); ?></strong></label>
|
||
<textarea id="ansico_wp_basic_meta_description" name="ansico_wp_basic_meta_description" class="widefat" rows="4" placeholder="<?php echo esc_attr__('Enter a custom meta description', 'ansico-wp-basic'); ?>"><?php echo esc_textarea($meta_description); ?></textarea>
|
||
<span class="description"><?php echo esc_html__('Recommended: around 140–155 characters. Longer text will usually be cut in search results.', 'ansico-wp-basic'); ?></span>
|
||
<span class="ansico-wp-basic-counter" data-counter-for="description"></span>
|
||
</p>
|
||
|
||
<div class="ansico-wp-basic-snippet-wrapper">
|
||
<strong><?php echo esc_html__('Search result preview', 'ansico-wp-basic'); ?></strong>
|
||
<div class="ansico-wp-basic-snippet" data-fallback-title="<?php echo esc_attr($fallback_title); ?>" data-permalink="<?php echo esc_url($permalink); ?>" data-site-name="<?php echo esc_attr($site_name); ?>">
|
||
<div class="ansico-wp-basic-snippet-site"><?php echo esc_html($site_name); ?></div>
|
||
<div class="ansico-wp-basic-snippet-url"></div>
|
||
<div class="ansico-wp-basic-snippet-title"></div>
|
||
<div class="ansico-wp-basic-snippet-description"><span class="ansico-wp-basic-snippet-description-text"></span><span class="ansico-wp-basic-snippet-overflow"></span></div>
|
||
</div>
|
||
<p class="description ansico-wp-basic-truncation-note"></p>
|
||
</div>
|
||
</div>
|
||
<?php
|
||
}
|
||
|
||
|
||
private function get_trimmed_text_excerpt($text, $limit = 150) {
|
||
$text = trim((string) $text);
|
||
if ($text === '') {
|
||
return '';
|
||
}
|
||
|
||
$text = preg_replace('/\s+/u', ' ', wp_strip_all_tags($text));
|
||
if ($text === '') {
|
||
return '';
|
||
}
|
||
|
||
if (function_exists('mb_strlen') && function_exists('mb_substr')) {
|
||
if (mb_strlen($text) <= $limit) {
|
||
return $text;
|
||
}
|
||
$trimmed = mb_substr($text, 0, $limit + 1);
|
||
$last_space = mb_strrpos($trimmed, ' ');
|
||
if ($last_space !== false && $last_space > (int) floor($limit * 0.6)) {
|
||
$trimmed = mb_substr($trimmed, 0, $last_space);
|
||
} else {
|
||
$trimmed = mb_substr($trimmed, 0, $limit);
|
||
}
|
||
return rtrim($trimmed, "
|
||
|
||
|