admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'metaforge_post_order_nonce' ), ) ); } public function admin_menu() { // 1. Main Settings Page (hidden from sidebar, accessible via header nav) add_submenu_page( null, 'Post Order', 'Post Order', 'manage_metaforge', 'metaforge_post_order', array( $this, 'settings_page' ) ); // 2. Dynamic Re-order Submenus $settings = get_option( $this->settings_key, array() ); $enabled_types = $settings['enabled_post_types'] ?? array(); if ( ! empty( $enabled_types ) ) { foreach ( $enabled_types as $post_type ) { $pt_obj = get_post_type_object( $post_type ); if ( ! $pt_obj ) { continue; } add_submenu_page( 'edit.php?post_type=' . $post_type, 'Re-order ' . $pt_obj->labels->name, 'Re-order', 'edit_posts', // Standard WP capability for editing posts 'metaforge_reorder_' . $post_type, function () use ( $post_type, $pt_obj ) { $this->reorder_page( $post_type, $pt_obj ); } ); } } } public function register_settings() { register_setting( 'metaforge_post_order_group', $this->settings_key, array( $this, 'sanitize_settings' ) ); } public function sanitize_settings( $input ) { $sanitized = array(); $sanitized['enabled_post_types'] = is_array( $input['enabled_post_types'] ?? null ) ? array_map( 'sanitize_key', $input['enabled_post_types'] ) : array(); $sanitized['auto_apply'] = isset( $input['auto_apply'] ) ? '1' : '0'; $sanitized['admin_auto_apply'] = isset( $input['admin_auto_apply'] ) ? '1' : '0'; return $sanitized; } /** * Settings Page UI */ public function settings_page() { if ( ! current_user_can( 'manage_metaforge' ) ) { return; } $settings = get_option( $this->settings_key, array( 'enabled_post_types' => array(), 'auto_apply' => '0', 'admin_auto_apply' => '0', ) ); $post_types = get_post_types( array( 'public' => true ), 'objects' ); unset( $post_types['attachment'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only notice query flag. $saved = ( isset( $_GET['settings-updated'] ) && sanitize_text_field( wp_unslash( $_GET['settings-updated'] ) ) === 'true' ); ?>

Post Types Order Settings

← Back

General Settings
Post Types Select post types to enable re-ordering.
Options Configure how order is applied.
$post_type, 'posts_per_page' => -1, 'orderby' => 'menu_order', 'order' => 'ASC', 'post_status' => 'any', ) ); ?>

Re-order labels->name ); ?>

  • No items found for this post type.
  • post_title ?: '(no title)' ); ?> #ID ); ?>
'Permission denied.' ) ); } $order = isset( $_POST['order'] ) && is_array( $_POST['order'] ) ? array_map( 'intval', wp_unslash( $_POST['order'] ) ) : array(); if ( empty( $order ) ) { wp_send_json_error( array( 'message' => 'No order data received.' ) ); } global $wpdb; // Build single batched CASE WHEN query for high performance with 100+ items $case_sql = array(); $ids = array(); foreach ( $order as $index => $post_id ) { $post_id = absint( $post_id ); if ( $post_id <= 0 ) { continue; } $case_sql[] = $wpdb->prepare( 'WHEN ID = %d THEN %d', $post_id, (int) $index ); $ids[] = $post_id; } if ( ! empty( $case_sql ) && ! empty( $ids ) ) { $ids_placeholder = implode( ',', $ids ); $cases_string = implode( ' ', $case_sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Batched case update with prepared clauses and sanitized integer IDs. $wpdb->query( "UPDATE {$wpdb->posts} SET menu_order = CASE {$cases_string} ELSE menu_order END WHERE ID IN ({$ids_placeholder})" ); foreach ( $ids as $pid ) { clean_post_cache( $pid ); } } wp_send_json_success( array( 'message' => 'Order saved successfully!' ) ); } /** * Apply custom order to queries */ public function apply_custom_order( $query ) { // Don't modify if suppressed or if orderby is already set manually in a specific way if ( $query->get( 'metaforge_suppress_sort' ) ) { return; } $settings = get_option( $this->settings_key, array() ); if ( empty( $settings['enabled_post_types'] ) ) { return; } $post_type = $query->get( 'post_type' ); // Handle array of post types if ( is_array( $post_type ) ) { $is_enabled = false; foreach ( $post_type as $pt ) { if ( in_array( $pt, $settings['enabled_post_types'] ) ) { $is_enabled = true; break; } } } else { $is_enabled = in_array( $post_type, $settings['enabled_post_types'] ); } if ( ! $is_enabled ) { return; } // Check if we should apply in admin if ( is_admin() ) { if ( empty( $settings['admin_auto_apply'] ) || $settings['admin_auto_apply'] !== '1' ) { return; } // Only apply to the main list table query in admin if ( ! $query->is_main_query() ) { return; } } else { // Frontend if ( empty( $settings['auto_apply'] ) || $settings['auto_apply'] !== '1' ) { return; } } // Apply sorting $query->set( 'orderby', 'menu_order' ); $query->set( 'order', 'ASC' ); } }