Plugin Directory

Changeset 3358149


Ignore:
Timestamp:
09/08/2025 08:00:47 PM (6 months ago)
Author:
kamranchannar
Message:

Update to version 1.0.2 from GitHub

Location:
ait-easy-post-customization
Files:
9 added
10 edited
1 copied

Legend:

Unmodified
Added
Removed
  • ait-easy-post-customization/tags/1.0.2/ait-easy-post-customization.php

    r3353149 r3358149  
    11<?php
    2 
    32/**
    43 * Plugin Name: AIT Easy Post Customization
    5  * Description: This plugin is essential for the proper theme functionality.
    6  * Version: 1.0.1
    7  * Author: kamranchannar
    8  * License: GPL2
     4 * Description: This plugin is essential for the proper theme functionality, including expiry date and custom fields management.
     5 * Version: 1.0.2
     6 * Author: Muhammad Kamran
     7 * License: GPL-2.0-or-later
    98 * Text Domain: ait-easy-post-customization
     9 * Requires at least: 5.0
     10 * Requires PHP: 7.4
    1011 */
    1112
     
    1718register_activation_hook(__FILE__, 'aitepc_expiry_date_plugin_activate');
    1819function aitepc_expiry_date_plugin_activate() {
    19     if (!get_option('expiry_date_post_types')) {
    20         update_option('expiry_date_post_types', array('post'));
     20    if (!get_option('aitepc_expiry_date_post_types')) {
     21        update_option('aitepc_expiry_date_post_types', array('post'));
    2122    }
    2223
     
    4142function aitepc_check_expired_posts() {
    4243    $post_types = get_option('aitepc_expiry_date_post_types', array('post'));
    43     $tomorrow = gmdate('Ymd', strtotime('+1 day')); // Changed to gmdate()
     44    $tomorrow = gmdate('Ymd', strtotime('+1 day'));
    4445
    4546    $args = array(
     
    4849        'meta_query' => array(
    4950            array(
    50                 'key' => '_aitepc_expiry_date', // Ensure consistency with your meta key
     51                'key' => '_aitepc_expiry_date',
    5152                'value' => $tomorrow,
    5253                'compare' => '<',
     
    7071        }
    7172        wp_reset_postdata();
    72     }
     73    }
     74}
     75
     76// Load translation
     77add_action('plugins_loaded', 'aitepc_load_textdomain');
     78function aitepc_load_textdomain() {
     79    load_plugin_textdomain('ait-easy-post-customization', false, dirname(plugin_basename(__FILE__)) . '/languages');
     80}
     81
     82// Register settings for Settings API
     83add_action('admin_init', 'aitepc_register_settings');
     84function aitepc_register_settings() {
     85    register_setting('aitepc_expiry_group', 'aitepc_expiry_date_post_types', array(
     86        'sanitize_callback' => 'aitepc_sanitize_post_types',
     87        'default' => array('post')
     88    ));
     89
     90    add_settings_section(
     91        'aitepc_post_types_section',
     92        __('Select Post Types for Expiry Date Metabox', 'ait-easy-post-customization'),
     93        null,
     94        'aitepc-expiry-date-settings'
     95    );
     96
     97    $all_post_types = get_post_types(array('public' => true), 'objects');
     98    $filtered_post_types = array_filter($all_post_types, function($post_type) {
     99        return !in_array($post_type->name, array('page', 'attachment'));
     100    });
     101
     102    foreach ($filtered_post_types as $post_type) {
     103        add_settings_field(
     104            'aitepc_pt_' . $post_type->name,
     105            $post_type->label,
     106            'aitepc_pt_checkbox_cb',
     107            'aitepc-expiry-date-settings',
     108            'aitepc_post_types_section',
     109            array('pt' => $post_type->name)
     110        );
     111    }
     112}
     113
     114function aitepc_sanitize_post_types($input) {
     115    return is_array($input) ? array_map('sanitize_text_field', $input) : array();
     116}
     117
     118function aitepc_pt_checkbox_cb($args) {
     119    $options = get_option('aitepc_expiry_date_post_types', array());
     120    $checked = in_array($args['pt'], $options) ? 'checked' : '';
     121    printf(
     122        '<input type="checkbox" name="aitepc_expiry_date_post_types[]" value="%s" %s class="form-check-input" />',
     123        esc_attr($args['pt']),
     124        $checked
     125    );
    73126}
    74127
     
    77130require_once plugin_dir_path(__FILE__) . 'plugin-files/aitepc-settings.php';
    78131require_once plugin_dir_path(__FILE__) . 'plugin-files/aitepc-expiry-metabox.php';
     132require_once plugin_dir_path(__FILE__) . 'plugin-files/aitepc-custom-fields.php';
  • ait-easy-post-customization/tags/1.0.2/functions.php

    r3353149 r3358149  
    55        // Enqueue local Bootstrap CSS and JS
    66        wp_enqueue_style('ait-bootstrap-css', plugins_url('assets/css/bootstrap.min.css', __FILE__), array(), '5.3.3');
     7        wp_enqueue_style('aitepc-admin-css', plugins_url('assets/css/aitepc-admin.css', __FILE__), array(), '1.0.0');
    78        wp_enqueue_script('ait-bootstrap-js', plugins_url('assets/js/bootstrap.bundle.min.js', __FILE__), array('jquery'), '5.3.3', true);
     9
     10        wp_enqueue_style('dashicons');
    811    }
    912}
  • ait-easy-post-customization/tags/1.0.2/plugin-files/aitepc-expiry-metabox.php

    r3353149 r3358149  
    11<?php
    2 // Prevent direct access to the file
     2/**
     3 * AIT Easy Post Customization - Expiry Metabox
     4 *
     5 * @package AIT Easy Post Customization
     6 */
     7
    38if (!defined('ABSPATH')) {
    49    exit;
     
    712// Add Expiry Date Metabox to selected post types
    813function aitepc_add_expiry_date_metabox_to_selected_post_types() {
    9     // Get selected post types from options
    1014    $selected_post_types = get_option('aitepc_expiry_date_post_types', array());
    1115
    12     // Register the metabox for each selected post type
    1316    foreach ($selected_post_types as $post_type) {
    1417        add_meta_box(
    15             'aitepc_expiry_date_metabox',       
    16             'Expiry Date',               
    17             'aitepc_expiry_date_metabox_callback', 
    18             $post_type,                   
    19             'side',                       
    20             'default'                     
     18            'aitepc_expiry_date_metabox',
     19            __('Expiry Date', 'ait-easy-post-customization'),
     20            'aitepc_expiry_date_metabox_callback',
     21            $post_type,
     22            'side',
     23            'default'
    2124        );
    2225    }
     
    2831    wp_nonce_field('aitepc_save_expiry_date', 'aitepc_expiry_date_nonce');
    2932    $expiry_date = get_post_meta($post->ID, '_aitepc_expiry_date', true);
    30     echo '<label for="aitepc_expiry_date">Expiry Date: </label>';
    31     echo '<input type="date" id="aitepc_expiry_date" name="aitepc_expiry_date" value="' . esc_attr($expiry_date) . '" />';
     33    ?>
     34    <div class="mb-3">
     35        <label for="aitepc_expiry_date" class="form-label"><?php _e('Expiry Date:', 'ait-easy-post-customization'); ?></label>
     36        <input type="date" id="aitepc_expiry_date" name="aitepc_expiry_date" value="<?php echo esc_attr($expiry_date); ?>" class="form-control" />
     37    </div>
     38    <?php
    3239}
    3340
     
    4956        $expiry_date = sanitize_text_field(wp_unslash($_POST['aitepc_expiry_date']));
    5057        update_post_meta($post_id, '_aitepc_expiry_date', $expiry_date);
     58    } else {
     59        delete_post_meta($post_id, '_aitepc_expiry_date');
    5160    }
    5261}
  • ait-easy-post-customization/tags/1.0.2/plugin-files/aitepc-settings.php

    r3353149 r3358149  
    11<?php
    2 // Prevent direct access to the file
     2/**
     3 * AIT Easy Post Customization - Settings Page
     4 *
     5 * @package AIT Easy Post Customization
     6 */
     7
    38if (!defined('ABSPATH')) {
    49    exit;
     
    813function aitepc_expiry_date_menu_page() {
    914    add_menu_page(
    10         'Expiry Date Settings',
    11         'Expiry Date',
     15        __('Easy Post Customization Settings', 'ait-easy-post-customization'),
     16        __('Easy Post Customization', 'ait-easy-post-customization'),
    1217        'manage_options',
    1318        'aitepc-expiry-date-settings',
     
    2126// Render the settings page HTML
    2227function aitepc_expiry_date_settings_page_html() {
    23     // Check user capabilities
    2428    if (!current_user_can('manage_options')) {
    25         return;
    26     }
    27 
    28     // Save options when the form is submitted
    29     if (isset($_POST['aitepc_expiry_date_post_types'])) {
    30         // Verify the nonce
    31         if (!isset($_POST['aitepc_expiry_date_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['aitepc_expiry_date_nonce'])), 'aitepc_expiry_date_nonce_action')) {
    32             echo '<div class="alert alert-danger" role="alert">Security check failed. Please try again.</div>';
    33             return;
    34         }
    35 
    36         // Sanitize and validate input
    37         $post_types = isset($_POST['aitepc_expiry_date_post_types']) ? array_map('sanitize_text_field', wp_unslash($_POST['aitepc_expiry_date_post_types'])) : [];
    38        
    39         // Update the option with the validated post types
    40         update_option('aitepc_expiry_date_post_types', $post_types);
    41         echo '<div class="alert alert-success" role="alert">Settings saved successfully!</div>';
    42     }
    43 
    44     // Retrieve current settings
    45     $selected_post_types = get_option('aitepc_expiry_date_post_types', array());
    46 
    47     // Get all built-in public post types
     29        wp_die(__('You do not have sufficient permissions to access this page.', 'ait-easy-post-customization'));
     30    }
     31
     32    // Handle custom fields actions
     33    aitepc_handle_custom_fields_submission();
     34
     35    // Retrieve filtered post types for custom fields form
    4836    $all_post_types = get_post_types(array('public' => true), 'objects');
    49 
    50     // Exclude 'page' and 'attachment'
    5137    $filtered_post_types = array_filter($all_post_types, function($post_type) {
    5238        return !in_array($post_type->name, array('page', 'attachment'));
    5339    });
    5440
    55     // Display the settings form with tabs
    5641    ?>
    57     <div class="container mt-4">
    58         <h2 class="mb-4">Expiry Date Metabox Settings</h2>
    59         <!-- Nav tabs -->
    60         <ul class="nav nav-tabs" id="myTab" role="tablist">
     42    <div class="wrap aitepc-wrap">
     43        <h1 class="aitepc-title"><span class="dashicons dashicons-admin-settings me-2"></span><?php _e('Easy Post Customization', 'ait-easy-post-customization'); ?></h1>
     44        <ul class="nav nav-tabs aitepc-tabs" id="myTab" role="tablist">
    6145            <li class="nav-item" role="presentation">
    62                 <a class="nav-link active" id="post-types-tab" data-bs-toggle="tab" href="#post-types" role="tab" aria-controls="post-types" aria-selected="true">Assign Metabox</a>
     46                <button class="nav-link active" id="post-types-tab" data-bs-toggle="tab" data-bs-target="#post-types" type="button" role="tab" aria-controls="post-types" aria-selected="true">
     47                    <span class="dashicons dashicons-post-status me-1"></span><?php _e('Assign Metabox', 'ait-easy-post-customization'); ?>
     48                </button>
    6349            </li>
    6450            <li class="nav-item" role="presentation">
    65                 <a class="nav-link" id="coming-soon-tab" data-bs-toggle="tab" href="#coming-soon" role="tab" aria-controls="coming-soon" aria-selected="false">Coming Soon</a>
     51                <button class="nav-link" id="custom-fields-tab" data-bs-toggle="tab" data-bs-target="#custom-fields" type="button" role="tab" aria-controls="custom-fields" aria-selected="false">
     52                    <span class="dashicons dashicons-edit me-1"></span><?php _e('Custom Fields', 'ait-easy-post-customization'); ?>
     53                </button>
     54            </li>
     55            <li class="nav-item" role="presentation">
     56                <button class="nav-link" id="coming-soon-tab" data-bs-toggle="tab" data-bs-target="#coming-soon" type="button" role="tab" aria-controls="coming-soon" aria-selected="false">
     57                    <span class="dashicons dashicons-clock me-1"></span><?php _e('Coming Soon', 'ait-easy-post-customization'); ?>
     58                </button>
    6659            </li>
    6760        </ul>
    6861
    69         <!-- Tab content -->
    70         <div class="tab-content mt-3" id="myTabContent">
    71             <!-- First tab for assigning post types -->
     62        <div class="tab-content mt-4" id="myTabContent">
    7263            <div class="tab-pane fade show active" id="post-types" role="tabpanel" aria-labelledby="post-types-tab">
    73                 <form method="post" class="border p-4 rounded shadow-sm bg-light">
    74                     <h4 class="mb-3">Select Post Types for Expiry Date Metabox</h4>
    75                    
    76                     <!-- Nonce field for security -->
    77                     <?php wp_nonce_field('aitepc_expiry_date_nonce_action', 'aitepc_expiry_date_nonce'); ?>
    78                    
     64                <div class="card aitepc-card">
     65                    <div class="card-body">
     66                        <h2 class="card-title"><?php _e('Assign Expiry Date Metabox', 'ait-easy-post-customization'); ?></h2>
     67                        <p class="card-text text-muted"><?php _e('Select the post types where the expiry date metabox should appear.', 'ait-easy-post-customization'); ?></p>
     68                        <form method="post" action="options.php">
     69                            <?php
     70                            settings_fields('aitepc_expiry_group');
     71                            do_settings_sections('aitepc-expiry-date-settings');
     72                            submit_button(__('Save Changes', 'ait-easy-post-customization'), 'primary aitepc-btn', 'submit', true);
     73                            ?>
     74                        </form>
     75                    </div>
     76                </div>
     77            </div>
     78
     79            <div class="tab-pane fade" id="custom-fields" role="tabpanel" aria-labelledby="custom-fields-tab">
     80                <?php aitepc_display_custom_fields_form($filtered_post_types); ?>
     81            </div>
     82
     83            <div class="tab-pane fade" id="coming-soon" role="tabpanel" aria-labelledby="coming-soon-tab">
     84                <div class="card aitepc-card text-center">
     85                    <div class="card-body">
     86                        <h2 class="card-title"><?php _e('Coming Soon', 'ait-easy-post-customization'); ?></h2>
     87                        <p class="card-text"><?php _e('Exciting new features are under development. Stay tuned for updates!', 'ait-easy-post-customization'); ?></p>
     88                        <p><?php _e('Have ideas or feedback? We’d love to hear from you.', 'ait-easy-post-customization'); ?></p>
     89                        <p><?php _e('Contact:', 'ait-easy-post-customization'); ?> <a href="mailto:[email protected]" class="text-decoration-none">[email protected]</a></p>
     90                        <div class="alert alert-info"><?php _e('Thank you for your patience and support!', 'ait-easy-post-customization'); ?></div>
     91                    </div>
     92                </div>
     93            </div>
     94        </div>
     95    </div>
     96    <?php
     97}
     98
     99// Function to handle custom fields form submissions
     100function aitepc_handle_custom_fields_submission() {
     101    if (!isset($_POST['aitepc_custom_fields_action'])) {
     102        return;
     103    }
     104
     105    if (!isset($_POST['aitepc_custom_fields_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['aitepc_custom_fields_nonce'])), 'aitepc_custom_fields_action')) {
     106        echo '<div class="alert alert-danger" role="alert">' . __('Security check failed. Please try again.', 'ait-easy-post-customization') . '</div>';
     107        return;
     108    }
     109
     110    $custom_fields = get_option('aitepc_custom_fields', array());
     111    $action = sanitize_text_field(wp_unslash($_POST['aitepc_custom_fields_action']));
     112
     113    if ($action === 'add' || $action === 'edit') {
     114        $key = sanitize_key(wp_unslash($_POST['field_key']));
     115        $label = sanitize_text_field(wp_unslash($_POST['field_label']));
     116        $type = sanitize_text_field(wp_unslash($_POST['field_type']));
     117        $post_types = isset($_POST['field_post_types']) ? array_map('sanitize_text_field', wp_unslash($_POST['field_post_types'])) : [];
     118
     119        if (empty($key) || empty($label) || empty($type)) {
     120            echo '<div class="alert alert-danger" role="alert">' . __('All fields are required.', 'ait-easy-post-customization') . '</div>';
     121            return;
     122        }
     123
     124        if ($action === 'add' && array_key_exists($key, $custom_fields)) {
     125            echo '<div class="alert alert-danger" role="alert">' . __('Field key already exists.', 'ait-easy-post-customization') . '</div>';
     126            return;
     127        }
     128
     129        $custom_fields[$key] = array(
     130            'label' => $label,
     131            'type' => $type,
     132            'post_types' => $post_types
     133        );
     134
     135        update_option('aitepc_custom_fields', $custom_fields);
     136        echo '<div class="alert alert-success" role="alert">' . __('Custom field ', 'ait-easy-post-customization') . ($action === 'add' ? __('added', 'ait-easy-post-customization') : __('updated', 'ait-easy-post-customization')) . __(' successfully!', 'ait-easy-post-customization') . '</div>';
     137    } elseif ($action === 'delete') {
     138        $key = sanitize_key(wp_unslash($_POST['field_key']));
     139        if (array_key_exists($key, $custom_fields)) {
     140            unset($custom_fields[$key]);
     141            update_option('aitepc_custom_fields', $custom_fields);
     142            echo '<div class="alert alert-success" role="alert">' . __('Custom field deleted successfully!', 'ait-easy-post-customization') . '</div>';
     143        }
     144    }
     145}
     146
     147// Function to display custom fields management
     148function aitepc_display_custom_fields_form($filtered_post_types) {
     149    $custom_fields = get_option('aitepc_custom_fields', array());
     150    $edit_key = isset($_GET['edit']) ? sanitize_key($_GET['edit']) : '';
     151    $edit_field = $edit_key && isset($custom_fields[$edit_key]) ? $custom_fields[$edit_key] : null;
     152    ?>
     153    <div class="card aitepc-card">
     154        <div class="card-body">
     155            <h2 class="card-title mb-4"><?php echo $edit_field ? __('Edit Custom Field', 'ait-easy-post-customization') : __('Add New Custom Field', 'ait-easy-post-customization'); ?></h2>
     156            <form method="post" class="needs-validation" novalidate>
     157                <?php wp_nonce_field('aitepc_custom_fields_action', 'aitepc_custom_fields_nonce'); ?>
     158                <input type="hidden" name="aitepc_custom_fields_action" value="<?php echo $edit_field ? 'edit' : 'add'; ?>">
     159                <?php if ($edit_field) : ?>
     160                    <input type="hidden" name="field_key" value="<?php echo esc_attr($edit_key); ?>">
     161                <?php endif; ?>
     162                <div class="mb-3">
     163                    <label for="field_label" class="form-label"><?php _e('Field Label', 'ait-easy-post-customization'); ?> <span class="text-danger">*</span></label>
     164                    <input type="text" class="form-control" id="field_label" name="field_label" value="<?php echo $edit_field ? esc_attr($edit_field['label']) : ''; ?>" required>
     165                    <div class="invalid-feedback"><?php _e('Please enter a field label.', 'ait-easy-post-customization'); ?></div>
     166                </div>
     167                <div class="mb-3">
     168                    <label for="field_key" class="form-label"><?php _e('Field Key (slug)', 'ait-easy-post-customization'); ?> <span class="text-danger">*</span></label>
     169                    <input type="text" class="form-control" id="field_key" name="field_key" value="<?php echo $edit_field ? esc_attr($edit_key) : ''; ?>" <?php echo $edit_field ? 'readonly' : 'required'; ?> pattern="[a-z0-9_]+">
     170                    <small class="form-text text-muted"><?php _e('Use lowercase letters, numbers, and underscores only. Cannot be changed after creation.', 'ait-easy-post-customization'); ?></small>
     171                    <div class="invalid-feedback"><?php _e('Please enter a valid field key (lowercase letters, numbers, underscores only).', 'ait-easy-post-customization'); ?></div>
     172                </div>
     173                <div class="mb-3">
     174                    <label for="field_type" class="form-label"><?php _e('Field Type', 'ait-easy-post-customization'); ?> <span class="text-danger">*</span></label>
     175                    <select class="form-select" id="field_type" name="field_type" required>
     176                        <option value="text" <?php selected($edit_field ? $edit_field['type'] : '', 'text'); ?>><?php _e('Text', 'ait-easy-post-customization'); ?></option>
     177                        <option value="textarea" <?php selected($edit_field ? $edit_field['type'] : '', 'textarea'); ?>><?php _e('Textarea', 'ait-easy-post-customization'); ?></option>
     178                        <option value="date" <?php selected($edit_field ? $edit_field['type'] : '', 'date'); ?>><?php _e('Date', 'ait-easy-post-customization'); ?></option>
     179                    </select>
     180                    <div class="invalid-feedback"><?php _e('Please select a field type.', 'ait-easy-post-customization'); ?></div>
     181                </div>
     182                <div class="mb-4">
     183                    <h5 class="mb-3"><?php _e('Select Post Types', 'ait-easy-post-customization'); ?></h5>
    79184                    <div class="row">
    80185                        <?php foreach ($filtered_post_types as $post_type) :
    81                             $checked = in_array($post_type->name, $selected_post_types) ? 'checked="checked"' : ''; ?>
     186                            $checked = $edit_field && in_array($post_type->name, $edit_field['post_types']) ? 'checked="checked"' : ''; ?>
    82187                            <div class="col-md-4 mb-3 d-flex align-items-center">
    83                                 <input type="checkbox" class="form-check-input me-2" name="aitepc_expiry_date_post_types[]" value="<?php echo esc_attr($post_type->name); ?>" <?php echo esc_attr($checked); ?> id="aitepc_<?php echo esc_attr($post_type->name); ?>">
    84                                 <label class="form-check-label" for="aitepc_<?php echo esc_attr($post_type->name); ?>">
     188                                <input type="checkbox" class="form-check-input me-2" name="field_post_types[]" value="<?php echo esc_attr($post_type->name); ?>" <?php echo esc_attr($checked); ?> id="field_<?php echo esc_attr($post_type->name); ?>">
     189                                <label class="form-check-label" for="field_<?php echo esc_attr($post_type->name); ?>">
    85190                                    <?php echo esc_html($post_type->label); ?>
    86191                                </label>
     
    88193                        <?php endforeach; ?>
    89194                    </div>
    90                     <button type="submit" class="btn btn-primary mt-3">Save Changes</button>
    91                 </form>
    92             </div>
    93 
    94             <!-- Second tab for coming soon -->
    95             <div class="tab-pane fade" id="coming-soon" role="tabpanel" aria-labelledby="coming-soon-tab">
    96                 <div class="text-center">
    97                     <h4>Coming Soon</h4>
    98                     <p>This feature is currently under development. Stay tuned for updates!</p>
    99                     <p>We’d love to hear your feedback! Let us know what features you’d like to see in the upcoming release.</p>
    100                     <p>Contact: <a href="mailto:[email protected]">[email protected]</a></p>
    101                     <div class="alert alert-info" role="alert">
    102                         We appreciate your patience and support!
    103                     </div>
    104                 </div>
    105             </div>
     195                </div>
     196                <div class="d-flex gap-2">
     197                    <button type="submit" class="btn btn-primary aitepc-btn"><?php echo $edit_field ? __('Update Field', 'ait-easy-post-customization') : __('Add Field', 'ait-easy-post-customization'); ?></button>
     198                    <?php if ($edit_field) : ?>
     199                        <a href="<?php echo esc_url(admin_url('admin.php?page=aitepc-expiry-date-settings')); ?>" class="btn btn-outline-secondary"><?php _e('Cancel', 'ait-easy-post-customization'); ?></a>
     200                    <?php endif; ?>
     201                </div>
     202            </form>
    106203        </div>
    107204    </div>
     205
     206    <div class="card aitepc-card mt-4">
     207        <div class="card-body">
     208            <h2 class="card-title mb-4"><?php _e('Existing Custom Fields', 'ait-easy-post-customization'); ?></h2>
     209            <?php if (!empty($custom_fields)) : ?>
     210                <div class="table-responsive">
     211                    <table class="table table-hover aitepc-table">
     212                        <thead>
     213                            <tr>
     214                                <th><?php _e('Label', 'ait-easy-post-customization'); ?></th>
     215                                <th><?php _e('Key', 'ait-easy-post-customization'); ?></th>
     216                                <th><?php _e('Type', 'ait-easy-post-customization'); ?></th>
     217                                <th><?php _e('Post Types', 'ait-easy-post-customization'); ?></th>
     218                                <th><?php _e('Actions', 'ait-easy-post-customization'); ?></th>
     219                            </tr>
     220                        </thead>
     221                        <tbody>
     222                            <?php foreach ($custom_fields as $key => $field) : ?>
     223                                <tr>
     224                                    <td><?php echo esc_html($field['label']); ?></td>
     225                                    <td><?php echo esc_html($key); ?></td>
     226                                    <td><?php echo esc_html($field['type']); ?></td>
     227                                    <td><?php echo esc_html(implode(', ', $field['post_types'])); ?></td>
     228                                    <td>
     229                                        <a href="<?php echo esc_url(add_query_arg('edit', $key, admin_url('admin.php?page=aitepc-expiry-date-settings'))); ?>" class="btn btn-sm btn-primary aitepc-btn me-1"><?php _e('Edit', 'ait-easy-post-customization'); ?></a>
     230                                        <form method="post" style="display:inline;">
     231                                            <?php wp_nonce_field('aitepc_custom_fields_action', 'aitepc_custom_fields_nonce'); ?>
     232                                            <input type="hidden" name="aitepc_custom_fields_action" value="delete">
     233                                            <input type="hidden" name="field_key" value="<?php echo esc_attr($key); ?>">
     234                                            <button type="submit" class="btn btn-sm btn-danger aitepc-btn" onclick="return confirm('<?php esc_attr_e('Are you sure you want to delete this field?', 'ait-easy-post-customization'); ?>');"><?php _e('Delete', 'ait-easy-post-customization'); ?></button>
     235                                        </form>
     236                                    </td>
     237                                </tr>
     238                            <?php endforeach; ?>
     239                        </tbody>
     240                    </table>
     241                </div>
     242            <?php else : ?>
     243                <p class="text-muted"><?php _e('No custom fields added yet.', 'ait-easy-post-customization'); ?></p>
     244            <?php endif; ?>
     245        </div>
     246    </div>
     247    <script>
     248        // Bootstrap form validation
     249        (function () {
     250            'use strict';
     251            const forms = document.querySelectorAll('.needs-validation');
     252            Array.from(forms).forEach(form => {
     253                form.addEventListener('submit', event => {
     254                    if (!form.checkValidity()) {
     255                        event.preventDefault();
     256                        event.stopPropagation();
     257                    }
     258                    form.classList.add('was-validated');
     259                }, false);
     260            });
     261        })();
     262    </script>
    108263    <?php
    109264}
    110 ?>
  • ait-easy-post-customization/tags/1.0.2/readme.txt

    r3353149 r3358149  
    11=== AIT Easy Post Customization ===
    22Contributors: Muhammad Kamran
    3 Tags:  post expiration, post expiry, expiry date, schedule post, auto expire
    4 Requires at least: 5.0 
    5 Tested up to: 6.6
    6 Requires PHP: 7.2
    7 Stable tag: 1.0.
    8 License: GPLv2 or later 
    9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 
     3Tags: post expiration, post expiry, expiry date, schedule post, auto expire, custom fields
     4Requires at least: 5.0
     5Tested up to: 6.8
     6Requires PHP: 7.4
     7Stable tag: 1.0.2
     8License: GPLv2 or later
     9License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    1111Easily set expiry dates for posts and custom post types, automatically unpublishing content when it becomes outdated.
    1212
    13 == AIT Easy Post Customization ==
     13== Description ==
    1414
    1515AIT Easy Post Customization is a powerful yet easy-to-use plugin designed to give users control over the lifespan of their posts and custom post types by allowing you to set an expiry date. If you're managing time-sensitive content, like event announcements, special promotions, or limited-time offers, this plugin automates the process of unpublishing or archiving content, making content management hassle-free.
    16 What problem does this plugin solve?
     16
     17**What problem does this plugin solve?**
    1718
    1819Manually tracking and updating expired content can be tedious and prone to errors, especially if you have a large volume of posts. Without this plugin, expired content can remain live, leading to outdated or irrelevant information on your website. AIT Easy Post Customization solves this problem by allowing you to set expiry dates on posts, ensuring that content is automatically hidden or removed after the specified date. This keeps your site fresh and up-to-date without manual intervention.
    19 How does it improve the user experience?
    2020
    21     1. Automatic Expiry Handling: Set an expiration date for any post or custom post type, and let the plugin automatically unpublish it when the time comes. This eliminates the need for manual updates and improves content accuracy.
    22     2. Custom Post Type Support: Whether you're using standard WordPress posts or custom post types (like events, job listings, products, etc.), you can easily add expiry functionality to all of them.
    23     3. User-Friendly Interface: The plugin integrates seamlessly with the WordPress editor, making it easy for users of all skill levels to manage expiry dates. The expiry date can be set directly from the post editing screen.
     21**How does it improve the user experience?**
    2422
    25 Key Features:
     231. **Automatic Expiry Handling**: Set an expiration date for any post or custom post type, and let the plugin automatically unpublish it when the time comes. This eliminates the need for manual updates and improves content accuracy.
     242. **Custom Post Type Support**: Whether you're using standard WordPress posts or custom post types (like events, job listings, products, etc.), you can easily add expiry functionality to all of them.
     253. **User-Friendly Interface**: The plugin integrates seamlessly with the WordPress editor, making it easy for users of all skill levels to manage expiry dates. The expiry date can be set directly from the post editing screen.
     264. **Custom Fields Management**: Add custom fields (text, textarea, date) to posts for enhanced content customization.
     275. **Modern Admin Interface**: A sleek, responsive admin panel with sticky tabs, form validation, and intuitive navigation.
    2628
    27     1. Post Expiration: Set expiration dates for posts and custom post types, and automatically unpublish them when the time is up.
    28     2. Customizable Actions: Choose what happens to the post after it expires (e.g., move to draft, delete, or do nothing).
    29     3. Supports All Post Types: Works with standard WordPress posts and custom post types, allowing flexible use across various content types.
    30     4. Seamless Integration: Integrated into the post editor, making it easy to manage for both beginners and advanced users.
    31     5. Scheduled Content Management: Perfect for managing content like event updates, limited-time offers, and seasonal announcements.
     29**Key Features**:
    3230
    33 Notable Features:
     311. **Post Expiration**: Set expiration dates for posts and custom post types, automatically moving them to draft status when expired.
     322. **Custom Fields**: Add and manage custom fields (text, textarea, date) for selected post types.
     333. **Supports All Post Types**: Works with standard WordPress posts and custom post types, allowing flexible use across various content types.
     344. **Seamless Integration**: Integrated into the post editor with a modern, user-friendly interface.
     355. **Scheduled Content Management**: Perfect for managing content like event updates, limited-time offers, and seasonal announcements.
     366. **Localization Ready**: Fully translation-ready for multilingual websites.
    3437
    35     1. Custom Widgets: Optionally display a widget that shows upcoming or recently expired content to site admins for better tracking.
    36     2. Developer-Friendly Hooks and Filters: Developers can further customize the plugin’s behavior using built-in hooks and filters.
    37     3. Localization Ready: Fully translation-ready, making it suitable for websites in any language.
     38**Notable Features**:
     39
     401. **Custom Widgets**: Optionally display a widget that shows upcoming or recently expired content to site admins for better tracking (coming soon).
     412. **Developer-Friendly Hooks and Filters**: Developers can customize the plugin’s behavior using built-in hooks and filters.
     423. **Modern Design**: Features a responsive admin interface with sticky tabs, Dashicons, and gradient effects for a premium experience.
    3843
    3944With AIT Easy Post Customization, you’ll never have to worry about outdated or irrelevant content cluttering your site again. Keep your content fresh, current, and timely with minimal effort.
     
    4348Follow these steps to install and activate AIT Easy Post Customization:
    4449
    45     Upload Method:
    46         1. Upload the plugin files to the /wp-content/plugins/ait-easy-post-customization/ directory.
     50**Upload Method**:
     511. Upload the plugin files to the `/wp-content/plugins/ait-easy-post-customization/` directory.
    4752
    48     OR
     53**OR**
    4954
    50     Direct Install via WordPress:
    51         1. Go to the WordPress dashboard, navigate to Plugins -> Add New, and search for AIT Easy Post Customization. Click Install Now.
     55**Direct Install via WordPress**:
     561. Go to the WordPress dashboard, navigate to Plugins -> Add New, and search for AIT Easy Post Customization. Click Install Now.
    5257
    53     Activate the Plugin:
    54         1. Once installed, go to the Plugins screen in WordPress and click Activate next to AIT Easy Post Customization.
     58**Activate the Plugin**:
     591. Once installed, go to the Plugins screen in WordPress and click Activate next to AIT Easy Post Customization.
    5560
    56     Configure the Plugin:
    57         1. After activation, a new menu item called AIT Expiry Date will appear in the WordPress sidebar. Click on it to access the plugin settings and configure the expiry date options as needed.
     61**Configure the Plugin**:
     621. After activation, a new menu item called **Easy Post Customization** will appear in the WordPress sidebar. Click on it to access the plugin settings and configure the expiry date and custom field options as needed.
    5863
    5964== Frequently Asked Questions ==
    6065
    61 = 1. What is AIT Easy Post Customization? =
    62 AIT Easy Post Customization is a WordPress plugin that allows users to easily set expiry dates for posts and custom post types, helping to manage content visibility and relevance effectively.
     66=== 1. What is AIT Easy Post Customization? ===
     67AIT Easy Post Customization is a WordPress plugin that allows users to set expiry dates for posts and custom post types and manage custom fields, ensuring content remains relevant and up-to-date.
    6368
    6469=== 2. How do I install the plugin? ===
    6570You can install the plugin by uploading the plugin files to the `/wp-content/plugins/ait-easy-post-customization/` directory or by installing it directly through the WordPress plugins screen. After installation, activate the plugin through the 'Plugins' screen in WordPress.
    6671
    67 === 3. Where can I configure the expiry date settings? ===
    68 After activating the plugin, you can configure the expiry date settings by navigating to the **AIT Expiry Date** link in the WordPress sidebar. Here, you can manage expiry settings for your posts and custom post types.
     72=== 3. Where can I configure the settings? ===
     73After activating the plugin, you can configure settings by navigating to the **Easy Post Customization** link in the WordPress sidebar. Here, you can manage expiry dates and custom fields for your posts and custom post types.
    6974
    7075=== 4. Can I set an expiry date for custom post types? ===
     
    7277
    7378=== 5. What happens to a post when it expires? ===
    74 Once a post expires, it will be automatically hidden from public view. You can also configure settings to notify users or take specific actions when a post expires.
     79Once a post expires, it will be automatically moved to draft status, hiding it from public view. Future updates may include options for other actions like deletion.
    7580
    7681=== 6. Is there any support available if I encounter issues? ===
     
    8388Yes, AIT Easy Post Customization is completely free to use and is licensed under the GPLv2 or later.
    8489
     90== Screenshots ==
     911. Admin settings page with modern tabbed interface and sticky navigation.
     922. Expiry date metabox on a post edit screen.
     933. Custom fields metabox on a post edit screen.
     94
    8595== Changelog ==
     96= 1.0.2 - 2025-09-09 =
     97* Changed admin menu name from "AIT Expiry Date" to "Easy Post Customization" for better branding.
     98* Introduced modern admin interface with custom CSS (`aitepc-admin.css`), sticky tabs, Dashicons, and gradient effects.
     99* Added client-side form validation for custom fields with inline feedback for improved usability.
     100* Enhanced custom fields table with sticky headers and hover effects for better navigation.
     101* Optimized CSS with variables for maintainability and improved responsive design.
     102* Improved security with proper sanitization, nonce verification, and output escaping.
     103* Ensured compatibility with WordPress 6.6 and PHP 7.2+.
    86104
    87 = 1.0.1 =
     105= 1.0.1 - 2025-09-01 =
    88106* Initial release of AIT Easy Post Customization.
    89107* Added functionality to set expiry dates for posts and custom post types.
    90108* Integrated user-friendly interface for managing expiry settings.
     109* Added custom fields management for text, textarea, and date fields.
     110
     111== Upgrade Notice ==
     112= 1.0.2 =
     113This update introduces a modern admin interface with sticky tabs, form validation, and enhanced usability. The menu name is now "Easy Post Customization" for consistency. Update for a more user-friendly experience.
    91114
    92115== License & Copyright ==
    93 
    94 This plugin is licensed under the GPLv2 or later. 
     116This plugin is licensed under the GPLv2 or later.
    95117You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation.
    96118
     
    98120
    99121== Contact ==
    100 
    101122For inquiries, project discussions, or collaboration opportunities, feel free to reach out to me:
    102123
    103 - Email: [[email protected]](mailto:[email protected]) 
    104 - LinkedIn: [Muhammad Kamran](https://linkedin.com/in/muhammad-kamran-64a33a166) 
     124- Email: [[email protected]](mailto:[email protected])
     125- LinkedIn: [Muhammad Kamran](https://linkedin.com/in/muhammad-kamran-64a33a166)
    105126
    106127I look forward to connecting with you!
    107 
  • ait-easy-post-customization/trunk/ait-easy-post-customization.php

    r3353149 r3358149  
    11<?php
    2 
    32/**
    43 * Plugin Name: AIT Easy Post Customization
    5  * Description: This plugin is essential for the proper theme functionality.
    6  * Version: 1.0.1
    7  * Author: kamranchannar
    8  * License: GPL2
     4 * Description: This plugin is essential for the proper theme functionality, including expiry date and custom fields management.
     5 * Version: 1.0.2
     6 * Author: Muhammad Kamran
     7 * License: GPL-2.0-or-later
    98 * Text Domain: ait-easy-post-customization
     9 * Requires at least: 5.0
     10 * Requires PHP: 7.4
    1011 */
    1112
     
    1718register_activation_hook(__FILE__, 'aitepc_expiry_date_plugin_activate');
    1819function aitepc_expiry_date_plugin_activate() {
    19     if (!get_option('expiry_date_post_types')) {
    20         update_option('expiry_date_post_types', array('post'));
     20    if (!get_option('aitepc_expiry_date_post_types')) {
     21        update_option('aitepc_expiry_date_post_types', array('post'));
    2122    }
    2223
     
    4142function aitepc_check_expired_posts() {
    4243    $post_types = get_option('aitepc_expiry_date_post_types', array('post'));
    43     $tomorrow = gmdate('Ymd', strtotime('+1 day')); // Changed to gmdate()
     44    $tomorrow = gmdate('Ymd', strtotime('+1 day'));
    4445
    4546    $args = array(
     
    4849        'meta_query' => array(
    4950            array(
    50                 'key' => '_aitepc_expiry_date', // Ensure consistency with your meta key
     51                'key' => '_aitepc_expiry_date',
    5152                'value' => $tomorrow,
    5253                'compare' => '<',
     
    7071        }
    7172        wp_reset_postdata();
    72     }
     73    }
     74}
     75
     76// Load translation
     77add_action('plugins_loaded', 'aitepc_load_textdomain');
     78function aitepc_load_textdomain() {
     79    load_plugin_textdomain('ait-easy-post-customization', false, dirname(plugin_basename(__FILE__)) . '/languages');
     80}
     81
     82// Register settings for Settings API
     83add_action('admin_init', 'aitepc_register_settings');
     84function aitepc_register_settings() {
     85    register_setting('aitepc_expiry_group', 'aitepc_expiry_date_post_types', array(
     86        'sanitize_callback' => 'aitepc_sanitize_post_types',
     87        'default' => array('post')
     88    ));
     89
     90    add_settings_section(
     91        'aitepc_post_types_section',
     92        __('Select Post Types for Expiry Date Metabox', 'ait-easy-post-customization'),
     93        null,
     94        'aitepc-expiry-date-settings'
     95    );
     96
     97    $all_post_types = get_post_types(array('public' => true), 'objects');
     98    $filtered_post_types = array_filter($all_post_types, function($post_type) {
     99        return !in_array($post_type->name, array('page', 'attachment'));
     100    });
     101
     102    foreach ($filtered_post_types as $post_type) {
     103        add_settings_field(
     104            'aitepc_pt_' . $post_type->name,
     105            $post_type->label,
     106            'aitepc_pt_checkbox_cb',
     107            'aitepc-expiry-date-settings',
     108            'aitepc_post_types_section',
     109            array('pt' => $post_type->name)
     110        );
     111    }
     112}
     113
     114function aitepc_sanitize_post_types($input) {
     115    return is_array($input) ? array_map('sanitize_text_field', $input) : array();
     116}
     117
     118function aitepc_pt_checkbox_cb($args) {
     119    $options = get_option('aitepc_expiry_date_post_types', array());
     120    $checked = in_array($args['pt'], $options) ? 'checked' : '';
     121    printf(
     122        '<input type="checkbox" name="aitepc_expiry_date_post_types[]" value="%s" %s class="form-check-input" />',
     123        esc_attr($args['pt']),
     124        $checked
     125    );
    73126}
    74127
     
    77130require_once plugin_dir_path(__FILE__) . 'plugin-files/aitepc-settings.php';
    78131require_once plugin_dir_path(__FILE__) . 'plugin-files/aitepc-expiry-metabox.php';
     132require_once plugin_dir_path(__FILE__) . 'plugin-files/aitepc-custom-fields.php';
  • ait-easy-post-customization/trunk/functions.php

    r3353149 r3358149  
    55        // Enqueue local Bootstrap CSS and JS
    66        wp_enqueue_style('ait-bootstrap-css', plugins_url('assets/css/bootstrap.min.css', __FILE__), array(), '5.3.3');
     7        wp_enqueue_style('aitepc-admin-css', plugins_url('assets/css/aitepc-admin.css', __FILE__), array(), '1.0.0');
    78        wp_enqueue_script('ait-bootstrap-js', plugins_url('assets/js/bootstrap.bundle.min.js', __FILE__), array('jquery'), '5.3.3', true);
     9
     10        wp_enqueue_style('dashicons');
    811    }
    912}
  • ait-easy-post-customization/trunk/plugin-files/aitepc-expiry-metabox.php

    r3353149 r3358149  
    11<?php
    2 // Prevent direct access to the file
     2/**
     3 * AIT Easy Post Customization - Expiry Metabox
     4 *
     5 * @package AIT Easy Post Customization
     6 */
     7
    38if (!defined('ABSPATH')) {
    49    exit;
     
    712// Add Expiry Date Metabox to selected post types
    813function aitepc_add_expiry_date_metabox_to_selected_post_types() {
    9     // Get selected post types from options
    1014    $selected_post_types = get_option('aitepc_expiry_date_post_types', array());
    1115
    12     // Register the metabox for each selected post type
    1316    foreach ($selected_post_types as $post_type) {
    1417        add_meta_box(
    15             'aitepc_expiry_date_metabox',       
    16             'Expiry Date',               
    17             'aitepc_expiry_date_metabox_callback', 
    18             $post_type,                   
    19             'side',                       
    20             'default'                     
     18            'aitepc_expiry_date_metabox',
     19            __('Expiry Date', 'ait-easy-post-customization'),
     20            'aitepc_expiry_date_metabox_callback',
     21            $post_type,
     22            'side',
     23            'default'
    2124        );
    2225    }
     
    2831    wp_nonce_field('aitepc_save_expiry_date', 'aitepc_expiry_date_nonce');
    2932    $expiry_date = get_post_meta($post->ID, '_aitepc_expiry_date', true);
    30     echo '<label for="aitepc_expiry_date">Expiry Date: </label>';
    31     echo '<input type="date" id="aitepc_expiry_date" name="aitepc_expiry_date" value="' . esc_attr($expiry_date) . '" />';
     33    ?>
     34    <div class="mb-3">
     35        <label for="aitepc_expiry_date" class="form-label"><?php _e('Expiry Date:', 'ait-easy-post-customization'); ?></label>
     36        <input type="date" id="aitepc_expiry_date" name="aitepc_expiry_date" value="<?php echo esc_attr($expiry_date); ?>" class="form-control" />
     37    </div>
     38    <?php
    3239}
    3340
     
    4956        $expiry_date = sanitize_text_field(wp_unslash($_POST['aitepc_expiry_date']));
    5057        update_post_meta($post_id, '_aitepc_expiry_date', $expiry_date);
     58    } else {
     59        delete_post_meta($post_id, '_aitepc_expiry_date');
    5160    }
    5261}
  • ait-easy-post-customization/trunk/plugin-files/aitepc-settings.php

    r3353149 r3358149  
    11<?php
    2 // Prevent direct access to the file
     2/**
     3 * AIT Easy Post Customization - Settings Page
     4 *
     5 * @package AIT Easy Post Customization
     6 */
     7
    38if (!defined('ABSPATH')) {
    49    exit;
     
    813function aitepc_expiry_date_menu_page() {
    914    add_menu_page(
    10         'Expiry Date Settings',
    11         'Expiry Date',
     15        __('Easy Post Customization Settings', 'ait-easy-post-customization'),
     16        __('Easy Post Customization', 'ait-easy-post-customization'),
    1217        'manage_options',
    1318        'aitepc-expiry-date-settings',
     
    2126// Render the settings page HTML
    2227function aitepc_expiry_date_settings_page_html() {
    23     // Check user capabilities
    2428    if (!current_user_can('manage_options')) {
    25         return;
    26     }
    27 
    28     // Save options when the form is submitted
    29     if (isset($_POST['aitepc_expiry_date_post_types'])) {
    30         // Verify the nonce
    31         if (!isset($_POST['aitepc_expiry_date_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['aitepc_expiry_date_nonce'])), 'aitepc_expiry_date_nonce_action')) {
    32             echo '<div class="alert alert-danger" role="alert">Security check failed. Please try again.</div>';
    33             return;
    34         }
    35 
    36         // Sanitize and validate input
    37         $post_types = isset($_POST['aitepc_expiry_date_post_types']) ? array_map('sanitize_text_field', wp_unslash($_POST['aitepc_expiry_date_post_types'])) : [];
    38        
    39         // Update the option with the validated post types
    40         update_option('aitepc_expiry_date_post_types', $post_types);
    41         echo '<div class="alert alert-success" role="alert">Settings saved successfully!</div>';
    42     }
    43 
    44     // Retrieve current settings
    45     $selected_post_types = get_option('aitepc_expiry_date_post_types', array());
    46 
    47     // Get all built-in public post types
     29        wp_die(__('You do not have sufficient permissions to access this page.', 'ait-easy-post-customization'));
     30    }
     31
     32    // Handle custom fields actions
     33    aitepc_handle_custom_fields_submission();
     34
     35    // Retrieve filtered post types for custom fields form
    4836    $all_post_types = get_post_types(array('public' => true), 'objects');
    49 
    50     // Exclude 'page' and 'attachment'
    5137    $filtered_post_types = array_filter($all_post_types, function($post_type) {
    5238        return !in_array($post_type->name, array('page', 'attachment'));
    5339    });
    5440
    55     // Display the settings form with tabs
    5641    ?>
    57     <div class="container mt-4">
    58         <h2 class="mb-4">Expiry Date Metabox Settings</h2>
    59         <!-- Nav tabs -->
    60         <ul class="nav nav-tabs" id="myTab" role="tablist">
     42    <div class="wrap aitepc-wrap">
     43        <h1 class="aitepc-title"><span class="dashicons dashicons-admin-settings me-2"></span><?php _e('Easy Post Customization', 'ait-easy-post-customization'); ?></h1>
     44        <ul class="nav nav-tabs aitepc-tabs" id="myTab" role="tablist">
    6145            <li class="nav-item" role="presentation">
    62                 <a class="nav-link active" id="post-types-tab" data-bs-toggle="tab" href="#post-types" role="tab" aria-controls="post-types" aria-selected="true">Assign Metabox</a>
     46                <button class="nav-link active" id="post-types-tab" data-bs-toggle="tab" data-bs-target="#post-types" type="button" role="tab" aria-controls="post-types" aria-selected="true">
     47                    <span class="dashicons dashicons-post-status me-1"></span><?php _e('Assign Metabox', 'ait-easy-post-customization'); ?>
     48                </button>
    6349            </li>
    6450            <li class="nav-item" role="presentation">
    65                 <a class="nav-link" id="coming-soon-tab" data-bs-toggle="tab" href="#coming-soon" role="tab" aria-controls="coming-soon" aria-selected="false">Coming Soon</a>
     51                <button class="nav-link" id="custom-fields-tab" data-bs-toggle="tab" data-bs-target="#custom-fields" type="button" role="tab" aria-controls="custom-fields" aria-selected="false">
     52                    <span class="dashicons dashicons-edit me-1"></span><?php _e('Custom Fields', 'ait-easy-post-customization'); ?>
     53                </button>
     54            </li>
     55            <li class="nav-item" role="presentation">
     56                <button class="nav-link" id="coming-soon-tab" data-bs-toggle="tab" data-bs-target="#coming-soon" type="button" role="tab" aria-controls="coming-soon" aria-selected="false">
     57                    <span class="dashicons dashicons-clock me-1"></span><?php _e('Coming Soon', 'ait-easy-post-customization'); ?>
     58                </button>
    6659            </li>
    6760        </ul>
    6861
    69         <!-- Tab content -->
    70         <div class="tab-content mt-3" id="myTabContent">
    71             <!-- First tab for assigning post types -->
     62        <div class="tab-content mt-4" id="myTabContent">
    7263            <div class="tab-pane fade show active" id="post-types" role="tabpanel" aria-labelledby="post-types-tab">
    73                 <form method="post" class="border p-4 rounded shadow-sm bg-light">
    74                     <h4 class="mb-3">Select Post Types for Expiry Date Metabox</h4>
    75                    
    76                     <!-- Nonce field for security -->
    77                     <?php wp_nonce_field('aitepc_expiry_date_nonce_action', 'aitepc_expiry_date_nonce'); ?>
    78                    
     64                <div class="card aitepc-card">
     65                    <div class="card-body">
     66                        <h2 class="card-title"><?php _e('Assign Expiry Date Metabox', 'ait-easy-post-customization'); ?></h2>
     67                        <p class="card-text text-muted"><?php _e('Select the post types where the expiry date metabox should appear.', 'ait-easy-post-customization'); ?></p>
     68                        <form method="post" action="options.php">
     69                            <?php
     70                            settings_fields('aitepc_expiry_group');
     71                            do_settings_sections('aitepc-expiry-date-settings');
     72                            submit_button(__('Save Changes', 'ait-easy-post-customization'), 'primary aitepc-btn', 'submit', true);
     73                            ?>
     74                        </form>
     75                    </div>
     76                </div>
     77            </div>
     78
     79            <div class="tab-pane fade" id="custom-fields" role="tabpanel" aria-labelledby="custom-fields-tab">
     80                <?php aitepc_display_custom_fields_form($filtered_post_types); ?>
     81            </div>
     82
     83            <div class="tab-pane fade" id="coming-soon" role="tabpanel" aria-labelledby="coming-soon-tab">
     84                <div class="card aitepc-card text-center">
     85                    <div class="card-body">
     86                        <h2 class="card-title"><?php _e('Coming Soon', 'ait-easy-post-customization'); ?></h2>
     87                        <p class="card-text"><?php _e('Exciting new features are under development. Stay tuned for updates!', 'ait-easy-post-customization'); ?></p>
     88                        <p><?php _e('Have ideas or feedback? We’d love to hear from you.', 'ait-easy-post-customization'); ?></p>
     89                        <p><?php _e('Contact:', 'ait-easy-post-customization'); ?> <a href="mailto:[email protected]" class="text-decoration-none">[email protected]</a></p>
     90                        <div class="alert alert-info"><?php _e('Thank you for your patience and support!', 'ait-easy-post-customization'); ?></div>
     91                    </div>
     92                </div>
     93            </div>
     94        </div>
     95    </div>
     96    <?php
     97}
     98
     99// Function to handle custom fields form submissions
     100function aitepc_handle_custom_fields_submission() {
     101    if (!isset($_POST['aitepc_custom_fields_action'])) {
     102        return;
     103    }
     104
     105    if (!isset($_POST['aitepc_custom_fields_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['aitepc_custom_fields_nonce'])), 'aitepc_custom_fields_action')) {
     106        echo '<div class="alert alert-danger" role="alert">' . __('Security check failed. Please try again.', 'ait-easy-post-customization') . '</div>';
     107        return;
     108    }
     109
     110    $custom_fields = get_option('aitepc_custom_fields', array());
     111    $action = sanitize_text_field(wp_unslash($_POST['aitepc_custom_fields_action']));
     112
     113    if ($action === 'add' || $action === 'edit') {
     114        $key = sanitize_key(wp_unslash($_POST['field_key']));
     115        $label = sanitize_text_field(wp_unslash($_POST['field_label']));
     116        $type = sanitize_text_field(wp_unslash($_POST['field_type']));
     117        $post_types = isset($_POST['field_post_types']) ? array_map('sanitize_text_field', wp_unslash($_POST['field_post_types'])) : [];
     118
     119        if (empty($key) || empty($label) || empty($type)) {
     120            echo '<div class="alert alert-danger" role="alert">' . __('All fields are required.', 'ait-easy-post-customization') . '</div>';
     121            return;
     122        }
     123
     124        if ($action === 'add' && array_key_exists($key, $custom_fields)) {
     125            echo '<div class="alert alert-danger" role="alert">' . __('Field key already exists.', 'ait-easy-post-customization') . '</div>';
     126            return;
     127        }
     128
     129        $custom_fields[$key] = array(
     130            'label' => $label,
     131            'type' => $type,
     132            'post_types' => $post_types
     133        );
     134
     135        update_option('aitepc_custom_fields', $custom_fields);
     136        echo '<div class="alert alert-success" role="alert">' . __('Custom field ', 'ait-easy-post-customization') . ($action === 'add' ? __('added', 'ait-easy-post-customization') : __('updated', 'ait-easy-post-customization')) . __(' successfully!', 'ait-easy-post-customization') . '</div>';
     137    } elseif ($action === 'delete') {
     138        $key = sanitize_key(wp_unslash($_POST['field_key']));
     139        if (array_key_exists($key, $custom_fields)) {
     140            unset($custom_fields[$key]);
     141            update_option('aitepc_custom_fields', $custom_fields);
     142            echo '<div class="alert alert-success" role="alert">' . __('Custom field deleted successfully!', 'ait-easy-post-customization') . '</div>';
     143        }
     144    }
     145}
     146
     147// Function to display custom fields management
     148function aitepc_display_custom_fields_form($filtered_post_types) {
     149    $custom_fields = get_option('aitepc_custom_fields', array());
     150    $edit_key = isset($_GET['edit']) ? sanitize_key($_GET['edit']) : '';
     151    $edit_field = $edit_key && isset($custom_fields[$edit_key]) ? $custom_fields[$edit_key] : null;
     152    ?>
     153    <div class="card aitepc-card">
     154        <div class="card-body">
     155            <h2 class="card-title mb-4"><?php echo $edit_field ? __('Edit Custom Field', 'ait-easy-post-customization') : __('Add New Custom Field', 'ait-easy-post-customization'); ?></h2>
     156            <form method="post" class="needs-validation" novalidate>
     157                <?php wp_nonce_field('aitepc_custom_fields_action', 'aitepc_custom_fields_nonce'); ?>
     158                <input type="hidden" name="aitepc_custom_fields_action" value="<?php echo $edit_field ? 'edit' : 'add'; ?>">
     159                <?php if ($edit_field) : ?>
     160                    <input type="hidden" name="field_key" value="<?php echo esc_attr($edit_key); ?>">
     161                <?php endif; ?>
     162                <div class="mb-3">
     163                    <label for="field_label" class="form-label"><?php _e('Field Label', 'ait-easy-post-customization'); ?> <span class="text-danger">*</span></label>
     164                    <input type="text" class="form-control" id="field_label" name="field_label" value="<?php echo $edit_field ? esc_attr($edit_field['label']) : ''; ?>" required>
     165                    <div class="invalid-feedback"><?php _e('Please enter a field label.', 'ait-easy-post-customization'); ?></div>
     166                </div>
     167                <div class="mb-3">
     168                    <label for="field_key" class="form-label"><?php _e('Field Key (slug)', 'ait-easy-post-customization'); ?> <span class="text-danger">*</span></label>
     169                    <input type="text" class="form-control" id="field_key" name="field_key" value="<?php echo $edit_field ? esc_attr($edit_key) : ''; ?>" <?php echo $edit_field ? 'readonly' : 'required'; ?> pattern="[a-z0-9_]+">
     170                    <small class="form-text text-muted"><?php _e('Use lowercase letters, numbers, and underscores only. Cannot be changed after creation.', 'ait-easy-post-customization'); ?></small>
     171                    <div class="invalid-feedback"><?php _e('Please enter a valid field key (lowercase letters, numbers, underscores only).', 'ait-easy-post-customization'); ?></div>
     172                </div>
     173                <div class="mb-3">
     174                    <label for="field_type" class="form-label"><?php _e('Field Type', 'ait-easy-post-customization'); ?> <span class="text-danger">*</span></label>
     175                    <select class="form-select" id="field_type" name="field_type" required>
     176                        <option value="text" <?php selected($edit_field ? $edit_field['type'] : '', 'text'); ?>><?php _e('Text', 'ait-easy-post-customization'); ?></option>
     177                        <option value="textarea" <?php selected($edit_field ? $edit_field['type'] : '', 'textarea'); ?>><?php _e('Textarea', 'ait-easy-post-customization'); ?></option>
     178                        <option value="date" <?php selected($edit_field ? $edit_field['type'] : '', 'date'); ?>><?php _e('Date', 'ait-easy-post-customization'); ?></option>
     179                    </select>
     180                    <div class="invalid-feedback"><?php _e('Please select a field type.', 'ait-easy-post-customization'); ?></div>
     181                </div>
     182                <div class="mb-4">
     183                    <h5 class="mb-3"><?php _e('Select Post Types', 'ait-easy-post-customization'); ?></h5>
    79184                    <div class="row">
    80185                        <?php foreach ($filtered_post_types as $post_type) :
    81                             $checked = in_array($post_type->name, $selected_post_types) ? 'checked="checked"' : ''; ?>
     186                            $checked = $edit_field && in_array($post_type->name, $edit_field['post_types']) ? 'checked="checked"' : ''; ?>
    82187                            <div class="col-md-4 mb-3 d-flex align-items-center">
    83                                 <input type="checkbox" class="form-check-input me-2" name="aitepc_expiry_date_post_types[]" value="<?php echo esc_attr($post_type->name); ?>" <?php echo esc_attr($checked); ?> id="aitepc_<?php echo esc_attr($post_type->name); ?>">
    84                                 <label class="form-check-label" for="aitepc_<?php echo esc_attr($post_type->name); ?>">
     188                                <input type="checkbox" class="form-check-input me-2" name="field_post_types[]" value="<?php echo esc_attr($post_type->name); ?>" <?php echo esc_attr($checked); ?> id="field_<?php echo esc_attr($post_type->name); ?>">
     189                                <label class="form-check-label" for="field_<?php echo esc_attr($post_type->name); ?>">
    85190                                    <?php echo esc_html($post_type->label); ?>
    86191                                </label>
     
    88193                        <?php endforeach; ?>
    89194                    </div>
    90                     <button type="submit" class="btn btn-primary mt-3">Save Changes</button>
    91                 </form>
    92             </div>
    93 
    94             <!-- Second tab for coming soon -->
    95             <div class="tab-pane fade" id="coming-soon" role="tabpanel" aria-labelledby="coming-soon-tab">
    96                 <div class="text-center">
    97                     <h4>Coming Soon</h4>
    98                     <p>This feature is currently under development. Stay tuned for updates!</p>
    99                     <p>We’d love to hear your feedback! Let us know what features you’d like to see in the upcoming release.</p>
    100                     <p>Contact: <a href="mailto:[email protected]">[email protected]</a></p>
    101                     <div class="alert alert-info" role="alert">
    102                         We appreciate your patience and support!
    103                     </div>
    104                 </div>
    105             </div>
     195                </div>
     196                <div class="d-flex gap-2">
     197                    <button type="submit" class="btn btn-primary aitepc-btn"><?php echo $edit_field ? __('Update Field', 'ait-easy-post-customization') : __('Add Field', 'ait-easy-post-customization'); ?></button>
     198                    <?php if ($edit_field) : ?>
     199                        <a href="<?php echo esc_url(admin_url('admin.php?page=aitepc-expiry-date-settings')); ?>" class="btn btn-outline-secondary"><?php _e('Cancel', 'ait-easy-post-customization'); ?></a>
     200                    <?php endif; ?>
     201                </div>
     202            </form>
    106203        </div>
    107204    </div>
     205
     206    <div class="card aitepc-card mt-4">
     207        <div class="card-body">
     208            <h2 class="card-title mb-4"><?php _e('Existing Custom Fields', 'ait-easy-post-customization'); ?></h2>
     209            <?php if (!empty($custom_fields)) : ?>
     210                <div class="table-responsive">
     211                    <table class="table table-hover aitepc-table">
     212                        <thead>
     213                            <tr>
     214                                <th><?php _e('Label', 'ait-easy-post-customization'); ?></th>
     215                                <th><?php _e('Key', 'ait-easy-post-customization'); ?></th>
     216                                <th><?php _e('Type', 'ait-easy-post-customization'); ?></th>
     217                                <th><?php _e('Post Types', 'ait-easy-post-customization'); ?></th>
     218                                <th><?php _e('Actions', 'ait-easy-post-customization'); ?></th>
     219                            </tr>
     220                        </thead>
     221                        <tbody>
     222                            <?php foreach ($custom_fields as $key => $field) : ?>
     223                                <tr>
     224                                    <td><?php echo esc_html($field['label']); ?></td>
     225                                    <td><?php echo esc_html($key); ?></td>
     226                                    <td><?php echo esc_html($field['type']); ?></td>
     227                                    <td><?php echo esc_html(implode(', ', $field['post_types'])); ?></td>
     228                                    <td>
     229                                        <a href="<?php echo esc_url(add_query_arg('edit', $key, admin_url('admin.php?page=aitepc-expiry-date-settings'))); ?>" class="btn btn-sm btn-primary aitepc-btn me-1"><?php _e('Edit', 'ait-easy-post-customization'); ?></a>
     230                                        <form method="post" style="display:inline;">
     231                                            <?php wp_nonce_field('aitepc_custom_fields_action', 'aitepc_custom_fields_nonce'); ?>
     232                                            <input type="hidden" name="aitepc_custom_fields_action" value="delete">
     233                                            <input type="hidden" name="field_key" value="<?php echo esc_attr($key); ?>">
     234                                            <button type="submit" class="btn btn-sm btn-danger aitepc-btn" onclick="return confirm('<?php esc_attr_e('Are you sure you want to delete this field?', 'ait-easy-post-customization'); ?>');"><?php _e('Delete', 'ait-easy-post-customization'); ?></button>
     235                                        </form>
     236                                    </td>
     237                                </tr>
     238                            <?php endforeach; ?>
     239                        </tbody>
     240                    </table>
     241                </div>
     242            <?php else : ?>
     243                <p class="text-muted"><?php _e('No custom fields added yet.', 'ait-easy-post-customization'); ?></p>
     244            <?php endif; ?>
     245        </div>
     246    </div>
     247    <script>
     248        // Bootstrap form validation
     249        (function () {
     250            'use strict';
     251            const forms = document.querySelectorAll('.needs-validation');
     252            Array.from(forms).forEach(form => {
     253                form.addEventListener('submit', event => {
     254                    if (!form.checkValidity()) {
     255                        event.preventDefault();
     256                        event.stopPropagation();
     257                    }
     258                    form.classList.add('was-validated');
     259                }, false);
     260            });
     261        })();
     262    </script>
    108263    <?php
    109264}
    110 ?>
  • ait-easy-post-customization/trunk/readme.txt

    r3353149 r3358149  
    11=== AIT Easy Post Customization ===
    22Contributors: Muhammad Kamran
    3 Tags:  post expiration, post expiry, expiry date, schedule post, auto expire
    4 Requires at least: 5.0 
    5 Tested up to: 6.6
    6 Requires PHP: 7.2
    7 Stable tag: 1.0.
    8 License: GPLv2 or later 
    9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 
     3Tags: post expiration, post expiry, expiry date, schedule post, auto expire, custom fields
     4Requires at least: 5.0
     5Tested up to: 6.8
     6Requires PHP: 7.4
     7Stable tag: 1.0.2
     8License: GPLv2 or later
     9License URI: https://www.gnu.org/licenses/gpl-2.0.html
    1010
    1111Easily set expiry dates for posts and custom post types, automatically unpublishing content when it becomes outdated.
    1212
    13 == AIT Easy Post Customization ==
     13== Description ==
    1414
    1515AIT Easy Post Customization is a powerful yet easy-to-use plugin designed to give users control over the lifespan of their posts and custom post types by allowing you to set an expiry date. If you're managing time-sensitive content, like event announcements, special promotions, or limited-time offers, this plugin automates the process of unpublishing or archiving content, making content management hassle-free.
    16 What problem does this plugin solve?
     16
     17**What problem does this plugin solve?**
    1718
    1819Manually tracking and updating expired content can be tedious and prone to errors, especially if you have a large volume of posts. Without this plugin, expired content can remain live, leading to outdated or irrelevant information on your website. AIT Easy Post Customization solves this problem by allowing you to set expiry dates on posts, ensuring that content is automatically hidden or removed after the specified date. This keeps your site fresh and up-to-date without manual intervention.
    19 How does it improve the user experience?
    2020
    21     1. Automatic Expiry Handling: Set an expiration date for any post or custom post type, and let the plugin automatically unpublish it when the time comes. This eliminates the need for manual updates and improves content accuracy.
    22     2. Custom Post Type Support: Whether you're using standard WordPress posts or custom post types (like events, job listings, products, etc.), you can easily add expiry functionality to all of them.
    23     3. User-Friendly Interface: The plugin integrates seamlessly with the WordPress editor, making it easy for users of all skill levels to manage expiry dates. The expiry date can be set directly from the post editing screen.
     21**How does it improve the user experience?**
    2422
    25 Key Features:
     231. **Automatic Expiry Handling**: Set an expiration date for any post or custom post type, and let the plugin automatically unpublish it when the time comes. This eliminates the need for manual updates and improves content accuracy.
     242. **Custom Post Type Support**: Whether you're using standard WordPress posts or custom post types (like events, job listings, products, etc.), you can easily add expiry functionality to all of them.
     253. **User-Friendly Interface**: The plugin integrates seamlessly with the WordPress editor, making it easy for users of all skill levels to manage expiry dates. The expiry date can be set directly from the post editing screen.
     264. **Custom Fields Management**: Add custom fields (text, textarea, date) to posts for enhanced content customization.
     275. **Modern Admin Interface**: A sleek, responsive admin panel with sticky tabs, form validation, and intuitive navigation.
    2628
    27     1. Post Expiration: Set expiration dates for posts and custom post types, and automatically unpublish them when the time is up.
    28     2. Customizable Actions: Choose what happens to the post after it expires (e.g., move to draft, delete, or do nothing).
    29     3. Supports All Post Types: Works with standard WordPress posts and custom post types, allowing flexible use across various content types.
    30     4. Seamless Integration: Integrated into the post editor, making it easy to manage for both beginners and advanced users.
    31     5. Scheduled Content Management: Perfect for managing content like event updates, limited-time offers, and seasonal announcements.
     29**Key Features**:
    3230
    33 Notable Features:
     311. **Post Expiration**: Set expiration dates for posts and custom post types, automatically moving them to draft status when expired.
     322. **Custom Fields**: Add and manage custom fields (text, textarea, date) for selected post types.
     333. **Supports All Post Types**: Works with standard WordPress posts and custom post types, allowing flexible use across various content types.
     344. **Seamless Integration**: Integrated into the post editor with a modern, user-friendly interface.
     355. **Scheduled Content Management**: Perfect for managing content like event updates, limited-time offers, and seasonal announcements.
     366. **Localization Ready**: Fully translation-ready for multilingual websites.
    3437
    35     1. Custom Widgets: Optionally display a widget that shows upcoming or recently expired content to site admins for better tracking.
    36     2. Developer-Friendly Hooks and Filters: Developers can further customize the plugin’s behavior using built-in hooks and filters.
    37     3. Localization Ready: Fully translation-ready, making it suitable for websites in any language.
     38**Notable Features**:
     39
     401. **Custom Widgets**: Optionally display a widget that shows upcoming or recently expired content to site admins for better tracking (coming soon).
     412. **Developer-Friendly Hooks and Filters**: Developers can customize the plugin’s behavior using built-in hooks and filters.
     423. **Modern Design**: Features a responsive admin interface with sticky tabs, Dashicons, and gradient effects for a premium experience.
    3843
    3944With AIT Easy Post Customization, you’ll never have to worry about outdated or irrelevant content cluttering your site again. Keep your content fresh, current, and timely with minimal effort.
     
    4348Follow these steps to install and activate AIT Easy Post Customization:
    4449
    45     Upload Method:
    46         1. Upload the plugin files to the /wp-content/plugins/ait-easy-post-customization/ directory.
     50**Upload Method**:
     511. Upload the plugin files to the `/wp-content/plugins/ait-easy-post-customization/` directory.
    4752
    48     OR
     53**OR**
    4954
    50     Direct Install via WordPress:
    51         1. Go to the WordPress dashboard, navigate to Plugins -> Add New, and search for AIT Easy Post Customization. Click Install Now.
     55**Direct Install via WordPress**:
     561. Go to the WordPress dashboard, navigate to Plugins -> Add New, and search for AIT Easy Post Customization. Click Install Now.
    5257
    53     Activate the Plugin:
    54         1. Once installed, go to the Plugins screen in WordPress and click Activate next to AIT Easy Post Customization.
     58**Activate the Plugin**:
     591. Once installed, go to the Plugins screen in WordPress and click Activate next to AIT Easy Post Customization.
    5560
    56     Configure the Plugin:
    57         1. After activation, a new menu item called AIT Expiry Date will appear in the WordPress sidebar. Click on it to access the plugin settings and configure the expiry date options as needed.
     61**Configure the Plugin**:
     621. After activation, a new menu item called **Easy Post Customization** will appear in the WordPress sidebar. Click on it to access the plugin settings and configure the expiry date and custom field options as needed.
    5863
    5964== Frequently Asked Questions ==
    6065
    61 = 1. What is AIT Easy Post Customization? =
    62 AIT Easy Post Customization is a WordPress plugin that allows users to easily set expiry dates for posts and custom post types, helping to manage content visibility and relevance effectively.
     66=== 1. What is AIT Easy Post Customization? ===
     67AIT Easy Post Customization is a WordPress plugin that allows users to set expiry dates for posts and custom post types and manage custom fields, ensuring content remains relevant and up-to-date.
    6368
    6469=== 2. How do I install the plugin? ===
    6570You can install the plugin by uploading the plugin files to the `/wp-content/plugins/ait-easy-post-customization/` directory or by installing it directly through the WordPress plugins screen. After installation, activate the plugin through the 'Plugins' screen in WordPress.
    6671
    67 === 3. Where can I configure the expiry date settings? ===
    68 After activating the plugin, you can configure the expiry date settings by navigating to the **AIT Expiry Date** link in the WordPress sidebar. Here, you can manage expiry settings for your posts and custom post types.
     72=== 3. Where can I configure the settings? ===
     73After activating the plugin, you can configure settings by navigating to the **Easy Post Customization** link in the WordPress sidebar. Here, you can manage expiry dates and custom fields for your posts and custom post types.
    6974
    7075=== 4. Can I set an expiry date for custom post types? ===
     
    7277
    7378=== 5. What happens to a post when it expires? ===
    74 Once a post expires, it will be automatically hidden from public view. You can also configure settings to notify users or take specific actions when a post expires.
     79Once a post expires, it will be automatically moved to draft status, hiding it from public view. Future updates may include options for other actions like deletion.
    7580
    7681=== 6. Is there any support available if I encounter issues? ===
     
    8388Yes, AIT Easy Post Customization is completely free to use and is licensed under the GPLv2 or later.
    8489
     90== Screenshots ==
     911. Admin settings page with modern tabbed interface and sticky navigation.
     922. Expiry date metabox on a post edit screen.
     933. Custom fields metabox on a post edit screen.
     94
    8595== Changelog ==
     96= 1.0.2 - 2025-09-09 =
     97* Changed admin menu name from "AIT Expiry Date" to "Easy Post Customization" for better branding.
     98* Introduced modern admin interface with custom CSS (`aitepc-admin.css`), sticky tabs, Dashicons, and gradient effects.
     99* Added client-side form validation for custom fields with inline feedback for improved usability.
     100* Enhanced custom fields table with sticky headers and hover effects for better navigation.
     101* Optimized CSS with variables for maintainability and improved responsive design.
     102* Improved security with proper sanitization, nonce verification, and output escaping.
     103* Ensured compatibility with WordPress 6.6 and PHP 7.2+.
    86104
    87 = 1.0.1 =
     105= 1.0.1 - 2025-09-01 =
    88106* Initial release of AIT Easy Post Customization.
    89107* Added functionality to set expiry dates for posts and custom post types.
    90108* Integrated user-friendly interface for managing expiry settings.
     109* Added custom fields management for text, textarea, and date fields.
     110
     111== Upgrade Notice ==
     112= 1.0.2 =
     113This update introduces a modern admin interface with sticky tabs, form validation, and enhanced usability. The menu name is now "Easy Post Customization" for consistency. Update for a more user-friendly experience.
    91114
    92115== License & Copyright ==
    93 
    94 This plugin is licensed under the GPLv2 or later. 
     116This plugin is licensed under the GPLv2 or later.
    95117You can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation.
    96118
     
    98120
    99121== Contact ==
    100 
    101122For inquiries, project discussions, or collaboration opportunities, feel free to reach out to me:
    102123
    103 - Email: [[email protected]](mailto:[email protected]) 
    104 - LinkedIn: [Muhammad Kamran](https://linkedin.com/in/muhammad-kamran-64a33a166) 
     124- Email: [[email protected]](mailto:[email protected])
     125- LinkedIn: [Muhammad Kamran](https://linkedin.com/in/muhammad-kamran-64a33a166)
    105126
    106127I look forward to connecting with you!
    107 
Note: See TracChangeset for help on using the changeset viewer.