$post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'fields' => 'ids', 'no_found_rows' => true, 'meta_query' => array( array( 'key' => '_aitepc_expiry_date', 'value' => $tomorrow, 'compare' => '<', 'type' => 'DATE', ), ), ); $expired_ids = get_posts( $args ); foreach ( $expired_ids as $post_id ) { aitepc_process_expiry_action( $post_id ); } } // --------------------------------------------------------------------------- // Register post meta for REST / Gutenberg // --------------------------------------------------------------------------- add_action( 'init', 'aitepc_register_post_meta' ); /** * Expose plugin post-meta keys to the REST API so the Gutenberg sidebar * can read and write them via the core/editor data store. * Called on 'init' to ensure post types are registered first. */ function aitepc_register_post_meta() { $post_types = get_option( 'aitepc_expiry_date_post_types', array( 'post' ) ); if ( empty( $post_types ) || ! is_array( $post_types ) ) { return; } $meta_configs = array( '_aitepc_expiry_date' => array( 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'description' => 'Post expiry date (Y-m-d)', ), '_aitepc_expiry_action' => array( 'type' => 'string', 'sanitize_callback' => 'sanitize_key', 'description' => 'Action taken when the post expires', ), '_aitepc_redirect_url' => array( 'type' => 'string', 'sanitize_callback' => 'esc_url_raw', 'description' => 'Redirect destination URL (used with redirect action)', ), ); foreach ( $post_types as $post_type ) { foreach ( $meta_configs as $meta_key => $config ) { register_meta( 'post', $meta_key, array( 'object_subtype' => $post_type, 'type' => $config['type'], 'description' => $config['description'], 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => $config['sanitize_callback'], 'auth_callback' => static function () { return current_user_can( 'edit_posts' ); }, ) ); } } } // --------------------------------------------------------------------------- // Translations // --------------------------------------------------------------------------- add_action( 'plugins_loaded', 'aitepc_load_textdomain' ); /** * Load plugin text domain for translations. */ function aitepc_load_textdomain() { load_plugin_textdomain( 'ait-easy-post-customization', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); } // --------------------------------------------------------------------------- // Settings API: post-type selection // --------------------------------------------------------------------------- add_action( 'admin_init', 'aitepc_register_settings' ); /** * Register the post-type selection option and its settings fields. */ function aitepc_register_settings() { register_setting( 'aitepc_expiry_group', 'aitepc_expiry_date_post_types', array( 'sanitize_callback' => 'aitepc_sanitize_post_types', 'default' => array( 'post' ), ) ); add_settings_section( 'aitepc_post_types_section', __( 'Select Post Types for Expiry Date Metabox', 'ait-easy-post-customization' ), null, 'aitepc-expiry-date-settings' ); $all_post_types = get_post_types( array( 'public' => true ), 'objects' ); $filtered_post_types = array_filter( $all_post_types, static function ( $post_type ) { return ! in_array( $post_type->name, array( 'page', 'attachment' ), true ); } ); foreach ( $filtered_post_types as $post_type ) { add_settings_field( 'aitepc_pt_' . $post_type->name, $post_type->label, 'aitepc_pt_checkbox_cb', 'aitepc-expiry-date-settings', 'aitepc_post_types_section', array( 'pt' => $post_type->name ) ); } } /** * Sanitize the post types option — array of strings. * * @param mixed $input Raw option value. * @return array Sanitized array of post-type slugs. */ function aitepc_sanitize_post_types( $input ) { return is_array( $input ) ? array_map( 'sanitize_text_field', $input ) : array(); } /** * Render a single post-type checkbox for the Settings API. * * @param array $args Field arguments containing 'pt' (post type slug). */ function aitepc_pt_checkbox_cb( $args ) { $options = get_option( 'aitepc_expiry_date_post_types', array() ); $checked = in_array( $args['pt'], $options, true ) ? 'checked' : ''; printf( '', esc_attr( $args['pt'] ), $checked ); } // --------------------------------------------------------------------------- // File includes — order matters (actions file before cron uses it) // --------------------------------------------------------------------------- require_once plugin_dir_path( __FILE__ ) . 'functions.php'; require_once plugin_dir_path( __FILE__ ) . 'plugin-files/aitepc-expiry-actions.php'; require_once plugin_dir_path( __FILE__ ) . 'plugin-files/aitepc-email-notifications.php'; require_once plugin_dir_path( __FILE__ ) . 'plugin-files/aitepc-rest-api.php'; require_once plugin_dir_path( __FILE__ ) . 'plugin-files/aitepc-settings.php'; require_once plugin_dir_path( __FILE__ ) . 'plugin-files/aitepc-expiry-metabox.php'; require_once plugin_dir_path( __FILE__ ) . 'plugin-files/aitepc-custom-fields.php';