<?php
/**
 * Name: Change Post Type
 * Description: Switch posts between different post types using dropdown in post editor sidebar or bulk actions to convert posts to pages or custom post types
 * Category: Content
 * Icon: -
 * UseCases: [
 *   {
 *     "title": "Content Migration",
 *     "description": "Convert 50 blog posts to 'Case Studies' custom post type after restructuring site architecture without losing content or metadata."
 *   },
 *   {
 *     "title": "Correct Mistakes",
 *     "description": "Quickly fix content published to wrong post type, like products accidentally created as posts instead of WooCommerce products."
 *   },
 *   {
 *     "title": "Site Restructuring",
 *     "description": "Transform pages into posts or vice versa when reorganizing site structure without manual copy-paste of content."
 *   }
 * ]
 * Added: 2025-09-01
 * Tags: post-type, convert, switch, change, migration
 * WhereToFind: {
 *   "location": "Post editor sidebar or bulk actions",
 *   "url": "",
 *   "instructions": "Use dropdown in publish box or bulk actions menu",
 *   "newTab": false
 * }
 */

// Prevent direct access
if (!defined('ABSPATH')) exit;

class SwitchboardChangePostType {

    public function __construct() {
        add_action('post_submitbox_misc_actions', [$this, 'add_post_type_selector']);
        add_action('save_post', [$this, 'save_post_type_change'], 10, 2);
        add_filter('bulk_actions-edit-post', [$this, 'add_bulk_action']);
        add_filter('bulk_actions-edit-page', [$this, 'add_bulk_action']);
        add_filter('handle_bulk_actions-edit-post', [$this, 'handle_bulk_action'], 10, 3);
        add_filter('handle_bulk_actions-edit-page', [$this, 'handle_bulk_action'], 10, 3);
    }

    /**
     * Register data locations for cleanup system
     */
    public function register_data_locations() {
        return [
            'options' => [],
            'option_patterns' => [],
            'tables' => [],
            'post_meta' => [],
            'user_meta' => [],
        ];
    }
    
    public function add_post_type_selector() {
        global $post;

        if (!$post || !current_user_can('edit_post', $post->ID)) {
            return;
        }

        $post_types = get_post_types(['show_ui' => true], 'objects');
        unset($post_types['attachment']); // Remove media

        ?>
        <div class="misc-pub-section">
            <label for="switchboard_post_type"><strong><?php esc_html_e('Post Type:', 'wpswitchboard'); ?></strong></label>
            <select name="switchboard_post_type" id="switchboard_post_type" style="margin-top: 5px; width: 100%;">
                <?php foreach ($post_types as $type):
                    if (!is_object($type) || !isset($type->name, $type->labels->singular_name)) {
                        continue;
                    }
                ?>
                <option value="<?php echo esc_attr($type->name); ?>" <?php selected($post->post_type, $type->name); ?>>
                    <?php echo esc_html($type->labels->singular_name); ?>
                </option>
                <?php endforeach; ?>
            </select>
            <?php wp_nonce_field('change_post_type', 'change_post_type_nonce'); ?>
        </div>
        <?php
    }
    
    public function save_post_type_change($post_id, $post) {
        if (!isset($_POST['change_post_type_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['change_post_type_nonce'])), 'change_post_type')) {
            return;
        }
        
        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }
        
        if (!current_user_can('edit_post', $post_id)) {
            return;
        }
        
        if (isset($_POST['switchboard_post_type']) && $_POST['switchboard_post_type'] !== $post->post_type) {
            $new_type = sanitize_key($_POST['switchboard_post_type']);
            
            // Verify the post type exists
            if (post_type_exists($new_type)) {
                set_post_type($post_id, $new_type);
            }
        }
    }
    
    public function add_bulk_action($actions) {
        $post_types = get_post_types(['show_ui' => true], 'objects');
        unset($post_types['attachment']);

        foreach ($post_types as $type) {
            if (!is_object($type) || !isset($type->name, $type->labels->singular_name)) {
                continue;
            }
            /* translators: %s: post type singular name */
            $actions['change_type_' . $type->name] = sprintf(__('Change to %s', 'wpswitchboard'), $type->labels->singular_name);
        }

        return $actions;
    }
    
    public function handle_bulk_action($redirect_to, $action, $post_ids) {
        if (strpos($action, 'change_type_') !== 0) {
            return $redirect_to;
        }
        
        $new_type = str_replace('change_type_', '', $action);
        
        if (!post_type_exists($new_type)) {
            return $redirect_to;
        }
        
        $changed = 0;
        foreach ($post_ids as $post_id) {
            if (current_user_can('edit_post', $post_id)) {
                set_post_type($post_id, $new_type);
                $changed++;
            }
        }
        
        $redirect_to = add_query_arg('changed_post_type', $changed, $redirect_to);
        return $redirect_to;
    }
}

$switchboard_instance = new SwitchboardChangePostType();
Switchboard_Data_Registry::get_instance()->auto_register($switchboard_instance, __FILE__);

// Show admin notice after bulk change
add_action('admin_notices', function() {
    // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display-only admin notice after redirect
    if (isset($_GET['changed_post_type']) && !empty($_GET['changed_post_type'])) {
        $count = intval($_GET['changed_post_type']); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        echo '<div class="notice notice-success is-dismissible"><p>';
        /* translators: %s: number of posts changed */
        printf(esc_html(_n('%s post type changed.', '%s post types changed.', $count, 'wpswitchboard')), esc_html(number_format_i18n($count)));
        echo '</p></div>';
    }
});
