Synced folder
This commit is contained in:
parent
85d3786cfb
commit
f03889e3c8
18 changed files with 1990 additions and 0 deletions
942
ansico-cpt-and-taxonomies/admin/class-ansico-cptax-admin.php
Normal file
942
ansico-cpt-and-taxonomies/admin/class-ansico-cptax-admin.php
Normal file
|
|
@ -0,0 +1,942 @@
|
|||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Ansico_CPTax_Admin {
|
||||
private static $instance = null;
|
||||
private $plugin;
|
||||
|
||||
public static function instance( $plugin ) {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self( $plugin );
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function __construct( $plugin ) {
|
||||
$this->plugin = $plugin;
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
||||
add_action( 'admin_init', array( $this, 'handle_actions' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
|
||||
}
|
||||
|
||||
public function admin_menu() {
|
||||
add_menu_page(
|
||||
__( 'Ansico CPT & Taxonomies', 'ansico-cpt-and-taxonomies' ),
|
||||
__( 'Ansico CPT', 'ansico-cpt-and-taxonomies' ),
|
||||
'manage_options',
|
||||
'ansico-cptax',
|
||||
array( $this, 'render_cpts_page' ),
|
||||
'dashicons-database-add',
|
||||
58
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'ansico-cptax',
|
||||
__( 'Custom Post Types', 'ansico-cpt-and-taxonomies' ),
|
||||
__( 'Custom Post Types', 'ansico-cpt-and-taxonomies' ),
|
||||
'manage_options',
|
||||
'ansico-cptax',
|
||||
array( $this, 'render_cpts_page' )
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'ansico-cptax',
|
||||
__( 'Taxonomies', 'ansico-cpt-and-taxonomies' ),
|
||||
__( 'Taxonomies', 'ansico-cpt-and-taxonomies' ),
|
||||
'manage_options',
|
||||
'ansico-cptax-taxonomies',
|
||||
array( $this, 'render_taxonomies_page' )
|
||||
);
|
||||
|
||||
add_submenu_page(
|
||||
'ansico-cptax',
|
||||
__( 'Tools', 'ansico-cpt-and-taxonomies' ),
|
||||
__( 'Tools', 'ansico-cpt-and-taxonomies' ),
|
||||
'manage_options',
|
||||
'ansico-cptax-tools',
|
||||
array( $this, 'render_tools_page' )
|
||||
);
|
||||
}
|
||||
|
||||
public function enqueue_assets( $hook_suffix ) {
|
||||
if ( false === strpos( $hook_suffix, 'ansico-cptax' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style(
|
||||
'ansico-cptax-admin',
|
||||
ANSICO_CPTAX_URL . 'assets/admin.css',
|
||||
array(),
|
||||
ANSICO_CPTAX_VERSION
|
||||
);
|
||||
|
||||
wp_enqueue_script(
|
||||
'ansico-cptax-admin',
|
||||
ANSICO_CPTAX_URL . 'assets/admin.js',
|
||||
array(),
|
||||
ANSICO_CPTAX_VERSION,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
public function handle_actions() {
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( empty( $_POST['ansico_cptax_action'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$action = sanitize_text_field( wp_unslash( $_POST['ansico_cptax_action'] ) );
|
||||
|
||||
if ( 'export_json' === $action ) {
|
||||
check_admin_referer( 'ansico_cptax_export' );
|
||||
$this->download_export();
|
||||
}
|
||||
|
||||
check_admin_referer( 'ansico_cptax_save' );
|
||||
|
||||
if ( 'save_cpt' === $action ) {
|
||||
$record = $this->sanitize_cpt_request();
|
||||
if ( ! empty( $record['is_override'] ) ) {
|
||||
$records = $this->plugin->get_cpt_overrides();
|
||||
$records = $this->upsert_by_key( $records, sanitize_key( wp_unslash( $_POST['current_key'] ?? '' ) ), $record, 'key' );
|
||||
$this->plugin->save_cpt_overrides( $records );
|
||||
} else {
|
||||
$records = $this->plugin->get_cpts();
|
||||
$records = $this->upsert_by_key( $records, sanitize_key( wp_unslash( $_POST['current_key'] ?? '' ) ), $record, 'key' );
|
||||
$this->plugin->save_cpts( $records );
|
||||
}
|
||||
flush_rewrite_rules();
|
||||
wp_safe_redirect( admin_url( 'admin.php?page=ansico-cptax&updated=1' ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( 'delete_cpt' === $action ) {
|
||||
$key = sanitize_key( wp_unslash( $_POST['key'] ?? '' ) );
|
||||
$is_override = ! empty( $_POST['is_override'] );
|
||||
$records = $is_override ? $this->plugin->get_cpt_overrides() : $this->plugin->get_cpts();
|
||||
$records = array_values( array_filter( $records, function( $cpt ) use ( $key ) {
|
||||
return ( $cpt['key'] ?? '' ) !== $key;
|
||||
} ) );
|
||||
if ( $is_override ) {
|
||||
$this->plugin->save_cpt_overrides( $records );
|
||||
} else {
|
||||
$this->plugin->save_cpts( $records );
|
||||
}
|
||||
flush_rewrite_rules();
|
||||
wp_safe_redirect( admin_url( 'admin.php?page=ansico-cptax&deleted=1' ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( 'save_taxonomy' === $action ) {
|
||||
$record = $this->sanitize_taxonomy_request();
|
||||
if ( ! empty( $record['is_override'] ) ) {
|
||||
$records = $this->plugin->get_taxonomy_overrides();
|
||||
$records = $this->upsert_by_key( $records, sanitize_key( wp_unslash( $_POST['current_key'] ?? '' ) ), $record, 'key' );
|
||||
$this->plugin->save_taxonomy_overrides( $records );
|
||||
} else {
|
||||
$records = $this->plugin->get_taxonomies();
|
||||
$records = $this->upsert_by_key( $records, sanitize_key( wp_unslash( $_POST['current_key'] ?? '' ) ), $record, 'key' );
|
||||
$this->plugin->save_taxonomies( $records );
|
||||
}
|
||||
flush_rewrite_rules();
|
||||
wp_safe_redirect( admin_url( 'admin.php?page=ansico-cptax-taxonomies&updated=1' ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( 'delete_taxonomy' === $action ) {
|
||||
$key = sanitize_key( wp_unslash( $_POST['key'] ?? '' ) );
|
||||
$is_override = ! empty( $_POST['is_override'] );
|
||||
$records = $is_override ? $this->plugin->get_taxonomy_overrides() : $this->plugin->get_taxonomies();
|
||||
$records = array_values( array_filter( $records, function( $taxonomy ) use ( $key ) {
|
||||
return ( $taxonomy['key'] ?? '' ) !== $key;
|
||||
} ) );
|
||||
if ( $is_override ) {
|
||||
$this->plugin->save_taxonomy_overrides( $records );
|
||||
} else {
|
||||
$this->plugin->save_taxonomies( $records );
|
||||
}
|
||||
flush_rewrite_rules();
|
||||
wp_safe_redirect( admin_url( 'admin.php?page=ansico-cptax-taxonomies&deleted=1' ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( 'import_json' === $action ) {
|
||||
$replace_existing = ! empty( $_POST['replace_existing'] );
|
||||
$result = $this->handle_import_json( $replace_existing );
|
||||
$status = ! empty( $result['error'] ) ? 'import_error=1' : 'imported=1';
|
||||
$message = ! empty( $result['message'] ) ? rawurlencode( $result['message'] ) : '';
|
||||
wp_safe_redirect( admin_url( 'admin.php?page=ansico-cptax-tools&' . $status . '&message=' . $message ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
private function download_export() {
|
||||
$filename = 'ansico-cptax-export-' . gmdate( 'Y-m-d-His' ) . '.json';
|
||||
$payload = $this->plugin->get_export_payload();
|
||||
|
||||
nocache_headers();
|
||||
header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
|
||||
header( 'Content-Disposition: attachment; filename=' . $filename );
|
||||
echo wp_json_encode( $payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES );
|
||||
exit;
|
||||
}
|
||||
|
||||
private function handle_import_json( $replace_existing ) {
|
||||
if ( empty( $_FILES['import_file']['tmp_name'] ) ) {
|
||||
return array(
|
||||
'error' => true,
|
||||
'message' => __( 'No JSON file was uploaded.', 'ansico-cpt-and-taxonomies' ),
|
||||
);
|
||||
}
|
||||
|
||||
$raw = file_get_contents( $_FILES['import_file']['tmp_name'] ); // phpcs:ignore WordPressVIPMinimum.Performance.FetchingRemoteData.FileGetContentsUnknown
|
||||
if ( false === $raw || '' === $raw ) {
|
||||
return array(
|
||||
'error' => true,
|
||||
'message' => __( 'The uploaded file could not be read.', 'ansico-cpt-and-taxonomies' ),
|
||||
);
|
||||
}
|
||||
|
||||
$payload = json_decode( $raw, true );
|
||||
if ( ! is_array( $payload ) ) {
|
||||
return array(
|
||||
'error' => true,
|
||||
'message' => __( 'The uploaded file is not valid JSON.', 'ansico-cpt-and-taxonomies' ),
|
||||
);
|
||||
}
|
||||
|
||||
$cpts = $this->normalize_import_records( $payload['cpts'] ?? array(), 'cpt' );
|
||||
$taxonomies = $this->normalize_import_records( $payload['taxonomies'] ?? array(), 'taxonomy' );
|
||||
$cpt_overrides = $this->normalize_import_records( $payload['cpt_overrides'] ?? array(), 'cpt' );
|
||||
$taxonomy_overrides = $this->normalize_import_records( $payload['taxonomy_overrides'] ?? array(), 'taxonomy' );
|
||||
|
||||
if ( $replace_existing ) {
|
||||
$this->plugin->save_cpts( $cpts );
|
||||
$this->plugin->save_taxonomies( $taxonomies );
|
||||
$this->plugin->save_cpt_overrides( $cpt_overrides );
|
||||
$this->plugin->save_taxonomy_overrides( $taxonomy_overrides );
|
||||
} else {
|
||||
$this->plugin->save_cpts( $this->merge_by_key( $this->plugin->get_cpts(), $cpts ) );
|
||||
$this->plugin->save_taxonomies( $this->merge_by_key( $this->plugin->get_taxonomies(), $taxonomies ) );
|
||||
$this->plugin->save_cpt_overrides( $this->merge_by_key( $this->plugin->get_cpt_overrides(), $cpt_overrides ) );
|
||||
$this->plugin->save_taxonomy_overrides( $this->merge_by_key( $this->plugin->get_taxonomy_overrides(), $taxonomy_overrides ) );
|
||||
}
|
||||
|
||||
flush_rewrite_rules();
|
||||
|
||||
return array(
|
||||
'error' => false,
|
||||
'message' => __( 'JSON import completed.', 'ansico-cpt-and-taxonomies' ),
|
||||
);
|
||||
}
|
||||
|
||||
private function normalize_import_records( $records, $type ) {
|
||||
$normalized = array();
|
||||
if ( ! is_array( $records ) ) {
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
foreach ( $records as $record ) {
|
||||
if ( 'taxonomy' === $type ) {
|
||||
$record = $this->plugin->normalize_taxonomy_record( $record );
|
||||
} else {
|
||||
$record = $this->plugin->normalize_cpt_record( $record );
|
||||
}
|
||||
|
||||
if ( empty( $record['key'] ) ) {
|
||||
continue;
|
||||
}
|
||||
$normalized[] = $record;
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
private function merge_by_key( $existing, $incoming ) {
|
||||
foreach ( $incoming as $record ) {
|
||||
$existing = $this->upsert_by_key( $existing, $record['key'] ?? '', $record, 'key' );
|
||||
}
|
||||
|
||||
return array_values( $existing );
|
||||
}
|
||||
|
||||
private function upsert_by_key( $records, $current_key, $record, $key_field ) {
|
||||
$updated = false;
|
||||
foreach ( $records as $index => $existing ) {
|
||||
if ( ( $existing[ $key_field ] ?? '' ) === $current_key ) {
|
||||
$records[ $index ] = $record;
|
||||
$updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $updated ) {
|
||||
$records[] = $record;
|
||||
}
|
||||
|
||||
return array_values( $records );
|
||||
}
|
||||
|
||||
|
||||
private function sanitize_cpt_request() {
|
||||
$supports = isset( $_POST['supports'] ) && is_array( $_POST['supports'] ) ? array_map( 'sanitize_key', wp_unslash( $_POST['supports'] ) ) : array();
|
||||
$taxonomies = isset( $_POST['taxonomies'] ) && is_array( $_POST['taxonomies'] ) ? array_map( 'sanitize_key', wp_unslash( $_POST['taxonomies'] ) ) : array();
|
||||
$custom_fields = $this->sanitize_custom_fields();
|
||||
$template_settings = array(
|
||||
'single_mode' => sanitize_key( wp_unslash( $_POST['single_mode'] ?? 'plugin' ) ),
|
||||
'archive_mode' => sanitize_key( wp_unslash( $_POST['archive_mode'] ?? 'plugin' ) ),
|
||||
'single_show_featured' => ! empty( $_POST['single_show_featured'] ) ? 1 : 0,
|
||||
'single_show_meta' => ! empty( $_POST['single_show_meta'] ) ? 1 : 0,
|
||||
'single_show_terms' => ! empty( $_POST['single_show_terms'] ) ? 1 : 0,
|
||||
'single_show_custom_fields' => ! empty( $_POST['single_show_custom_fields'] ) ? 1 : 0,
|
||||
'archive_show_featured' => ! empty( $_POST['archive_show_featured'] ) ? 1 : 0,
|
||||
'archive_show_excerpt' => ! empty( $_POST['archive_show_excerpt'] ) ? 1 : 0,
|
||||
'archive_show_meta' => ! empty( $_POST['archive_show_meta'] ) ? 1 : 0,
|
||||
'archive_columns' => absint( wp_unslash( $_POST['archive_columns'] ?? 3 ) ),
|
||||
'archive_intro' => sanitize_textarea_field( wp_unslash( $_POST['archive_intro'] ?? '' ) ),
|
||||
);
|
||||
|
||||
return $this->plugin->normalize_cpt_record(
|
||||
array(
|
||||
'key' => sanitize_key( wp_unslash( $_POST['key'] ?? '' ) ),
|
||||
'singular_label' => sanitize_text_field( wp_unslash( $_POST['singular_label'] ?? '' ) ),
|
||||
'plural_label' => sanitize_text_field( wp_unslash( $_POST['plural_label'] ?? '' ) ),
|
||||
'slug' => sanitize_title( wp_unslash( $_POST['slug'] ?? '' ) ),
|
||||
'exclude_from_search' => ! empty( $_POST['exclude_from_search'] ) ? 1 : 0,
|
||||
'can_export' => ! empty( $_POST['can_export'] ) ? 1 : 0,
|
||||
'supports' => $supports,
|
||||
'taxonomies' => $taxonomies,
|
||||
'custom_fields' => $custom_fields,
|
||||
'template_settings' => $template_settings,
|
||||
'is_override' => ! empty( $_POST['is_override'] ) ? 1 : 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private function sanitize_taxonomy_request() {
|
||||
$object_type = isset( $_POST['object_type'] ) && is_array( $_POST['object_type'] ) ? array_map( 'sanitize_key', wp_unslash( $_POST['object_type'] ) ) : array();
|
||||
$template_settings = array(
|
||||
'archive_mode' => sanitize_key( wp_unslash( $_POST['archive_mode'] ?? 'plugin' ) ),
|
||||
'archive_show_featured' => ! empty( $_POST['archive_show_featured'] ) ? 1 : 0,
|
||||
'archive_show_excerpt' => ! empty( $_POST['archive_show_excerpt'] ) ? 1 : 0,
|
||||
'archive_show_meta' => ! empty( $_POST['archive_show_meta'] ) ? 1 : 0,
|
||||
'archive_columns' => absint( wp_unslash( $_POST['archive_columns'] ?? 3 ) ),
|
||||
'archive_intro' => sanitize_textarea_field( wp_unslash( $_POST['archive_intro'] ?? '' ) ),
|
||||
);
|
||||
|
||||
return $this->plugin->normalize_taxonomy_record(
|
||||
array(
|
||||
'key' => sanitize_key( wp_unslash( $_POST['key'] ?? '' ) ),
|
||||
'singular_label' => sanitize_text_field( wp_unslash( $_POST['singular_label'] ?? '' ) ),
|
||||
'plural_label' => sanitize_text_field( wp_unslash( $_POST['plural_label'] ?? '' ) ),
|
||||
'slug' => sanitize_title( wp_unslash( $_POST['slug'] ?? '' ) ),
|
||||
'hierarchical' => ! empty( $_POST['hierarchical'] ) ? 1 : 0,
|
||||
'object_type' => $object_type,
|
||||
'template_settings' => $template_settings,
|
||||
'is_override' => ! empty( $_POST['is_override'] ) ? 1 : 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private function sanitize_custom_fields() {
|
||||
$labels = isset( $_POST['field_label'] ) && is_array( $_POST['field_label'] ) ? wp_unslash( $_POST['field_label'] ) : array();
|
||||
$keys = isset( $_POST['field_key'] ) && is_array( $_POST['field_key'] ) ? wp_unslash( $_POST['field_key'] ) : array();
|
||||
$types = isset( $_POST['field_type'] ) && is_array( $_POST['field_type'] ) ? wp_unslash( $_POST['field_type'] ) : array();
|
||||
$descriptions = isset( $_POST['field_description'] ) && is_array( $_POST['field_description'] ) ? wp_unslash( $_POST['field_description'] ) : array();
|
||||
$options = isset( $_POST['field_options'] ) && is_array( $_POST['field_options'] ) ? wp_unslash( $_POST['field_options'] ) : array();
|
||||
$custom_fields = array();
|
||||
|
||||
foreach ( $keys as $index => $key ) {
|
||||
$key = sanitize_key( $key );
|
||||
if ( ! $key ) {
|
||||
continue;
|
||||
}
|
||||
$raw_options = preg_split( '/[
|
||||
,]+/', (string) ( $options[ $index ] ?? '' ) );
|
||||
$normalized_options = array();
|
||||
foreach ( $raw_options as $option ) {
|
||||
$option = sanitize_text_field( $option );
|
||||
if ( '' !== $option ) {
|
||||
$normalized_options[] = $option;
|
||||
}
|
||||
}
|
||||
$custom_fields[] = array(
|
||||
'label' => sanitize_text_field( $labels[ $index ] ?? '' ),
|
||||
'key' => $key,
|
||||
'type' => sanitize_key( $types[ $index ] ?? 'text' ),
|
||||
'description' => sanitize_text_field( $descriptions[ $index ] ?? '' ),
|
||||
'options' => $normalized_options,
|
||||
);
|
||||
}
|
||||
|
||||
return $custom_fields;
|
||||
}
|
||||
|
||||
private function render_page_header( $title, $description, $active_tab ) {
|
||||
?>
|
||||
<div class="wrap ansico-cptax-wrap">
|
||||
<h1><?php echo esc_html( $title ); ?></h1>
|
||||
<p class="ansico-cptax-intro"><?php echo esc_html( $description ); ?></p>
|
||||
<nav class="nav-tab-wrapper ansico-cptax-tabs">
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=ansico-cptax' ) ); ?>" class="nav-tab <?php echo 'cpts' === $active_tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Custom Post Types', 'ansico-cpt-and-taxonomies' ); ?></a>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=ansico-cptax-taxonomies' ) ); ?>" class="nav-tab <?php echo 'taxonomies' === $active_tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Taxonomies', 'ansico-cpt-and-taxonomies' ); ?></a>
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=ansico-cptax-tools' ) ); ?>" class="nav-tab <?php echo 'tools' === $active_tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Tools', 'ansico-cpt-and-taxonomies' ); ?></a>
|
||||
</nav>
|
||||
<?php
|
||||
$this->render_notices();
|
||||
}
|
||||
|
||||
private function render_notices() {
|
||||
if ( ! empty( $_GET['updated'] ) ) {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Saved successfully.', 'ansico-cpt-and-taxonomies' ) . '</p></div>';
|
||||
}
|
||||
if ( ! empty( $_GET['deleted'] ) ) {
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Deleted successfully.', 'ansico-cpt-and-taxonomies' ) . '</p></div>';
|
||||
}
|
||||
if ( ! empty( $_GET['imported'] ) ) {
|
||||
$message = sanitize_text_field( wp_unslash( $_GET['message'] ?? __( 'Import completed.', 'ansico-cpt-and-taxonomies' ) ) );
|
||||
echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $message ) . '</p></div>';
|
||||
}
|
||||
if ( ! empty( $_GET['import_error'] ) ) {
|
||||
$message = sanitize_text_field( wp_unslash( $_GET['message'] ?? __( 'Import failed.', 'ansico-cpt-and-taxonomies' ) ) );
|
||||
echo '<div class="notice notice-error is-dismissible"><p>' . esc_html( $message ) . '</p></div>';
|
||||
}
|
||||
}
|
||||
|
||||
public function render_cpts_page() {
|
||||
$managed = $this->plugin->get_cpts();
|
||||
$overrides = $this->plugin->get_cpt_overrides();
|
||||
$edit_key = sanitize_key( wp_unslash( $_GET['edit'] ?? '' ) );
|
||||
$import_key = sanitize_key( wp_unslash( $_GET['import'] ?? '' ) );
|
||||
$editing = null;
|
||||
|
||||
foreach ( array_merge( $managed, $overrides ) as $record ) {
|
||||
if ( $edit_key && ( $record['key'] ?? '' ) === $edit_key ) {
|
||||
$editing = $record;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $editing && $import_key ) {
|
||||
$all_post_types = $this->plugin->get_editable_post_types();
|
||||
if ( isset( $all_post_types[ $import_key ] ) ) {
|
||||
$editing = $this->map_post_type_object_to_record( $all_post_types[ $import_key ] );
|
||||
$editing['is_override'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$editing = $editing ?: $this->plugin->normalize_cpt_record( array( 'supports' => array( 'title', 'editor' ) ) );
|
||||
$all_taxonomies = $this->plugin->get_editable_taxonomies();
|
||||
$all_post_types = $this->plugin->get_editable_post_types();
|
||||
$field_types = $this->get_field_types();
|
||||
$template_row = $this->get_field_row_template( $field_types );
|
||||
|
||||
$this->render_page_header(
|
||||
__( 'Ansico CPT & Taxonomies', 'ansico-cpt-and-taxonomies' ),
|
||||
__( 'Create new custom post types or import existing post types for plugin-based overrides.', 'ansico-cpt-and-taxonomies' ),
|
||||
'cpts'
|
||||
);
|
||||
?>
|
||||
<div class="ansico-cptax-grid ansico-cptax-grid--wide">
|
||||
<section class="ansico-cptax-card">
|
||||
<div class="ansico-cptax-card__header">
|
||||
<h2><?php echo $edit_key ? esc_html__( 'Edit Custom Post Type', 'ansico-cpt-and-taxonomies' ) : esc_html__( 'Add Custom Post Type', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Define labels, slug, supported features, taxonomies, custom fields, and template behavior.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'ansico_cptax_save' ); ?>
|
||||
<input type="hidden" name="ansico_cptax_action" value="save_cpt">
|
||||
<input type="hidden" name="current_key" value="<?php echo esc_attr( $editing['key'] ?? '' ); ?>">
|
||||
<input type="hidden" name="is_override" value="<?php echo ! empty( $editing['is_override'] ) ? '1' : '0'; ?>">
|
||||
|
||||
<div class="ansico-cptax-form-grid">
|
||||
<div>
|
||||
<label for="key"><strong><?php esc_html_e( 'Post type key', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="key" id="key" type="text" class="regular-text ansico-slug-source" maxlength="20" required value="<?php echo esc_attr( $editing['key'] ?? '' ); ?>" <?php disabled( ! empty( $editing['is_override'] ) ); ?>>
|
||||
<p class="description"><?php esc_html_e( 'Lowercase letters, numbers, dashes, and underscores. Max 20 characters for new post types.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<div>
|
||||
<label for="slug"><strong><?php esc_html_e( 'Slug', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="slug" id="slug" type="text" class="regular-text ansico-slug-target" required value="<?php echo esc_attr( $editing['slug'] ?? '' ); ?>">
|
||||
<p class="description"><?php esc_html_e( 'Used for front-end URLs and archives.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<div>
|
||||
<label for="singular_label"><strong><?php esc_html_e( 'Singular label', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="singular_label" id="singular_label" type="text" class="regular-text" required value="<?php echo esc_attr( $editing['singular_label'] ?? '' ); ?>">
|
||||
</div>
|
||||
<div>
|
||||
<label for="plural_label"><strong><?php esc_html_e( 'Plural label', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="plural_label" id="plural_label" type="text" class="regular-text" required value="<?php echo esc_attr( $editing['plural_label'] ?? '' ); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ansico-cptax-option-columns">
|
||||
<div>
|
||||
<h3><?php esc_html_e( 'Visibility', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
<label><input type="checkbox" name="exclude_from_search" value="1" <?php checked( ! empty( $editing['exclude_from_search'] ) ); ?>> <?php esc_html_e( 'Exclude from search results', 'ansico-cpt-and-taxonomies' ); ?></label><br>
|
||||
<label><input type="checkbox" name="can_export" value="1" <?php checked( ! empty( $editing['can_export'] ) ); ?>> <?php esc_html_e( 'Allow export', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
</div>
|
||||
<div>
|
||||
<h3><?php esc_html_e( 'Supports', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
<?php foreach ( array( 'title' => 'Title', 'editor' => 'Editor', 'thumbnail' => 'Featured image', 'author' => 'Author', 'comments' => 'Comments' ) as $feature => $label ) : ?>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="supports[]" value="<?php echo esc_attr( $feature ); ?>" <?php checked( in_array( $feature, $editing['supports'] ?? array(), true ) ); ?>> <?php echo esc_html( $label ); ?></label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ansico-cptax-card ansico-cptax-card--nested">
|
||||
<div class="ansico-cptax-card__header">
|
||||
<h3><?php esc_html_e( 'Attached taxonomies', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Connect categories, tags, or any existing taxonomy to this post type.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<div class="ansico-checkbox-grid">
|
||||
<?php foreach ( $all_taxonomies as $name => $taxonomy ) : ?>
|
||||
<label><input type="checkbox" name="taxonomies[]" value="<?php echo esc_attr( $name ); ?>" <?php checked( in_array( $name, $editing['taxonomies'] ?? array(), true ) ); ?>> <?php echo esc_html( ( $taxonomy->labels->name ?? $name ) . ' (' . $name . ')' ); ?></label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="ansico-cptax-card ansico-cptax-card--nested">
|
||||
<div class="ansico-cptax-card__header">
|
||||
<h3><?php esc_html_e( 'Template customization', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Choose whether the plugin should supply the front-end templates or leave rendering to your theme.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<?php $template_settings = $editing['template_settings'] ?? array(); ?>
|
||||
<div class="ansico-cptax-form-grid">
|
||||
<div>
|
||||
<label for="single_mode"><strong><?php esc_html_e( 'Single template source', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<select name="single_mode" id="single_mode">
|
||||
<option value="plugin" <?php selected( $template_settings['single_mode'] ?? 'plugin', 'plugin' ); ?>><?php esc_html_e( 'Use plugin template', 'ansico-cpt-and-taxonomies' ); ?></option>
|
||||
<option value="theme" <?php selected( $template_settings['single_mode'] ?? 'plugin', 'theme' ); ?>><?php esc_html_e( 'Let theme handle it', 'ansico-cpt-and-taxonomies' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archive_mode"><strong><?php esc_html_e( 'Archive template source', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<select name="archive_mode" id="archive_mode">
|
||||
<option value="plugin" <?php selected( $template_settings['archive_mode'] ?? 'plugin', 'plugin' ); ?>><?php esc_html_e( 'Use plugin template', 'ansico-cpt-and-taxonomies' ); ?></option>
|
||||
<option value="theme" <?php selected( $template_settings['archive_mode'] ?? 'plugin', 'theme' ); ?>><?php esc_html_e( 'Let theme handle it', 'ansico-cpt-and-taxonomies' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archive_columns"><strong><?php esc_html_e( 'Archive columns', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<select name="archive_columns" id="archive_columns">
|
||||
<?php foreach ( array( 1, 2, 3, 4 ) as $columns ) : ?>
|
||||
<option value="<?php echo esc_attr( $columns ); ?>" <?php selected( (int) ( $template_settings['archive_columns'] ?? 3 ), $columns ); ?>><?php echo esc_html( $columns ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archive_intro"><strong><?php esc_html_e( 'Archive intro text', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<textarea name="archive_intro" id="archive_intro" rows="3" class="large-text"><?php echo esc_textarea( $template_settings['archive_intro'] ?? '' ); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ansico-cptax-option-columns">
|
||||
<div>
|
||||
<h4><?php esc_html_e( 'Single template elements', 'ansico-cpt-and-taxonomies' ); ?></h4>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="single_show_featured" value="1" <?php checked( ! empty( $template_settings['single_show_featured'] ) ); ?>> <?php esc_html_e( 'Show featured image', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="single_show_meta" value="1" <?php checked( ! empty( $template_settings['single_show_meta'] ) ); ?>> <?php esc_html_e( 'Show post meta', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="single_show_terms" value="1" <?php checked( ! empty( $template_settings['single_show_terms'] ) ); ?>> <?php esc_html_e( 'Show attached taxonomy terms', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="single_show_custom_fields" value="1" <?php checked( ! empty( $template_settings['single_show_custom_fields'] ) ); ?>> <?php esc_html_e( 'Show custom fields section', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
</div>
|
||||
<div>
|
||||
<h4><?php esc_html_e( 'Archive template elements', 'ansico-cpt-and-taxonomies' ); ?></h4>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="archive_show_featured" value="1" <?php checked( ! empty( $template_settings['archive_show_featured'] ) ); ?>> <?php esc_html_e( 'Show featured image', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="archive_show_excerpt" value="1" <?php checked( ! empty( $template_settings['archive_show_excerpt'] ) ); ?>> <?php esc_html_e( 'Show excerpt', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="archive_show_meta" value="1" <?php checked( ! empty( $template_settings['archive_show_meta'] ) ); ?>> <?php esc_html_e( 'Show post meta', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="description"><?php esc_html_e( 'When set to theme, WordPress can use single-{post_type}.php or archive-{post_type}.php from the active theme.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="ansico-cptax-card ansico-cptax-card--nested">
|
||||
<div class="ansico-cptax-card__header ansico-cptax-card__header--spread">
|
||||
<div>
|
||||
<h3><?php esc_html_e( 'Custom fields', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Add simple post meta fields. Select and radio fields accept one option per line or comma separated values.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<button type="button" class="button button-secondary" id="ansico-add-field"><?php esc_html_e( 'Add field', 'ansico-cpt-and-taxonomies' ); ?></button>
|
||||
</div>
|
||||
<div class="ansico-cptax-fields-wrap">
|
||||
<table class="widefat striped ansico-cptax-fields-table" id="ansico-fields-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?php esc_html_e( 'Label', 'ansico-cpt-and-taxonomies' ); ?></th>
|
||||
<th><?php esc_html_e( 'Key', 'ansico-cpt-and-taxonomies' ); ?></th>
|
||||
<th><?php esc_html_e( 'Type', 'ansico-cpt-and-taxonomies' ); ?></th>
|
||||
<th><?php esc_html_e( 'Description', 'ansico-cpt-and-taxonomies' ); ?></th>
|
||||
<th><?php esc_html_e( 'Options', 'ansico-cpt-and-taxonomies' ); ?></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if ( ! empty( $editing['custom_fields'] ) ) : ?>
|
||||
<?php foreach ( $editing['custom_fields'] as $field ) : ?>
|
||||
<?php $this->render_field_row( $field, $field_types ); ?>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<script type="text/html" id="tmpl-ansico-field-row"><?php echo $template_row; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php submit_button( $edit_key ? __( 'Save Custom Post Type', 'ansico-cpt-and-taxonomies' ) : __( 'Create Custom Post Type', 'ansico-cpt-and-taxonomies' ) ); ?>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<aside class="ansico-cptax-sidebar">
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Plugin-created post types', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<?php $this->render_cpt_table( $managed, false ); ?>
|
||||
</section>
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Imported / overridden post types', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<?php $this->render_cpt_table( $overrides, true ); ?>
|
||||
</section>
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Available post types to import', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<table class="widefat striped"><thead><tr><th><?php esc_html_e( 'Name', 'ansico-cpt-and-taxonomies' ); ?></th><th><?php esc_html_e( 'Key', 'ansico-cpt-and-taxonomies' ); ?></th><th><?php esc_html_e( 'Action', 'ansico-cpt-and-taxonomies' ); ?></th></tr></thead><tbody>
|
||||
<?php foreach ( $all_post_types as $name => $obj ) : ?>
|
||||
<?php if ( $this->plugin->get_cpt_by_key( $name ) || $this->plugin->get_cpt_override_by_key( $name ) ) { continue; } ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( $obj->labels->name ?? $name ); ?></td>
|
||||
<td><code><?php echo esc_html( $name ); ?></code></td>
|
||||
<td><a class="button button-small" href="<?php echo esc_url( admin_url( 'admin.php?page=ansico-cptax&import=' . $name ) ); ?>"><?php esc_html_e( 'Import', 'ansico-cpt-and-taxonomies' ); ?></a></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody></table>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_taxonomies_page() {
|
||||
$managed = $this->plugin->get_taxonomies();
|
||||
$overrides = $this->plugin->get_taxonomy_overrides();
|
||||
$edit_key = sanitize_key( wp_unslash( $_GET['edit'] ?? '' ) );
|
||||
$import_key = sanitize_key( wp_unslash( $_GET['import'] ?? '' ) );
|
||||
$editing = null;
|
||||
|
||||
foreach ( array_merge( $managed, $overrides ) as $record ) {
|
||||
if ( $edit_key && ( $record['key'] ?? '' ) === $edit_key ) {
|
||||
$editing = $record;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $editing && $import_key ) {
|
||||
$all_taxonomies = $this->plugin->get_editable_taxonomies();
|
||||
if ( isset( $all_taxonomies[ $import_key ] ) ) {
|
||||
$editing = $this->map_taxonomy_object_to_record( $all_taxonomies[ $import_key ] );
|
||||
$editing['is_override'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
$editing = $editing ?: $this->plugin->normalize_taxonomy_record( array( 'object_type' => array( 'post' ) ) );
|
||||
$post_types = $this->plugin->get_editable_post_types();
|
||||
|
||||
$this->render_page_header(
|
||||
__( 'Taxonomies', 'ansico-cpt-and-taxonomies' ),
|
||||
__( 'Create new taxonomies or import existing ones for plugin-based overrides.', 'ansico-cpt-and-taxonomies' ),
|
||||
'taxonomies'
|
||||
);
|
||||
?>
|
||||
<div class="ansico-cptax-grid ansico-cptax-grid--wide">
|
||||
<section class="ansico-cptax-card">
|
||||
<div class="ansico-cptax-card__header">
|
||||
<h2><?php echo $edit_key ? esc_html__( 'Edit Taxonomy', 'ansico-cpt-and-taxonomies' ) : esc_html__( 'Add Taxonomy', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Set labels, slug, hierarchy, connected post types, and archive template behavior.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'ansico_cptax_save' ); ?>
|
||||
<input type="hidden" name="ansico_cptax_action" value="save_taxonomy">
|
||||
<input type="hidden" name="current_key" value="<?php echo esc_attr( $editing['key'] ?? '' ); ?>">
|
||||
<input type="hidden" name="is_override" value="<?php echo ! empty( $editing['is_override'] ) ? '1' : '0'; ?>">
|
||||
|
||||
<div class="ansico-cptax-form-grid">
|
||||
<div>
|
||||
<label for="key"><strong><?php esc_html_e( 'Taxonomy key', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="key" id="key" type="text" class="regular-text ansico-slug-source" maxlength="32" required value="<?php echo esc_attr( $editing['key'] ?? '' ); ?>" <?php disabled( ! empty( $editing['is_override'] ) ); ?>>
|
||||
</div>
|
||||
<div>
|
||||
<label for="slug"><strong><?php esc_html_e( 'Slug', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="slug" id="slug" type="text" class="regular-text ansico-slug-target" required value="<?php echo esc_attr( $editing['slug'] ?? '' ); ?>">
|
||||
</div>
|
||||
<div>
|
||||
<label for="singular_label"><strong><?php esc_html_e( 'Singular label', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="singular_label" id="singular_label" type="text" class="regular-text" required value="<?php echo esc_attr( $editing['singular_label'] ?? '' ); ?>">
|
||||
</div>
|
||||
<div>
|
||||
<label for="plural_label"><strong><?php esc_html_e( 'Plural label', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<input name="plural_label" id="plural_label" type="text" class="regular-text" required value="<?php echo esc_attr( $editing['plural_label'] ?? '' ); ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ansico-cptax-card ansico-cptax-card--nested">
|
||||
<h3><?php esc_html_e( 'Structure', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
<label><input type="checkbox" name="hierarchical" value="1" <?php checked( ! empty( $editing['hierarchical'] ) ); ?>> <?php esc_html_e( 'Hierarchical like categories', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<p class="description"><?php esc_html_e( 'Leave unchecked for tag-like behavior.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="ansico-cptax-card ansico-cptax-card--nested">
|
||||
<div class="ansico-cptax-card__header">
|
||||
<h3><?php esc_html_e( 'Attach to post types', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
</div>
|
||||
<div class="ansico-checkbox-grid">
|
||||
<?php foreach ( $post_types as $post_type ) : ?>
|
||||
<label><input type="checkbox" name="object_type[]" value="<?php echo esc_attr( $post_type->name ); ?>" <?php checked( in_array( $post_type->name, $editing['object_type'] ?? array(), true ) ); ?>> <?php echo esc_html( $post_type->labels->name . ' (' . $post_type->name . ')' ); ?></label>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="ansico-cptax-card ansico-cptax-card--nested">
|
||||
<div class="ansico-cptax-card__header">
|
||||
<h3><?php esc_html_e( 'Archive template customization', 'ansico-cpt-and-taxonomies' ); ?></h3>
|
||||
<p><?php esc_html_e( 'Control the plugin taxonomy archive layout or hand template rendering back to your theme.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
<?php $template_settings = $editing['template_settings'] ?? array(); ?>
|
||||
<div class="ansico-cptax-form-grid">
|
||||
<div>
|
||||
<label for="archive_mode"><strong><?php esc_html_e( 'Archive template source', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<select name="archive_mode" id="archive_mode">
|
||||
<option value="plugin" <?php selected( $template_settings['archive_mode'] ?? 'plugin', 'plugin' ); ?>><?php esc_html_e( 'Use plugin template', 'ansico-cpt-and-taxonomies' ); ?></option>
|
||||
<option value="theme" <?php selected( $template_settings['archive_mode'] ?? 'plugin', 'theme' ); ?>><?php esc_html_e( 'Let theme handle it', 'ansico-cpt-and-taxonomies' ); ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archive_columns"><strong><?php esc_html_e( 'Archive columns', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<select name="archive_columns" id="archive_columns">
|
||||
<?php foreach ( array( 1, 2, 3, 4 ) as $columns ) : ?>
|
||||
<option value="<?php echo esc_attr( $columns ); ?>" <?php selected( (int) ( $template_settings['archive_columns'] ?? 3 ), $columns ); ?>><?php echo esc_html( $columns ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archive_intro"><strong><?php esc_html_e( 'Archive intro text', 'ansico-cpt-and-taxonomies' ); ?></strong></label>
|
||||
<textarea name="archive_intro" id="archive_intro" rows="3" class="large-text"><?php echo esc_textarea( $template_settings['archive_intro'] ?? '' ); ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ansico-cptax-option-columns">
|
||||
<div>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="archive_show_featured" value="1" <?php checked( ! empty( $template_settings['archive_show_featured'] ) ); ?>> <?php esc_html_e( 'Show featured image', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="archive_show_excerpt" value="1" <?php checked( ! empty( $template_settings['archive_show_excerpt'] ) ); ?>> <?php esc_html_e( 'Show excerpt', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
<label class="ansico-inline-option"><input type="checkbox" name="archive_show_meta" value="1" <?php checked( ! empty( $template_settings['archive_show_meta'] ) ); ?>> <?php esc_html_e( 'Show post meta', 'ansico-cpt-and-taxonomies' ); ?></label>
|
||||
</div>
|
||||
</div>
|
||||
<p class="description"><?php esc_html_e( 'When set to theme, WordPress can use taxonomy-{taxonomy}.php or related archive templates from the active theme.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
</div>
|
||||
|
||||
<?php submit_button( $edit_key ? __( 'Save Taxonomy', 'ansico-cpt-and-taxonomies' ) : __( 'Create Taxonomy', 'ansico-cpt-and-taxonomies' ) ); ?>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<aside class="ansico-cptax-sidebar">
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Plugin-created taxonomies', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<?php $this->render_taxonomy_table( $managed, false ); ?>
|
||||
</section>
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Imported / overridden taxonomies', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<?php $this->render_taxonomy_table( $overrides, true ); ?>
|
||||
</section>
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Available taxonomies to import', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<table class="widefat striped"><thead><tr><th><?php esc_html_e( 'Name', 'ansico-cpt-and-taxonomies' ); ?></th><th><?php esc_html_e( 'Key', 'ansico-cpt-and-taxonomies' ); ?></th><th><?php esc_html_e( 'Action', 'ansico-cpt-and-taxonomies' ); ?></th></tr></thead><tbody>
|
||||
<?php foreach ( $this->plugin->get_editable_taxonomies() as $name => $obj ) : ?>
|
||||
<?php if ( $this->plugin->get_taxonomy_by_key( $name ) || $this->plugin->get_taxonomy_override_by_key( $name ) ) { continue; } ?>
|
||||
<tr>
|
||||
<td><?php echo esc_html( $obj->labels->name ?? $name ); ?></td>
|
||||
<td><code><?php echo esc_html( $name ); ?></code></td>
|
||||
<td><a class="button button-small" href="<?php echo esc_url( admin_url( 'admin.php?page=ansico-cptax-taxonomies&import=' . $name ) ); ?>"><?php esc_html_e( 'Import', 'ansico-cpt-and-taxonomies' ); ?></a></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody></table>
|
||||
</section>
|
||||
</aside>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
public function render_tools_page() {
|
||||
$payload = $this->plugin->get_export_payload();
|
||||
$this->render_page_header(
|
||||
__( 'Tools', 'ansico-cpt-and-taxonomies' ),
|
||||
__( 'Export or import plugin-managed custom post types, taxonomies, overrides, and custom fields as JSON.', 'ansico-cpt-and-taxonomies' ),
|
||||
'tools'
|
||||
);
|
||||
?>
|
||||
<div class="ansico-cptax-grid">
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Export JSON', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Download a JSON snapshot of all plugin-managed registrations and overrides.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
<ul class="ansico-cptax-stat-list">
|
||||
<li><?php echo esc_html( sprintf( __( '%d custom post types', 'ansico-cpt-and-taxonomies' ), count( $payload['cpts'] ) ) ); ?></li>
|
||||
<li><?php echo esc_html( sprintf( __( '%d taxonomies', 'ansico-cpt-and-taxonomies' ), count( $payload['taxonomies'] ) ) ); ?></li>
|
||||
<li><?php echo esc_html( sprintf( __( '%d post type overrides', 'ansico-cpt-and-taxonomies' ), count( $payload['cpt_overrides'] ) ) ); ?></li>
|
||||
<li><?php echo esc_html( sprintf( __( '%d taxonomy overrides', 'ansico-cpt-and-taxonomies' ), count( $payload['taxonomy_overrides'] ) ) ); ?></li>
|
||||
</ul>
|
||||
<form method="post">
|
||||
<?php wp_nonce_field( 'ansico_cptax_export' ); ?>
|
||||
<input type="hidden" name="ansico_cptax_action" value="export_json">
|
||||
<?php submit_button( __( 'Download JSON export', 'ansico-cpt-and-taxonomies' ), 'primary', 'submit', false ); ?>
|
||||
</form>
|
||||
</section>
|
||||
<section class="ansico-cptax-card">
|
||||
<h2><?php esc_html_e( 'Import JSON', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Import a previously exported JSON file. You can merge it with current plugin data or replace everything.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
<form method="post" enctype="multipart/form-data">
|
||||
<?php wp_nonce_field( 'ansico_cptax_save' ); ?>
|
||||
<input type="hidden" name="ansico_cptax_action" value="import_json">
|
||||
<p><input type="file" name="import_file" accept="application/json,.json" required></p>
|
||||
<p><label><input type="checkbox" name="replace_existing" value="1"> <?php esc_html_e( 'Replace current plugin data instead of merging by key', 'ansico-cpt-and-taxonomies' ); ?></label></p>
|
||||
<?php submit_button( __( 'Import JSON', 'ansico-cpt-and-taxonomies' ), 'secondary', 'submit', false ); ?>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private function render_cpt_table( $records, $is_override ) {
|
||||
echo '<table class="widefat striped"><thead><tr><th>' . esc_html__( 'Name', 'ansico-cpt-and-taxonomies' ) . '</th><th>' . esc_html__( 'Key', 'ansico-cpt-and-taxonomies' ) . '</th><th>' . esc_html__( 'Slug', 'ansico-cpt-and-taxonomies' ) . '</th><th>' . esc_html__( 'Actions', 'ansico-cpt-and-taxonomies' ) . '</th></tr></thead><tbody>';
|
||||
if ( empty( $records ) ) {
|
||||
echo '<tr><td colspan="4">' . esc_html__( 'No items found.', 'ansico-cpt-and-taxonomies' ) . '</td></tr>';
|
||||
} else {
|
||||
foreach ( $records as $cpt ) {
|
||||
echo '<tr>';
|
||||
echo '<td>' . esc_html( $cpt['plural_label'] ?? $cpt['key'] ) . '</td>';
|
||||
echo '<td><code>' . esc_html( $cpt['key'] ?? '' ) . '</code></td>';
|
||||
echo '<td>' . esc_html( $cpt['slug'] ?? '' ) . '</td>';
|
||||
echo '<td><a class="button button-small" href="' . esc_url( admin_url( 'admin.php?page=ansico-cptax&edit=' . ( $cpt['key'] ?? '' ) ) ) . '">' . esc_html__( 'Edit', 'ansico-cpt-and-taxonomies' ) . '</a> ';
|
||||
echo '<form method="post" style="display:inline;">';
|
||||
wp_nonce_field( 'ansico_cptax_save' );
|
||||
echo '<input type="hidden" name="ansico_cptax_action" value="delete_cpt">';
|
||||
echo '<input type="hidden" name="key" value="' . esc_attr( $cpt['key'] ?? '' ) . '">';
|
||||
echo '<input type="hidden" name="is_override" value="' . ( $is_override ? '1' : '0' ) . '">';
|
||||
submit_button( __( 'Delete', 'ansico-cpt-and-taxonomies' ), 'delete small', '', false, array( 'onclick' => "return confirm('Are you sure?');" ) );
|
||||
echo '</form></td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
private function render_taxonomy_table( $records, $is_override ) {
|
||||
echo '<table class="widefat striped"><thead><tr><th>' . esc_html__( 'Name', 'ansico-cpt-and-taxonomies' ) . '</th><th>' . esc_html__( 'Key', 'ansico-cpt-and-taxonomies' ) . '</th><th>' . esc_html__( 'Slug', 'ansico-cpt-and-taxonomies' ) . '</th><th>' . esc_html__( 'Actions', 'ansico-cpt-and-taxonomies' ) . '</th></tr></thead><tbody>';
|
||||
if ( empty( $records ) ) {
|
||||
echo '<tr><td colspan="4">' . esc_html__( 'No items found.', 'ansico-cpt-and-taxonomies' ) . '</td></tr>';
|
||||
} else {
|
||||
foreach ( $records as $taxonomy ) {
|
||||
echo '<tr>';
|
||||
echo '<td>' . esc_html( $taxonomy['plural_label'] ?? $taxonomy['key'] ) . '</td>';
|
||||
echo '<td><code>' . esc_html( $taxonomy['key'] ?? '' ) . '</code></td>';
|
||||
echo '<td>' . esc_html( $taxonomy['slug'] ?? '' ) . '</td>';
|
||||
echo '<td><a class="button button-small" href="' . esc_url( admin_url( 'admin.php?page=ansico-cptax-taxonomies&edit=' . ( $taxonomy['key'] ?? '' ) ) ) . '">' . esc_html__( 'Edit', 'ansico-cpt-and-taxonomies' ) . '</a> ';
|
||||
echo '<form method="post" style="display:inline;">';
|
||||
wp_nonce_field( 'ansico_cptax_save' );
|
||||
echo '<input type="hidden" name="ansico_cptax_action" value="delete_taxonomy">';
|
||||
echo '<input type="hidden" name="key" value="' . esc_attr( $taxonomy['key'] ?? '' ) . '">';
|
||||
echo '<input type="hidden" name="is_override" value="' . ( $is_override ? '1' : '0' ) . '">';
|
||||
submit_button( __( 'Delete', 'ansico-cpt-and-taxonomies' ), 'delete small', '', false, array( 'onclick' => "return confirm('Are you sure?');" ) );
|
||||
echo '</form></td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
private function get_field_types() {
|
||||
return array(
|
||||
'text' => __( 'Text', 'ansico-cpt-and-taxonomies' ),
|
||||
'textarea' => __( 'Textarea', 'ansico-cpt-and-taxonomies' ),
|
||||
'number' => __( 'Number', 'ansico-cpt-and-taxonomies' ),
|
||||
'url' => __( 'URL', 'ansico-cpt-and-taxonomies' ),
|
||||
'email' => __( 'Email', 'ansico-cpt-and-taxonomies' ),
|
||||
'date' => __( 'Date', 'ansico-cpt-and-taxonomies' ),
|
||||
'checkbox' => __( 'Checkbox', 'ansico-cpt-and-taxonomies' ),
|
||||
'select' => __( 'Select', 'ansico-cpt-and-taxonomies' ),
|
||||
'radio' => __( 'Radio', 'ansico-cpt-and-taxonomies' ),
|
||||
);
|
||||
}
|
||||
|
||||
private function render_field_row( $field, $field_types ) {
|
||||
echo $this->get_field_row_markup( $field, $field_types ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
}
|
||||
|
||||
private function get_field_row_template( $field_types ) {
|
||||
return str_replace( array( "\n", "\r", "\t" ), '', $this->get_field_row_markup( array(), $field_types ) );
|
||||
}
|
||||
|
||||
private function get_field_row_markup( $field, $field_types ) {
|
||||
ob_start();
|
||||
?>
|
||||
<tr class="ansico-field-row">
|
||||
<td><input type="text" class="regular-text" name="field_label[]" value="<?php echo esc_attr( $field['label'] ?? '' ); ?>" placeholder="<?php esc_attr_e( 'Field label', 'ansico-cpt-and-taxonomies' ); ?>"></td>
|
||||
<td><input type="text" class="regular-text ansico-field-key" name="field_key[]" value="<?php echo esc_attr( $field['key'] ?? '' ); ?>" placeholder="<?php esc_attr_e( 'field_key', 'ansico-cpt-and-taxonomies' ); ?>"></td>
|
||||
<td>
|
||||
<select name="field_type[]" class="ansico-field-type">
|
||||
<?php foreach ( $field_types as $type_key => $type_label ) : ?>
|
||||
<option value="<?php echo esc_attr( $type_key ); ?>" <?php selected( $field['type'] ?? 'text', $type_key ); ?>><?php echo esc_html( $type_label ); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</td>
|
||||
<td><input type="text" class="regular-text" name="field_description[]" value="<?php echo esc_attr( $field['description'] ?? '' ); ?>" placeholder="<?php esc_attr_e( 'Help text shown below the field', 'ansico-cpt-and-taxonomies' ); ?>"></td>
|
||||
<td><textarea name="field_options[]" rows="3" class="large-text ansico-field-options" placeholder="<?php esc_attr_e( 'Only for select/radio. One option per line or comma separated.', 'ansico-cpt-and-taxonomies' ); ?>"><?php echo esc_textarea( ! empty( $field['options'] ) && is_array( $field['options'] ) ? implode( "\n", $field['options'] ) : '' ); ?></textarea></td>
|
||||
<td><button type="button" class="button-link-delete ansico-remove-field"><?php esc_html_e( 'Remove', 'ansico-cpt-and-taxonomies' ); ?></button></td>
|
||||
</tr>
|
||||
<?php
|
||||
return (string) ob_get_clean();
|
||||
}
|
||||
|
||||
private function map_post_type_object_to_record( $obj ) {
|
||||
$supports = array();
|
||||
foreach ( array( 'title', 'editor', 'thumbnail', 'author', 'comments' ) as $feature ) {
|
||||
if ( post_type_supports( $obj->name, $feature ) ) {
|
||||
$supports[] = $feature;
|
||||
}
|
||||
}
|
||||
|
||||
$taxonomies = get_object_taxonomies( $obj->name, 'names' );
|
||||
|
||||
return $this->plugin->normalize_cpt_record(
|
||||
array(
|
||||
'key' => $obj->name,
|
||||
'singular_label' => $obj->labels->singular_name ?? $obj->name,
|
||||
'plural_label' => $obj->labels->name ?? $obj->name,
|
||||
'slug' => is_array( $obj->rewrite ) && ! empty( $obj->rewrite['slug'] ) ? $obj->rewrite['slug'] : $obj->name,
|
||||
'exclude_from_search' => ! empty( $obj->exclude_from_search ) ? 1 : 0,
|
||||
'can_export' => ! empty( $obj->can_export ) ? 1 : 0,
|
||||
'supports' => $supports,
|
||||
'taxonomies' => is_array( $taxonomies ) ? $taxonomies : array(),
|
||||
'custom_fields' => array(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private function map_taxonomy_object_to_record( $obj ) {
|
||||
return $this->plugin->normalize_taxonomy_record(
|
||||
array(
|
||||
'key' => $obj->name,
|
||||
'singular_label' => $obj->labels->singular_name ?? $obj->name,
|
||||
'plural_label' => $obj->labels->name ?? $obj->name,
|
||||
'slug' => is_array( $obj->rewrite ) && ! empty( $obj->rewrite['slug'] ) ? $obj->rewrite['slug'] : $obj->name,
|
||||
'hierarchical' => ! empty( $obj->hierarchical ) ? 1 : 0,
|
||||
'object_type' => is_array( $obj->object_type ) ? $obj->object_type : array(),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Binary file not shown.
32
ansico-cpt-and-taxonomies/ansico-cpt-and-taxonomies.php
Normal file
32
ansico-cpt-and-taxonomies/ansico-cpt-and-taxonomies.php
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Plugin Name: Ansico CPT and Taxonomies
|
||||
* Plugin URI: https://ansico.dk/
|
||||
* Description: Create and manage custom post types, taxonomies, and custom fields from the WordPress admin.
|
||||
* Version: 0.0.0.4
|
||||
* Author: Andreas Andersen (Ansico)
|
||||
* Author URI: https://ansico.dk
|
||||
* Text Domain: ansico-cpt-and-taxonomies
|
||||
* Requires at least: 6.0
|
||||
* Requires PHP: 7.4
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
define( 'ANSICO_CPTAX_VERSION', '0.0.0.4' );
|
||||
define( 'ANSICO_CPTAX_FILE', __FILE__ );
|
||||
define( 'ANSICO_CPTAX_PATH', plugin_dir_path( __FILE__ ) );
|
||||
define( 'ANSICO_CPTAX_URL', plugin_dir_url( __FILE__ ) );
|
||||
|
||||
require_once ANSICO_CPTAX_PATH . 'includes/class-ansico-cptax-plugin.php';
|
||||
|
||||
function ansico_cptax() {
|
||||
return Ansico_CPTax_Plugin::instance();
|
||||
}
|
||||
|
||||
ansico_cptax();
|
||||
|
||||
register_activation_hook( __FILE__, array( 'Ansico_CPTax_Plugin', 'activate' ) );
|
||||
register_deactivation_hook( __FILE__, array( 'Ansico_CPTax_Plugin', 'deactivate' ) );
|
||||
Binary file not shown.
124
ansico-cpt-and-taxonomies/assets/admin.css
Normal file
124
ansico-cpt-and-taxonomies/assets/admin.css
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
.ansico-cptax-wrap {
|
||||
max-width: 1440px;
|
||||
}
|
||||
|
||||
.ansico-cptax-intro {
|
||||
max-width: 900px;
|
||||
}
|
||||
|
||||
.ansico-cptax-tabs {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.ansico-cptax-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.ansico-cptax-grid--wide {
|
||||
grid-template-columns: minmax(0, 1.65fr) minmax(320px, 1fr);
|
||||
}
|
||||
|
||||
.ansico-cptax-sidebar,
|
||||
.ansico-cptax-grid > section,
|
||||
.ansico-cptax-grid > aside {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
align-content: start;
|
||||
}
|
||||
|
||||
.ansico-cptax-card {
|
||||
background: #fff;
|
||||
border: 1px solid #dcdcde;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,.04);
|
||||
}
|
||||
|
||||
.ansico-cptax-card--nested {
|
||||
margin-top: 20px;
|
||||
background: #fcfcfd;
|
||||
}
|
||||
|
||||
.ansico-cptax-card__header {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.ansico-cptax-card__header h2,
|
||||
.ansico-cptax-card__header h3,
|
||||
.ansico-cptax-card h2,
|
||||
.ansico-cptax-card h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.ansico-cptax-card__header--spread {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.ansico-cptax-form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(220px, 1fr));
|
||||
gap: 18px;
|
||||
}
|
||||
|
||||
.ansico-cptax-form-grid input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ansico-cptax-option-columns {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(220px, 1fr));
|
||||
gap: 20px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.ansico-inline-option,
|
||||
.ansico-checkbox-grid label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.ansico-checkbox-grid {
|
||||
columns: 2 260px;
|
||||
}
|
||||
|
||||
.ansico-cptax-fields-wrap {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.ansico-cptax-fields-table td,
|
||||
.ansico-cptax-fields-table th {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.ansico-cptax-fields-table textarea,
|
||||
.ansico-cptax-fields-table select,
|
||||
.ansico-cptax-fields-table input[type="text"] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ansico-cptax-stat-list {
|
||||
margin: 0 0 18px 18px;
|
||||
}
|
||||
|
||||
@media (max-width: 1100px) {
|
||||
.ansico-cptax-grid--wide {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 782px) {
|
||||
.ansico-cptax-form-grid,
|
||||
.ansico-cptax-option-columns {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.ansico-cptax-card__header--spread {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
BIN
ansico-cpt-and-taxonomies/assets/admin.css:Zone.Identifier
Normal file
BIN
ansico-cpt-and-taxonomies/assets/admin.css:Zone.Identifier
Normal file
Binary file not shown.
54
ansico-cpt-and-taxonomies/assets/admin.js
Normal file
54
ansico-cpt-and-taxonomies/assets/admin.js
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
(function () {
|
||||
function slugify(value) {
|
||||
return (value || '')
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.trim()
|
||||
.replace(/[^a-z0-9-_\s]/g, '')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/-+/g, '-');
|
||||
}
|
||||
|
||||
function bindSlugHelpers() {
|
||||
document.querySelectorAll('.ansico-slug-source').forEach(function (source) {
|
||||
var form = source.closest('form');
|
||||
if (!form) return;
|
||||
var target = form.querySelector('.ansico-slug-target');
|
||||
if (!target || target.value) return;
|
||||
source.addEventListener('input', function () {
|
||||
if (!target.dataset.userEdited) {
|
||||
target.value = slugify(source.value);
|
||||
}
|
||||
});
|
||||
target.addEventListener('input', function () {
|
||||
if (target.value) {
|
||||
target.dataset.userEdited = '1';
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function bindFieldRows() {
|
||||
var addButton = document.getElementById('ansico-add-field');
|
||||
var tableBody = document.querySelector('#ansico-fields-table tbody');
|
||||
var template = document.getElementById('tmpl-ansico-field-row');
|
||||
if (!addButton || !tableBody || !template) return;
|
||||
|
||||
addButton.addEventListener('click', function () {
|
||||
tableBody.insertAdjacentHTML('beforeend', template.innerHTML);
|
||||
});
|
||||
|
||||
tableBody.addEventListener('click', function (event) {
|
||||
var removeButton = event.target.closest('.ansico-remove-field');
|
||||
if (removeButton) {
|
||||
var row = removeButton.closest('.ansico-field-row');
|
||||
if (row) row.remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
bindSlugHelpers();
|
||||
bindFieldRows();
|
||||
});
|
||||
})();
|
||||
BIN
ansico-cpt-and-taxonomies/assets/admin.js:Zone.Identifier
Normal file
BIN
ansico-cpt-and-taxonomies/assets/admin.js:Zone.Identifier
Normal file
Binary file not shown.
601
ansico-cpt-and-taxonomies/includes/class-ansico-cptax-plugin.php
Normal file
601
ansico-cpt-and-taxonomies/includes/class-ansico-cptax-plugin.php
Normal file
|
|
@ -0,0 +1,601 @@
|
|||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class Ansico_CPTax_Plugin {
|
||||
const CPT_OPTION = 'ansico_cptax_cpts';
|
||||
const TAX_OPTION = 'ansico_cptax_taxonomies';
|
||||
const CPT_OVERRIDE_OPTION = 'ansico_cptax_cpt_overrides';
|
||||
const TAX_OVERRIDE_OPTION = 'ansico_cptax_taxonomy_overrides';
|
||||
|
||||
private static $instance = null;
|
||||
|
||||
public static function instance() {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'register_taxonomies' ), 5 );
|
||||
add_filter( 'register_taxonomy_args', array( $this, 'filter_taxonomy_args' ), 20, 2 );
|
||||
add_action( 'init', array( $this, 'register_post_types' ), 10 );
|
||||
add_filter( 'register_post_type_args', array( $this, 'filter_post_type_args' ), 20, 2 );
|
||||
add_action( 'init', array( $this, 'attach_overridden_taxonomies_to_objects' ), 99 );
|
||||
add_action( 'add_meta_boxes', array( $this, 'register_meta_boxes' ) );
|
||||
add_action( 'save_post', array( $this, 'save_custom_fields' ) );
|
||||
add_filter( 'template_include', array( $this, 'template_include' ) );
|
||||
|
||||
if ( is_admin() ) {
|
||||
require_once ANSICO_CPTAX_PATH . 'admin/class-ansico-cptax-admin.php';
|
||||
Ansico_CPTax_Admin::instance( $this );
|
||||
}
|
||||
}
|
||||
|
||||
public static function activate() {
|
||||
self::instance()->register_taxonomies();
|
||||
self::instance()->register_post_types();
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
public static function deactivate() {
|
||||
flush_rewrite_rules();
|
||||
}
|
||||
|
||||
public function get_cpts() {
|
||||
$cpts = get_option( self::CPT_OPTION, array() );
|
||||
return is_array( $cpts ) ? array_map( array( $this, 'normalize_cpt_record' ), $cpts ) : array();
|
||||
}
|
||||
|
||||
public function get_taxonomies() {
|
||||
$taxonomies = get_option( self::TAX_OPTION, array() );
|
||||
return is_array( $taxonomies ) ? array_map( array( $this, 'normalize_taxonomy_record' ), $taxonomies ) : array();
|
||||
}
|
||||
|
||||
public function get_cpt_overrides() {
|
||||
$cpts = get_option( self::CPT_OVERRIDE_OPTION, array() );
|
||||
return is_array( $cpts ) ? array_map( array( $this, 'normalize_cpt_record' ), $cpts ) : array();
|
||||
}
|
||||
|
||||
public function get_taxonomy_overrides() {
|
||||
$tax = get_option( self::TAX_OVERRIDE_OPTION, array() );
|
||||
return is_array( $tax ) ? array_map( array( $this, 'normalize_taxonomy_record' ), $tax ) : array();
|
||||
}
|
||||
|
||||
public function save_cpts( $cpts ) {
|
||||
update_option( self::CPT_OPTION, array_values( array_map( array( $this, 'normalize_cpt_record' ), $cpts ) ), false );
|
||||
}
|
||||
|
||||
public function save_taxonomies( $taxonomies ) {
|
||||
update_option( self::TAX_OPTION, array_values( array_map( array( $this, 'normalize_taxonomy_record' ), $taxonomies ) ), false );
|
||||
}
|
||||
|
||||
public function save_cpt_overrides( $cpts ) {
|
||||
update_option( self::CPT_OVERRIDE_OPTION, array_values( array_map( array( $this, 'normalize_cpt_record' ), $cpts ) ), false );
|
||||
}
|
||||
|
||||
public function save_taxonomy_overrides( $taxonomies ) {
|
||||
update_option( self::TAX_OVERRIDE_OPTION, array_values( array_map( array( $this, 'normalize_taxonomy_record' ), $taxonomies ) ), false );
|
||||
}
|
||||
|
||||
public function normalize_cpt_record( $record ) {
|
||||
$record = is_array( $record ) ? $record : array();
|
||||
$custom_fields = array();
|
||||
|
||||
if ( ! empty( $record['custom_fields'] ) && is_array( $record['custom_fields'] ) ) {
|
||||
foreach ( $record['custom_fields'] as $field ) {
|
||||
if ( ! is_array( $field ) ) {
|
||||
continue;
|
||||
}
|
||||
$type = sanitize_key( $field['type'] ?? 'text' );
|
||||
if ( ! in_array( $type, array( 'text', 'textarea', 'number', 'url', 'email', 'date', 'checkbox', 'select', 'radio' ), true ) ) {
|
||||
$type = 'text';
|
||||
}
|
||||
$options = array();
|
||||
if ( ! empty( $field['options'] ) && is_array( $field['options'] ) ) {
|
||||
foreach ( $field['options'] as $option ) {
|
||||
$option = sanitize_text_field( $option );
|
||||
if ( '' !== $option ) {
|
||||
$options[] = $option;
|
||||
}
|
||||
}
|
||||
}
|
||||
$custom_fields[] = array(
|
||||
'label' => sanitize_text_field( $field['label'] ?? '' ),
|
||||
'key' => sanitize_key( $field['key'] ?? '' ),
|
||||
'type' => $type,
|
||||
'description' => sanitize_text_field( $field['description'] ?? '' ),
|
||||
'options' => $options,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$template_settings = $this->normalize_cpt_template_settings( $record['template_settings'] ?? array() );
|
||||
|
||||
|
||||
return array(
|
||||
'key' => sanitize_key( $record['key'] ?? '' ),
|
||||
'singular_label' => sanitize_text_field( $record['singular_label'] ?? '' ),
|
||||
'plural_label' => sanitize_text_field( $record['plural_label'] ?? '' ),
|
||||
'slug' => sanitize_title( $record['slug'] ?? '' ),
|
||||
'hierarchical' => ! empty( $record['hierarchical'] ) ? 1 : 0,
|
||||
'object_type' => ! empty( $record['object_type'] ) && is_array( $record['object_type'] ) ? array_values( array_unique( array_map( 'sanitize_key', $record['object_type'] ) ) ) : array(),
|
||||
'template_settings' => $this->normalize_taxonomy_template_settings( $record['template_settings'] ?? array() ),
|
||||
'is_override' => ! empty( $record['is_override'] ) ? 1 : 0,
|
||||
);
|
||||
}
|
||||
|
||||
public function normalize_taxonomy_record( $record ) {
|
||||
$record = is_array( $record ) ? $record : array();
|
||||
|
||||
|
||||
$template_settings = $this->normalize_cpt_template_settings( $record['template_settings'] ?? array() );
|
||||
|
||||
|
||||
return array(
|
||||
'key' => sanitize_key( $record['key'] ?? '' ),
|
||||
'singular_label' => sanitize_text_field( $record['singular_label'] ?? '' ),
|
||||
'plural_label' => sanitize_text_field( $record['plural_label'] ?? '' ),
|
||||
'slug' => sanitize_title( $record['slug'] ?? '' ),
|
||||
'hierarchical' => ! empty( $record['hierarchical'] ) ? 1 : 0,
|
||||
'object_type' => ! empty( $record['object_type'] ) && is_array( $record['object_type'] ) ? array_values( array_unique( array_map( 'sanitize_key', $record['object_type'] ) ) ) : array(),
|
||||
'template_settings' => $this->normalize_taxonomy_template_settings( $record['template_settings'] ?? array() ),
|
||||
'is_override' => ! empty( $record['is_override'] ) ? 1 : 0,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function normalize_cpt_template_settings( $settings ) {
|
||||
$settings = is_array( $settings ) ? $settings : array();
|
||||
$single_mode = isset( $settings['single_mode'] ) && in_array( $settings['single_mode'], array( 'plugin', 'theme' ), true ) ? $settings['single_mode'] : 'plugin';
|
||||
$archive_mode = isset( $settings['archive_mode'] ) && in_array( $settings['archive_mode'], array( 'plugin', 'theme' ), true ) ? $settings['archive_mode'] : 'plugin';
|
||||
$archive_columns = absint( $settings['archive_columns'] ?? 3 );
|
||||
if ( $archive_columns < 1 || $archive_columns > 4 ) {
|
||||
$archive_columns = 3;
|
||||
}
|
||||
return array(
|
||||
'single_mode' => $single_mode,
|
||||
'archive_mode' => $archive_mode,
|
||||
'single_show_featured' => ! empty( $settings['single_show_featured'] ) ? 1 : 0,
|
||||
'single_show_meta' => ! empty( $settings['single_show_meta'] ) ? 1 : 0,
|
||||
'single_show_terms' => ! empty( $settings['single_show_terms'] ) ? 1 : 0,
|
||||
'single_show_custom_fields' => ! empty( $settings['single_show_custom_fields'] ) ? 1 : 0,
|
||||
'archive_show_featured' => ! empty( $settings['archive_show_featured'] ) ? 1 : 0,
|
||||
'archive_show_excerpt' => ! empty( $settings['archive_show_excerpt'] ) ? 1 : 0,
|
||||
'archive_show_meta' => ! empty( $settings['archive_show_meta'] ) ? 1 : 0,
|
||||
'archive_columns' => $archive_columns,
|
||||
'archive_intro' => sanitize_textarea_field( $settings['archive_intro'] ?? '' ),
|
||||
);
|
||||
}
|
||||
|
||||
public function normalize_taxonomy_template_settings( $settings ) {
|
||||
$settings = is_array( $settings ) ? $settings : array();
|
||||
$archive_mode = isset( $settings['archive_mode'] ) && in_array( $settings['archive_mode'], array( 'plugin', 'theme' ), true ) ? $settings['archive_mode'] : 'plugin';
|
||||
$archive_columns = absint( $settings['archive_columns'] ?? 3 );
|
||||
if ( $archive_columns < 1 || $archive_columns > 4 ) {
|
||||
$archive_columns = 3;
|
||||
}
|
||||
return array(
|
||||
'archive_mode' => $archive_mode,
|
||||
'archive_show_featured' => ! empty( $settings['archive_show_featured'] ) ? 1 : 0,
|
||||
'archive_show_excerpt' => ! empty( $settings['archive_show_excerpt'] ) ? 1 : 0,
|
||||
'archive_show_meta' => ! empty( $settings['archive_show_meta'] ) ? 1 : 0,
|
||||
'archive_columns' => $archive_columns,
|
||||
'archive_intro' => sanitize_textarea_field( $settings['archive_intro'] ?? '' ),
|
||||
);
|
||||
}
|
||||
|
||||
public function get_cpt_template_settings( $post_type ) {
|
||||
$record = $this->get_any_managed_cpt_by_key( $post_type );
|
||||
return $record['template_settings'] ?? $this->normalize_cpt_template_settings( array() );
|
||||
}
|
||||
|
||||
public function get_taxonomy_template_settings( $taxonomy ) {
|
||||
$record = $this->get_taxonomy_by_key( $taxonomy ) ?: $this->get_taxonomy_override_by_key( $taxonomy );
|
||||
return $record['template_settings'] ?? $this->normalize_taxonomy_template_settings( array() );
|
||||
}
|
||||
|
||||
public function get_export_payload() {
|
||||
return array(
|
||||
'plugin' => 'ansico-cpt-and-taxonomies',
|
||||
'version' => ANSICO_CPTAX_VERSION,
|
||||
'exported_at_gmt' => gmdate( 'c' ),
|
||||
'cpts' => $this->get_cpts(),
|
||||
'taxonomies' => $this->get_taxonomies(),
|
||||
'cpt_overrides' => $this->get_cpt_overrides(),
|
||||
'taxonomy_overrides' => $this->get_taxonomy_overrides(),
|
||||
);
|
||||
}
|
||||
|
||||
public function register_taxonomies() {
|
||||
foreach ( $this->get_taxonomies() as $taxonomy ) {
|
||||
if ( empty( $taxonomy['key'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attached_post_types = isset( $taxonomy['object_type'] ) && is_array( $taxonomy['object_type'] ) ? array_filter( $taxonomy['object_type'] ) : array( 'post' );
|
||||
if ( empty( $attached_post_types ) ) {
|
||||
$attached_post_types = array( 'post' );
|
||||
}
|
||||
|
||||
register_taxonomy( $taxonomy['key'], $attached_post_types, $this->build_taxonomy_args( $taxonomy ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function register_post_types() {
|
||||
foreach ( $this->get_cpts() as $cpt ) {
|
||||
if ( empty( $cpt['key'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
register_post_type( $cpt['key'], $this->build_post_type_args( $cpt ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function build_taxonomy_args( $taxonomy, $existing_args = array() ) {
|
||||
$singular = $taxonomy['singular_label'] ?? ucfirst( $taxonomy['key'] );
|
||||
$plural = $taxonomy['plural_label'] ?? $singular . 's';
|
||||
$slug = $taxonomy['slug'] ?? $taxonomy['key'];
|
||||
$hierarchical = ! empty( $taxonomy['hierarchical'] );
|
||||
|
||||
$labels = array(
|
||||
'name' => $plural,
|
||||
'singular_name' => $singular,
|
||||
'search_items' => sprintf( __( 'Search %s', 'ansico-cpt-and-taxonomies' ), $plural ),
|
||||
'all_items' => sprintf( __( 'All %s', 'ansico-cpt-and-taxonomies' ), $plural ),
|
||||
'parent_item' => sprintf( __( 'Parent %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'parent_item_colon' => sprintf( __( 'Parent %s:', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'edit_item' => sprintf( __( 'Edit %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'update_item' => sprintf( __( 'Update %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'add_new_item' => sprintf( __( 'Add New %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'new_item_name' => sprintf( __( 'New %s Name', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'menu_name' => $plural,
|
||||
);
|
||||
|
||||
return array_merge(
|
||||
$existing_args,
|
||||
array(
|
||||
'labels' => $labels,
|
||||
'public' => $existing_args['public'] ?? true,
|
||||
'show_ui' => $existing_args['show_ui'] ?? true,
|
||||
'show_admin_column' => $existing_args['show_admin_column'] ?? true,
|
||||
'show_in_nav_menus' => $existing_args['show_in_nav_menus'] ?? true,
|
||||
'show_tagcloud' => ! $hierarchical,
|
||||
'show_in_rest' => $existing_args['show_in_rest'] ?? true,
|
||||
'hierarchical' => $hierarchical,
|
||||
'rewrite' => array( 'slug' => sanitize_title( $slug ) ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function build_post_type_args( $cpt, $existing_args = array() ) {
|
||||
$singular = $cpt['singular_label'] ?? ucfirst( $cpt['key'] );
|
||||
$plural = $cpt['plural_label'] ?? $singular . 's';
|
||||
$slug = $cpt['slug'] ?? $cpt['key'];
|
||||
$supports = isset( $cpt['supports'] ) && is_array( $cpt['supports'] ) ? array_values( array_filter( $cpt['supports'] ) ) : array( 'title', 'editor' );
|
||||
$taxonomies = isset( $cpt['taxonomies'] ) && is_array( $cpt['taxonomies'] ) ? array_values( array_filter( $cpt['taxonomies'] ) ) : array();
|
||||
|
||||
if ( ! in_array( 'custom-fields', $supports, true ) && ! empty( $cpt['custom_fields'] ) ) {
|
||||
$supports[] = 'custom-fields';
|
||||
}
|
||||
|
||||
$labels = array(
|
||||
'name' => $plural,
|
||||
'singular_name' => $singular,
|
||||
'menu_name' => $plural,
|
||||
'name_admin_bar' => $singular,
|
||||
'add_new' => __( 'Add New', 'ansico-cpt-and-taxonomies' ),
|
||||
'add_new_item' => sprintf( __( 'Add New %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'new_item' => sprintf( __( 'New %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'edit_item' => sprintf( __( 'Edit %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'view_item' => sprintf( __( 'View %s', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'all_items' => sprintf( __( 'All %s', 'ansico-cpt-and-taxonomies' ), $plural ),
|
||||
'search_items' => sprintf( __( 'Search %s', 'ansico-cpt-and-taxonomies' ), $plural ),
|
||||
'parent_item_colon' => sprintf( __( 'Parent %s:', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
'not_found' => sprintf( __( 'No %s found.', 'ansico-cpt-and-taxonomies' ), strtolower( $plural ) ),
|
||||
'not_found_in_trash' => sprintf( __( 'No %s found in Trash.', 'ansico-cpt-and-taxonomies' ), strtolower( $plural ) ),
|
||||
'featured_image' => __( 'Featured image', 'ansico-cpt-and-taxonomies' ),
|
||||
'set_featured_image' => __( 'Set featured image', 'ansico-cpt-and-taxonomies' ),
|
||||
'remove_featured_image' => __( 'Remove featured image', 'ansico-cpt-and-taxonomies' ),
|
||||
'use_featured_image' => __( 'Use as featured image', 'ansico-cpt-and-taxonomies' ),
|
||||
'archives' => sprintf( __( '%s archives', 'ansico-cpt-and-taxonomies' ), $singular ),
|
||||
);
|
||||
|
||||
return array_merge(
|
||||
$existing_args,
|
||||
array(
|
||||
'labels' => $labels,
|
||||
'public' => $existing_args['public'] ?? true,
|
||||
'show_ui' => $existing_args['show_ui'] ?? true,
|
||||
'show_in_menu' => $existing_args['show_in_menu'] ?? true,
|
||||
'show_in_rest' => $existing_args['show_in_rest'] ?? true,
|
||||
'has_archive' => $existing_args['has_archive'] ?? true,
|
||||
'rewrite' => array( 'slug' => sanitize_title( $slug ) ),
|
||||
'exclude_from_search' => ! empty( $cpt['exclude_from_search'] ),
|
||||
'can_export' => ! empty( $cpt['can_export'] ),
|
||||
'supports' => $supports,
|
||||
'taxonomies' => $taxonomies,
|
||||
'menu_position' => $existing_args['menu_position'] ?? 20,
|
||||
'menu_icon' => $existing_args['menu_icon'] ?? 'dashicons-admin-post',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function filter_post_type_args( $args, $post_type ) {
|
||||
$override = $this->get_cpt_override_by_key( $post_type );
|
||||
if ( ! $override ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
return $this->build_post_type_args( $override, $args );
|
||||
}
|
||||
|
||||
public function filter_taxonomy_args( $args, $taxonomy ) {
|
||||
$override = $this->get_taxonomy_override_by_key( $taxonomy );
|
||||
if ( ! $override ) {
|
||||
return $args;
|
||||
}
|
||||
|
||||
return $this->build_taxonomy_args( $override, $args );
|
||||
}
|
||||
|
||||
public function attach_overridden_taxonomies_to_objects() {
|
||||
foreach ( $this->get_cpt_overrides() as $override ) {
|
||||
if ( empty( $override['key'] ) || empty( $override['taxonomies'] ) || ! is_array( $override['taxonomies'] ) ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $override['taxonomies'] as $taxonomy ) {
|
||||
if ( taxonomy_exists( $taxonomy ) ) {
|
||||
register_taxonomy_for_object_type( $taxonomy, $override['key'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $this->get_taxonomy_overrides() as $override ) {
|
||||
if ( empty( $override['key'] ) || empty( $override['object_type'] ) || ! is_array( $override['object_type'] ) ) {
|
||||
continue;
|
||||
}
|
||||
foreach ( $override['object_type'] as $object_type ) {
|
||||
if ( post_type_exists( $object_type ) ) {
|
||||
register_taxonomy_for_object_type( $override['key'], $object_type );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function register_meta_boxes() {
|
||||
foreach ( $this->get_all_managed_cpts() as $cpt ) {
|
||||
if ( empty( $cpt['key'] ) || empty( $cpt['custom_fields'] ) || ! is_array( $cpt['custom_fields'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
add_meta_box(
|
||||
'ansico_cptax_fields_' . $cpt['key'],
|
||||
__( 'Custom Fields', 'ansico-cpt-and-taxonomies' ),
|
||||
array( $this, 'render_meta_box' ),
|
||||
$cpt['key'],
|
||||
'normal',
|
||||
'default',
|
||||
array( 'fields' => $cpt['custom_fields'] )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function render_meta_box( $post, $box ) {
|
||||
$fields = $box['args']['fields'] ?? array();
|
||||
wp_nonce_field( 'ansico_cptax_save_fields', 'ansico_cptax_nonce' );
|
||||
|
||||
echo '<table class="form-table"><tbody>';
|
||||
foreach ( $fields as $field ) {
|
||||
$key = $field['key'] ?? '';
|
||||
$label = $field['label'] ?? $key;
|
||||
$type = $field['type'] ?? 'text';
|
||||
$description = $field['description'] ?? '';
|
||||
$options = ! empty( $field['options'] ) && is_array( $field['options'] ) ? $field['options'] : array();
|
||||
|
||||
if ( ! $key ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$meta_key = 'ansico_' . $key;
|
||||
$value = get_post_meta( $post->ID, $meta_key, true );
|
||||
|
||||
echo '<tr>';
|
||||
echo '<th><label for="' . esc_attr( $meta_key ) . '">' . esc_html( $label ) . '</label></th>';
|
||||
echo '<td>';
|
||||
|
||||
switch ( $type ) {
|
||||
case 'textarea':
|
||||
echo '<textarea class="widefat" rows="4" id="' . esc_attr( $meta_key ) . '" name="ansico_fields[' . esc_attr( $key ) . ']">' . esc_textarea( $value ) . '</textarea>';
|
||||
break;
|
||||
case 'checkbox':
|
||||
echo '<label><input type="checkbox" id="' . esc_attr( $meta_key ) . '" name="ansico_fields[' . esc_attr( $key ) . ']" value="1" ' . checked( $value, '1', false ) . '> ' . esc_html__( 'Yes', 'ansico-cpt-and-taxonomies' ) . '</label>';
|
||||
break;
|
||||
case 'select':
|
||||
echo '<select class="regular-text" id="' . esc_attr( $meta_key ) . '" name="ansico_fields[' . esc_attr( $key ) . ']">';
|
||||
echo '<option value="">' . esc_html__( 'Select…', 'ansico-cpt-and-taxonomies' ) . '</option>';
|
||||
foreach ( $options as $option ) {
|
||||
echo '<option value="' . esc_attr( $option ) . '" ' . selected( $value, $option, false ) . '>' . esc_html( $option ) . '</option>';
|
||||
}
|
||||
echo '</select>';
|
||||
break;
|
||||
case 'radio':
|
||||
foreach ( $options as $index => $option ) {
|
||||
echo '<label style="display:block;margin-bottom:6px;"><input type="radio" name="ansico_fields[' . esc_attr( $key ) . ']" value="' . esc_attr( $option ) . '" ' . checked( $value, $option, false ) . '> ' . esc_html( $option ) . '</label>';
|
||||
}
|
||||
break;
|
||||
default:
|
||||
echo '<input class="regular-text" type="' . esc_attr( $type ) . '" id="' . esc_attr( $meta_key ) . '" name="ansico_fields[' . esc_attr( $key ) . ']" value="' . esc_attr( $value ) . '">';
|
||||
break;
|
||||
}
|
||||
|
||||
if ( $description ) {
|
||||
echo '<p class="description">' . esc_html( $description ) . '</p>';
|
||||
}
|
||||
|
||||
echo '</td>';
|
||||
echo '</tr>';
|
||||
}
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
|
||||
public function save_custom_fields( $post_id ) {
|
||||
if ( ! isset( $_POST['ansico_cptax_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ansico_cptax_nonce'] ) ), 'ansico_cptax_save_fields' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post_type = get_post_type( $post_id );
|
||||
$cpt = $this->get_any_managed_cpt_by_key( $post_type );
|
||||
if ( ! $cpt || empty( $cpt['custom_fields'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$submitted = isset( $_POST['ansico_fields'] ) && is_array( $_POST['ansico_fields'] ) ? wp_unslash( $_POST['ansico_fields'] ) : array();
|
||||
|
||||
foreach ( $cpt['custom_fields'] as $field ) {
|
||||
$key = $field['key'] ?? '';
|
||||
$type = $field['type'] ?? 'text';
|
||||
$options = ! empty( $field['options'] ) && is_array( $field['options'] ) ? $field['options'] : array();
|
||||
|
||||
if ( ! $key ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$meta_key = 'ansico_' . $key;
|
||||
|
||||
if ( 'checkbox' === $type ) {
|
||||
$value = isset( $submitted[ $key ] ) ? '1' : '0';
|
||||
} elseif ( 'textarea' === $type ) {
|
||||
$value = sanitize_textarea_field( $submitted[ $key ] ?? '' );
|
||||
} elseif ( in_array( $type, array( 'select', 'radio' ), true ) ) {
|
||||
$candidate = sanitize_text_field( $submitted[ $key ] ?? '' );
|
||||
$value = in_array( $candidate, $options, true ) ? $candidate : '';
|
||||
} else {
|
||||
$value = sanitize_text_field( $submitted[ $key ] ?? '' );
|
||||
}
|
||||
|
||||
update_post_meta( $post_id, $meta_key, $value );
|
||||
}
|
||||
}
|
||||
|
||||
public function get_cpt_by_key( $key ) {
|
||||
foreach ( $this->get_cpts() as $cpt ) {
|
||||
if ( isset( $cpt['key'] ) && $cpt['key'] === $key ) {
|
||||
return $cpt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_taxonomy_by_key( $key ) {
|
||||
foreach ( $this->get_taxonomies() as $taxonomy ) {
|
||||
if ( isset( $taxonomy['key'] ) && $taxonomy['key'] === $key ) {
|
||||
return $taxonomy;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_cpt_override_by_key( $key ) {
|
||||
foreach ( $this->get_cpt_overrides() as $cpt ) {
|
||||
if ( isset( $cpt['key'] ) && $cpt['key'] === $key ) {
|
||||
return $cpt;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_taxonomy_override_by_key( $key ) {
|
||||
foreach ( $this->get_taxonomy_overrides() as $tax ) {
|
||||
if ( isset( $tax['key'] ) && $tax['key'] === $key ) {
|
||||
return $tax;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_any_managed_cpt_by_key( $key ) {
|
||||
return $this->get_cpt_by_key( $key ) ?: $this->get_cpt_override_by_key( $key );
|
||||
}
|
||||
|
||||
public function get_all_managed_cpts() {
|
||||
return array_merge( $this->get_cpts(), $this->get_cpt_overrides() );
|
||||
}
|
||||
|
||||
public function get_editable_post_types() {
|
||||
$objects = get_post_types( array(), 'objects' );
|
||||
$skip = array( 'attachment', 'revision', 'nav_menu_item', 'custom_css', 'customize_changeset', 'oembed_cache', 'user_request', 'wp_block', 'wp_template', 'wp_template_part', 'wp_global_styles', 'wp_navigation', 'wp_font_family', 'wp_font_face' );
|
||||
foreach ( $skip as $post_type ) {
|
||||
unset( $objects[ $post_type ] );
|
||||
}
|
||||
ksort( $objects );
|
||||
return $objects;
|
||||
}
|
||||
|
||||
public function get_editable_taxonomies() {
|
||||
$objects = get_taxonomies( array(), 'objects' );
|
||||
unset( $objects['nav_menu'] );
|
||||
ksort( $objects );
|
||||
return $objects;
|
||||
}
|
||||
|
||||
|
||||
public function template_include( $template ) {
|
||||
if ( is_singular() ) {
|
||||
$post_type = get_post_type();
|
||||
if ( $post_type && $this->get_any_managed_cpt_by_key( $post_type ) ) {
|
||||
$settings = $this->get_cpt_template_settings( $post_type );
|
||||
if ( 'plugin' === ( $settings['single_mode'] ?? 'plugin' ) ) {
|
||||
$plugin_template = ANSICO_CPTAX_PATH . 'templates/single-cpt.php';
|
||||
if ( file_exists( $plugin_template ) ) {
|
||||
return $plugin_template;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_post_type_archive() ) {
|
||||
$post_type = get_query_var( 'post_type' );
|
||||
if ( is_array( $post_type ) ) {
|
||||
$post_type = reset( $post_type );
|
||||
}
|
||||
if ( $post_type && $this->get_any_managed_cpt_by_key( $post_type ) ) {
|
||||
$settings = $this->get_cpt_template_settings( $post_type );
|
||||
if ( 'plugin' === ( $settings['archive_mode'] ?? 'plugin' ) ) {
|
||||
$plugin_template = ANSICO_CPTAX_PATH . 'templates/archive-cpt.php';
|
||||
if ( file_exists( $plugin_template ) ) {
|
||||
return $plugin_template;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_tax() || is_category() || is_tag() ) {
|
||||
$term = get_queried_object();
|
||||
if ( ! empty( $term->taxonomy ) && ( $this->get_taxonomy_by_key( $term->taxonomy ) || $this->get_taxonomy_override_by_key( $term->taxonomy ) ) ) {
|
||||
$settings = $this->get_taxonomy_template_settings( $term->taxonomy );
|
||||
if ( 'plugin' === ( $settings['archive_mode'] ?? 'plugin' ) ) {
|
||||
$plugin_template = ANSICO_CPTAX_PATH . 'templates/taxonomy-archive.php';
|
||||
if ( file_exists( $plugin_template ) ) {
|
||||
return $plugin_template;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
70
ansico-cpt-and-taxonomies/readme.txt
Normal file
70
ansico-cpt-and-taxonomies/readme.txt
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
=== Ansico CPT and Taxonomies ===
|
||||
Contributors: openai
|
||||
Tags: custom post type, taxonomy, custom fields
|
||||
Requires at least: 6.0
|
||||
Tested up to: 6.8
|
||||
Requires PHP: 7.4
|
||||
Stable tag: 0.0.0.4
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
Create and manage custom post types, taxonomies, overrides, and simple custom fields from the WordPress admin.
|
||||
|
||||
== Description ==
|
||||
|
||||
Ansico CPT and Taxonomies lets administrators:
|
||||
|
||||
* Create custom post types
|
||||
* Create taxonomies
|
||||
* Define singular and plural labels
|
||||
* Change slugs
|
||||
* Choose whether a post type is excluded from search
|
||||
* Choose whether a post type can be exported
|
||||
* Enable support for title, editor, featured image, author, and comments
|
||||
* Attach existing taxonomies, including categories and tags
|
||||
* Add simple custom fields to managed post types
|
||||
* Use text, textarea, number, URL, email, date, checkbox, select, and radio custom field types
|
||||
* Add field descriptions and options for select/radio fields
|
||||
* Use plugin-provided single and archive templates for managed content
|
||||
* Import existing registered post types and taxonomies into the plugin as overrides
|
||||
* Export and import plugin-managed data as JSON
|
||||
|
||||
Version 0.0.0.3 improves the admin interface, adds more custom field types, and introduces JSON export/import tools.
|
||||
|
||||
== Notes ==
|
||||
|
||||
* This is an early version intended as a practical foundation.
|
||||
* Imported existing registrations are overridden through WordPress registration hooks rather than being re-created from scratch.
|
||||
* Custom fields added through the plugin are simple meta box fields and not a full field framework.
|
||||
* Template handling is performed through the template_include filter.
|
||||
* JSON import can merge records by key or replace all plugin data.
|
||||
|
||||
== Installation ==
|
||||
|
||||
1. Upload the plugin zip in WordPress.
|
||||
2. Activate the plugin.
|
||||
3. Visit Ansico CPT in the admin menu.
|
||||
4. Create a new post type or taxonomy, or import an existing one for override.
|
||||
5. Use the Tools page for JSON export and import.
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 0.0.0.3 =
|
||||
* Added a more structured admin UI with dedicated Tools page.
|
||||
* Added JSON export and import for managed records and overrides.
|
||||
* Added more custom field types: select and radio.
|
||||
* Added field descriptions and options for select/radio fields.
|
||||
* Added normalization for stored plugin records.
|
||||
|
||||
= 0.0.0.2 =
|
||||
* Added import and override support for existing post types.
|
||||
* Added import and override support for existing taxonomies.
|
||||
* Added separate lists for plugin-created and imported/overridden registrations.
|
||||
* Improved internal data model for managed registrations.
|
||||
|
||||
= 0.0.0.1 =
|
||||
* Initial release.
|
||||
|
||||
== Author ==
|
||||
Andreas Andersen (Ansico)
|
||||
https://ansico.dk
|
||||
BIN
ansico-cpt-and-taxonomies/readme.txt:Zone.Identifier
Normal file
BIN
ansico-cpt-and-taxonomies/readme.txt:Zone.Identifier
Normal file
Binary file not shown.
45
ansico-cpt-and-taxonomies/templates/archive-cpt.php
Normal file
45
ansico-cpt-and-taxonomies/templates/archive-cpt.php
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
get_header();
|
||||
$post_type = get_query_var( 'post_type' );
|
||||
if ( is_array( $post_type ) ) {
|
||||
$post_type = reset( $post_type );
|
||||
}
|
||||
$settings = function_exists( 'ansico_cptax' ) ? ansico_cptax()->get_cpt_template_settings( $post_type ) : array();
|
||||
$columns = max( 1, min( 4, (int) ( $settings['archive_columns'] ?? 3 ) ) );
|
||||
$min_card = 100 / $columns;
|
||||
?>
|
||||
<main id="primary" class="site-main ansico-cpt-archive" style="max-width:1100px;margin:40px auto;padding:0 20px;">
|
||||
<header class="page-header" style="margin-bottom:30px;">
|
||||
<h1 class="page-title"><?php post_type_archive_title(); ?></h1>
|
||||
<?php the_archive_description( '<div class="archive-description">', '</div>' ); ?>
|
||||
<?php if ( ! empty( $settings['archive_intro'] ) ) : ?>
|
||||
<div class="archive-description"><?php echo wp_kses_post( wpautop( $settings['archive_intro'] ) ); ?></div>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
|
||||
<?php if ( have_posts() ) : ?>
|
||||
<div class="ansico-grid" style="display:grid;grid-template-columns:repeat(<?php echo (int) $columns; ?>, minmax(0, 1fr));gap:24px;">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?> style="border:1px solid #ddd;border-radius:8px;padding:20px;">
|
||||
<?php if ( ! empty( $settings['archive_show_featured'] ) && has_post_thumbnail() ) : ?>
|
||||
<div style="margin-bottom:12px;"><?php the_post_thumbnail( 'medium' ); ?></div>
|
||||
<?php endif; ?>
|
||||
<h2 style="margin-top:0;"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
|
||||
<?php if ( ! empty( $settings['archive_show_meta'] ) ) : ?>
|
||||
<p style="color:#666;font-size:0.95em;"><?php echo esc_html( get_the_date() ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $settings['archive_show_excerpt'] ) ) : ?>
|
||||
<div><?php the_excerpt(); ?></div>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<div style="margin-top:24px;"><?php the_posts_pagination(); ?></div>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e( 'No content found.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
<?php get_footer(); ?>
|
||||
Binary file not shown.
79
ansico-cpt-and-taxonomies/templates/single-cpt.php
Normal file
79
ansico-cpt-and-taxonomies/templates/single-cpt.php
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
get_header();
|
||||
$post_type = get_post_type();
|
||||
$settings = function_exists( 'ansico_cptax' ) ? ansico_cptax()->get_cpt_template_settings( $post_type ) : array();
|
||||
?>
|
||||
<main id="primary" class="site-main ansico-cpt-single" style="max-width:900px;margin:40px auto;padding:0 20px;">
|
||||
<?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
|
||||
<header class="entry-header" style="margin-bottom:24px;">
|
||||
<h1 class="entry-title"><?php the_title(); ?></h1>
|
||||
<?php if ( ! empty( $settings['single_show_meta'] ) ) : ?>
|
||||
<p class="entry-meta" style="color:#666;margin-top:8px;">
|
||||
<?php echo esc_html( get_the_date() ); ?>
|
||||
<?php if ( post_type_supports( $post_type, 'author' ) ) : ?>
|
||||
· <?php echo esc_html( get_the_author() ); ?>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $settings['single_show_featured'] ) && has_post_thumbnail() ) : ?>
|
||||
<div class="entry-thumbnail" style="margin:20px 0;"><?php the_post_thumbnail( 'large' ); ?></div>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
|
||||
<div class="entry-content">
|
||||
<?php the_content(); ?>
|
||||
</div>
|
||||
|
||||
<?php if ( ! empty( $settings['single_show_terms'] ) ) : ?>
|
||||
<?php $taxonomies = get_object_taxonomies( $post_type, 'objects' ); ?>
|
||||
<?php if ( ! empty( $taxonomies ) ) : ?>
|
||||
<section class="ansico-tax-terms" style="margin-top:30px;">
|
||||
<h2><?php esc_html_e( 'Taxonomies', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<?php foreach ( $taxonomies as $taxonomy_name => $taxonomy_obj ) : ?>
|
||||
<?php $terms = get_the_terms( get_the_ID(), $taxonomy_name ); ?>
|
||||
<?php if ( ! empty( $terms ) && ! is_wp_error( $terms ) ) : ?>
|
||||
<p><strong><?php echo esc_html( $taxonomy_obj->labels->name ?? $taxonomy_name ); ?>:</strong>
|
||||
<?php echo esc_html( implode( ', ', wp_list_pluck( $terms, 'name' ) ) ); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</section>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
if ( ! empty( $settings['single_show_custom_fields'] ) ) :
|
||||
$custom = get_post_custom( get_the_ID() );
|
||||
$ansico_fields = array_filter(
|
||||
$custom,
|
||||
function ( $key ) {
|
||||
return 0 === strpos( $key, 'ansico_' );
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
if ( ! empty( $ansico_fields ) ) :
|
||||
?>
|
||||
<section class="ansico-custom-fields" style="margin-top:30px;">
|
||||
<h2><?php esc_html_e( 'Details', 'ansico-cpt-and-taxonomies' ); ?></h2>
|
||||
<ul>
|
||||
<?php foreach ( $ansico_fields as $key => $values ) : ?>
|
||||
<?php
|
||||
$display_value = is_array( $values ) ? implode( ', ', array_map( 'wp_strip_all_tags', $values ) ) : wp_strip_all_tags( (string) $values );
|
||||
if ( '' === trim( $display_value ) ) {
|
||||
continue;
|
||||
}
|
||||
?>
|
||||
<li><strong><?php echo esc_html( ucwords( str_replace( array( 'ansico_', '_' ), array( '', ' ' ), $key ) ) ); ?>:</strong> <?php echo esc_html( $display_value ); ?></li>
|
||||
<?php endforeach; ?>
|
||||
</ul>
|
||||
</section>
|
||||
<?php endif; endif; ?>
|
||||
</article>
|
||||
<?php endwhile; endif; ?>
|
||||
</main>
|
||||
<?php get_footer(); ?>
|
||||
Binary file not shown.
43
ansico-cpt-and-taxonomies/templates/taxonomy-archive.php
Normal file
43
ansico-cpt-and-taxonomies/templates/taxonomy-archive.php
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
get_header();
|
||||
$term = get_queried_object();
|
||||
$settings = function_exists( 'ansico_cptax' ) && ! empty( $term->taxonomy ) ? ansico_cptax()->get_taxonomy_template_settings( $term->taxonomy ) : array();
|
||||
$columns = max( 1, min( 4, (int) ( $settings['archive_columns'] ?? 3 ) ) );
|
||||
?>
|
||||
<main id="primary" class="site-main ansico-taxonomy-archive" style="max-width:1100px;margin:40px auto;padding:0 20px;">
|
||||
<header class="page-header" style="margin-bottom:30px;">
|
||||
<h1 class="page-title"><?php single_term_title(); ?></h1>
|
||||
<?php if ( ! empty( $term->description ) ) : ?>
|
||||
<div class="taxonomy-description"><?php echo wp_kses_post( wpautop( $term->description ) ); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $settings['archive_intro'] ) ) : ?>
|
||||
<div class="taxonomy-description"><?php echo wp_kses_post( wpautop( $settings['archive_intro'] ) ); ?></div>
|
||||
<?php endif; ?>
|
||||
</header>
|
||||
|
||||
<?php if ( have_posts() ) : ?>
|
||||
<div class="ansico-grid" style="display:grid;grid-template-columns:repeat(<?php echo (int) $columns; ?>, minmax(0, 1fr));gap:24px;">
|
||||
<?php while ( have_posts() ) : the_post(); ?>
|
||||
<article id="post-<?php the_ID(); ?>" <?php post_class(); ?> style="border:1px solid #ddd;border-radius:8px;padding:20px;">
|
||||
<?php if ( ! empty( $settings['archive_show_featured'] ) && has_post_thumbnail() ) : ?>
|
||||
<div style="margin-bottom:12px;"><?php the_post_thumbnail( 'medium' ); ?></div>
|
||||
<?php endif; ?>
|
||||
<h2 style="margin-top:0;"><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
|
||||
<?php if ( ! empty( $settings['archive_show_meta'] ) ) : ?>
|
||||
<p style="color:#666;font-size:0.95em;"><?php echo esc_html( get_the_date() ); ?></p>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $settings['archive_show_excerpt'] ) ) : ?>
|
||||
<div><?php the_excerpt(); ?></div>
|
||||
<?php endif; ?>
|
||||
</article>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
<div style="margin-top:24px;"><?php the_posts_pagination(); ?></div>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e( 'No content found in this taxonomy archive.', 'ansico-cpt-and-taxonomies' ); ?></p>
|
||||
<?php endif; ?>
|
||||
</main>
|
||||
<?php get_footer(); ?>
|
||||
Binary file not shown.
Loading…
Reference in a new issue