Changeset 3343286
- Timestamp:
- 08/12/2025 05:37:45 AM (7 months ago)
- Location:
- default-post-author
- Files:
-
- 4 edited
- 1 copied
-
tags/2.0 (copied) (copied from default-post-author/trunk)
-
tags/2.0/default-post-author.php (modified) (1 diff)
-
tags/2.0/readme.txt (modified) (3 diffs)
-
trunk/default-post-author.php (modified) (1 diff)
-
trunk/readme.txt (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
default-post-author/tags/2.0/default-post-author.php
r3230262 r3343286 1 1 <?php 2 3 2 /** 4 3 * Plugin Name: Default Post Author 5 * Plugin URI: https://wordpress.org/plugins/default-post-author/4 * Plugin URI: https://wordpress.org/plugins/default-post-author/ 6 5 * Description: The easiest way to set default post author in your WordPress Site. 7 * Version: 1.1.56 * Version: 2.0 8 7 * Requires at least: 6.1 9 * Requires PHP: 7.410 * Author: MonarchWP11 * Author URI: https://www.monarchwp.com12 * License: GPL v2 or later8 * Requires PHP: 8.0 9 * Author: MonarchWP 10 * Author URI: https://www.monarchwp.com 11 * License: GPL v2 or later 13 12 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 14 13 * Text Domain: default-post-author 15 * Domain Path: /languages 16 */ 17 18 if (!defined('ABSPATH')) { 19 die; // Exit if accessed directly 20 } 21 22 /** 23 * Load plugin textdomain. 24 */ 25 function dpap_load_textdomain() { 26 load_plugin_textdomain('default-post-author', false, dirname(plugin_basename(__FILE__)) . '/languages'); 27 } 28 add_action('plugins_loaded', 'dpap_load_textdomain'); 29 30 31 // Add the field to the general settings page 32 function dpap_add_author_setting_field() { 33 add_settings_field( 34 'default_post_author', // ID of the settings field 35 __('Default Post Author', 'default-post-author'), // Title of the field 36 'dpap_default_post_author_field_html', // Function to display the field 37 'general' // Page to add the field to (General Settings page) 14 */ 15 16 if ( ! defined( 'ABSPATH' ) ) { 17 exit; // Exit if accessed directly. 18 } 19 20 /** 21 * Option name constant. 22 */ 23 if ( ! defined( 'DPAP_OPTION_NAME' ) ) { 24 define( 'DPAP_OPTION_NAME', 'default_post_author' ); 25 } 26 27 /** 28 * Register setting for storing default author ID. 29 */ 30 function dpap_register_setting() { 31 register_setting( 32 'dpap_options_group', 33 DPAP_OPTION_NAME, 34 array( 35 'type' => 'integer', 36 'sanitize_callback' => 'absint', 37 'default' => 1, 38 ) 38 39 ); 39 40 // Register the setting 41 register_setting('general', 'default_post_author', array( 42 'type' => 'integer', 43 'description' => 'Default author ID for new posts', 44 'sanitize_callback' => 'absint', // Ensure the value is an absolute integer 45 'default' => 1 // Default value if not set 46 )); 47 } 48 add_action('admin_init', 'dpap_add_author_setting_field'); 49 50 // HTML for the settings field 51 function dpap_default_post_author_field_html() { 52 $value = get_option('default_post_author', 1); // Get the current value, default to 1 53 54 // Fetch users with 'Author', 'Editor', or 'Administrator' roles 55 $user_query = new WP_User_Query(array( 56 'role__in' => array('Author', 'Editor', 'Administrator'), // Array of roles 57 'orderby' => 'display_name', 58 'order' => 'ASC' 59 )); 40 } 41 add_action( 'admin_init', 'dpap_register_setting' ); 42 43 /** 44 * Add settings page under Settings menu. 45 */ 46 function dpap_add_admin_menu() { 47 add_options_page( 48 __( 'Default Post Author', 'default-post-author' ), 49 __( 'Default Post Author', 'default-post-author' ), 50 'manage_options', 51 'default-post-author', 52 'dpap_render_options_page' 53 ); 54 } 55 add_action( 'admin_menu', 'dpap_add_admin_menu' ); 56 57 /** 58 * Render the options page HTML. The form posts to admin-post.php handlers. 59 */ 60 function dpap_render_options_page() { 61 if ( ! current_user_can( 'manage_options' ) ) { 62 return; 63 } 64 65 $current_value = get_option( DPAP_OPTION_NAME, 1 ); 66 67 // Fetch users with roles author, editor, administrator. 68 $user_query = new WP_User_Query( array( 69 'role__in' => array( 'author', 'editor', 'administrator' ), 70 'orderby' => 'display_name', 71 'order' => 'ASC', 72 ) ); 60 73 61 74 $users = $user_query->get_results(); 62 63 // Create a dropdown list of users 64 echo '<select id="default_post_author" name="default_post_author">'; 65 foreach ($users as $user) { 66 echo '<option value="' . esc_attr($user->ID) . '"' . selected($user->ID, $value, false) . '>' . esc_html($user->display_name) . '</option>'; 67 } 68 echo '</select>'; 69 } 70 71 // Set the default author for new posts 75 ?> 76 <div class="wrap"> 77 <h1><?php esc_html_e( 'Default Post Author Settings', 'default-post-author' ); ?></h1> 78 79 <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"> 80 <?php // Settings fields for WP Settings API (keeps option group consistent). 81 settings_fields( 'dpap_options_group' ); ?> 82 83 <table class="form-table" role="presentation"> 84 <tr> 85 <th scope="row"><label for="default_post_author"><?php esc_html_e( 'Default Post Author', 'default-post-author' ); ?></label></th> 86 <td> 87 <select id="default_post_author" name="default_post_author"> 88 <?php if ( empty( $users ) ) : ?> 89 <option value="0"><?php esc_html_e( 'No eligible users found', 'default-post-author' ); ?></option> 90 <?php else : ?> 91 <?php foreach ( $users as $user ) : ?> 92 <option value="<?php echo esc_attr( $user->ID ); ?>" <?php selected( $user->ID, $current_value ); ?>> 93 <?php echo esc_html( $user->display_name ); ?> 94 </option> 95 <?php endforeach; ?> 96 <?php endif; ?> 97 </select> 98 <p class="description"><?php esc_html_e( 'Select the default author for new posts.', 'default-post-author' ); ?></p> 99 </td> 100 </tr> 101 </table> 102 103 <?php // Nonce and action for saving settings. 104 wp_nonce_field( 'dpap_save_settings_action', 'dpap_save_settings_nonce' ); ?> 105 <input type="hidden" name="action" value="dpap_save_settings"> 106 <?php submit_button( __( 'Save Changes', 'default-post-author' ), 'primary', 'submit' ); ?> 107 </form> 108 109 <hr /> 110 111 <h2><?php esc_html_e( 'Update Existing Posts Authors', 'default-post-author' ); ?></h2> 112 <p><?php esc_html_e( "Click the button below to change all existing posts' authors to the selected default author. This operation uses batch updates to avoid timeouts and will respect WordPress hooks for each post update.", 'default-post-author' ); ?></p> 113 114 <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"> 115 <?php wp_nonce_field( 'dpap_update_old_posts_action', 'dpap_update_old_posts_nonce' ); ?> 116 <input type="hidden" name="action" value="dpap_update_old_posts"> 117 <input type="hidden" name="default_post_author" value="<?php echo esc_attr( $current_value ); ?>"> 118 <?php submit_button( __( 'Update All Existing Posts to Default Author', 'default-post-author' ), 'secondary', 'dpap_update_old_authors' ); ?> 119 </form> 120 </div> 121 <?php 122 } 123 124 /** 125 * Handle save settings via admin-post action. 126 */ 127 function dpap_handle_save_settings() { 128 if ( ! current_user_can( 'manage_options' ) ) { 129 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'default-post-author' ) ); 130 } 131 132 $nonce = isset( $_POST['dpap_save_settings_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['dpap_save_settings_nonce'] ) ) : ''; 133 134 if ( ! wp_verify_nonce( $nonce, 'dpap_save_settings_action' ) ) { 135 wp_die( esc_html__( 'Security check failed.', 'default-post-author' ) ); 136 } 137 138 if ( isset( $_POST['default_post_author'] ) ) { 139 $new_author = absint( wp_unslash( $_POST['default_post_author'] ) ); 140 update_option( DPAP_OPTION_NAME, $new_author ); 141 } 142 143 wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'options-general.php?page=default-post-author' ) ); 144 exit; 145 } 146 add_action( 'admin_post_dpap_save_settings', 'dpap_handle_save_settings' ); 147 148 /** 149 * Handle update of existing posts to the selected default author. 150 * Processes posts in batches to avoid memory/timeouts and uses wp_update_post so hooks run. 151 */ 152 function dpap_handle_update_old_posts() { 153 if ( ! current_user_can( 'manage_options' ) ) { 154 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'default-post-author' ) ); 155 } 156 157 $nonce = isset( $_POST['dpap_update_old_posts_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['dpap_update_old_posts_nonce'] ) ) : ''; 158 159 if ( ! wp_verify_nonce( $nonce, 'dpap_update_old_posts_action' ) ) { 160 wp_die( esc_html__( 'Security check failed.', 'default-post-author' ) ); 161 } 162 163 $default_author_id = get_option( DPAP_OPTION_NAME, 1 ); 164 165 if ( isset( $_POST['default_post_author'] ) ) { 166 $default_author_id = absint( wp_unslash( $_POST['default_post_author'] ) ); 167 update_option( DPAP_OPTION_NAME, $default_author_id ); 168 } 169 170 $user = get_userdata( $default_author_id ); 171 if ( ! $user || ! array_intersect( array( 'author', 'editor', 'administrator' ), $user->roles ) ) { 172 wp_die( esc_html__( 'Selected default author is invalid.', 'default-post-author' ) ); 173 } 174 175 // Batch process posts to avoid timeout/memory issues. 176 $args = array( 177 'post_type' => 'post', 178 'post_status' => 'any', 179 'posts_per_page' => 100, 180 'fields' => 'ids', 181 'orderby' => 'ID', 182 'order' => 'ASC', 183 'paged' => 1, 184 ); 185 186 $total_updated = 0; 187 188 while ( true ) { 189 $query = new WP_Query( $args ); 190 if ( ! $query->have_posts() ) { 191 break; 192 } 193 194 foreach ( $query->posts as $post_id ) { 195 // Skip auto-drafts. 196 $post_status = get_post_status( $post_id ); 197 if ( 'auto-draft' === $post_status ) { 198 continue; 199 } 200 201 // Only update if different. 202 $current_author = (int) get_post_field( 'post_author', $post_id ); 203 if ( $current_author === $default_author_id ) { 204 continue; 205 } 206 207 // Use wp_update_post so hooks & cache invalidation run as expected. 208 $updated_post_id = wp_update_post( array( 209 'ID' => $post_id, 210 'post_author' => $default_author_id, 211 ), true ); 212 213 if ( is_wp_error( $updated_post_id ) ) { 214 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 215 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 216 error_log( sprintf( 'dpap: failed to update post %d: %s', $post_id, $updated_post_id->get_error_message() ) ); 217 } 218 continue; 219 } 220 221 $total_updated++; 222 } 223 224 // Move to next page. 225 $args['paged']++; 226 227 // Avoid infinite loops - break if no more found. 228 if ( 0 === count( $query->posts ) ) { 229 break; 230 } 231 232 // Clean up. 233 wp_reset_postdata(); 234 } 235 236 /* translators: %d: number of posts updated */ 237 $message = sprintf( esc_html( _n( '%d post author updated.', '%d post authors updated.', $total_updated, 'default-post-author' ) ), $total_updated ); 238 239 // Store message as transient to display after redirect. 240 set_transient( 'dpap_update_result', $message, 30 ); 241 242 wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'options-general.php?page=default-post-author' ) ); 243 exit; 244 } 245 add_action( 'admin_post_dpap_update_old_posts', 'dpap_handle_update_old_posts' ); 246 247 /** 248 * Show admin notices for the batch update result (transient-based). 249 */ 250 function dpap_admin_notices() { 251 if ( ! current_user_can( 'manage_options' ) ) { 252 return; 253 } 254 255 $message = get_transient( 'dpap_update_result' ); 256 if ( $message ) { 257 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $message ) . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 258 delete_transient( 'dpap_update_result' ); 259 } 260 } 261 add_action( 'admin_notices', 'dpap_admin_notices' ); 262 263 /** 264 * Set default author for new posts during creation only. 265 * Uses wp_insert_post_data filter. 266 * 267 * @param array $data Array of slashed post data. 268 * @param array $postarr Original post data. 269 * @return array Modified post data. 270 */ 72 271 function dpap_force_post_author( $data, $postarr ) { 73 // Retrieve the default author ID from WordPress options, default to 1 if not set 74 $default_author_id = get_option('default_post_author', 1); 75 76 // Set the author for new posts 77 if (empty($postarr['ID'])) { 272 $default_author_id = (int) get_option( DPAP_OPTION_NAME, 1 ); 273 274 if ( empty( $postarr['ID'] ) ) { 78 275 $data['post_author'] = $default_author_id; 79 276 } 277 80 278 return $data; 81 279 } 82 280 add_filter( 'wp_insert_post_data', 'dpap_force_post_author', 10, 2 ); 83 281 84 // Set the revision author to the same author as the post 85 function dpap_set_revision_author($post_has_changed, $last_revision, $post) { 86 global $wpdb; 87 88 // Update the post_author of the revision to match the original post 89 $result = $wpdb->update( 90 $wpdb->posts, 91 array('post_author' => $post->post_author), 92 array('ID' => $last_revision->ID), 93 array('%d'), 94 array('%d') 95 ); 96 97 // Basic error handling 98 if (false === $result) { 99 error_log('Failed to update revision author for post ID ' . $post->ID); 100 } 101 102 return $post_has_changed; 103 } 104 add_filter('wp_save_post_revision_check_for_changes', 'dpap_set_revision_author', 10, 3); 282 /** 283 * Ensure revision author matches original post author. 284 * Hook into wp_save_post_revision which provides revision ID and original post. 285 * Use wp_update_post to avoid direct DB queries. 286 * 287 * @param int $revision_id Revision post ID. 288 * @param WP_Post $post The original post object. 289 */ 290 function dpap_set_revision_author( $revision_id, $post ) { 291 $revision_id = (int) $revision_id; 292 $post_author = (int) $post->post_author; 293 294 $result = wp_update_post( array( 295 'ID' => $revision_id, 296 'post_author' => $post_author, 297 ), true ); 298 299 if ( is_wp_error( $result ) ) { 300 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 301 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 302 error_log( 'dpap: Failed to update revision author for post ID ' . $post->ID . ': ' . $result->get_error_message() ); 303 } 304 } 305 } 306 add_action( 'wp_save_post_revision', 'dpap_set_revision_author', 10, 2 ); 307 308 /** 309 * Uninstall cleanup: remove option when plugin is uninstalled. 310 */ 311 function dpap_uninstall() { 312 delete_option( DPAP_OPTION_NAME ); 313 } 314 register_uninstall_hook( __FILE__, 'dpap_uninstall' ); 315 316 /* End of file */ 317 -
default-post-author/tags/2.0/readme.txt
r3230273 r3343286 3 3 Tags: post author, default post author, wp post, posts 4 4 Requires at least: 6.1 5 Tested up to: 6. 76 Requires PHP: 7.47 Stable tag: 1.1.55 Tested up to: 6.8 6 Requires PHP: 8.0 7 Stable tag: 2.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 73 73 == Upgrade Notice == 74 74 75 = 2.0 - (August 12, 2025) = 76 - Security Update 77 - Performance Update 78 - Ability to Update All Existing Posts to Default Author 79 75 80 = 1.1.5 - (January 28, 2025) = 76 81 - Security Update … … 110 115 == Changelog == 111 116 117 = 2.0 - (August 28, 2025) = 118 - Security Update 119 - Performance Update 120 - Ability to Update All Existing Posts to Default Author 121 112 122 = 1.1.5 - (January 28, 2025) = 113 123 - Security Update -
default-post-author/trunk/default-post-author.php
r3230262 r3343286 1 1 <?php 2 3 2 /** 4 3 * Plugin Name: Default Post Author 5 * Plugin URI: https://wordpress.org/plugins/default-post-author/4 * Plugin URI: https://wordpress.org/plugins/default-post-author/ 6 5 * Description: The easiest way to set default post author in your WordPress Site. 7 * Version: 1.1.56 * Version: 2.0 8 7 * Requires at least: 6.1 9 * Requires PHP: 7.410 * Author: MonarchWP11 * Author URI: https://www.monarchwp.com12 * License: GPL v2 or later8 * Requires PHP: 8.0 9 * Author: MonarchWP 10 * Author URI: https://www.monarchwp.com 11 * License: GPL v2 or later 13 12 * License URI: https://www.gnu.org/licenses/gpl-2.0.html 14 13 * Text Domain: default-post-author 15 * Domain Path: /languages 16 */ 17 18 if (!defined('ABSPATH')) { 19 die; // Exit if accessed directly 20 } 21 22 /** 23 * Load plugin textdomain. 24 */ 25 function dpap_load_textdomain() { 26 load_plugin_textdomain('default-post-author', false, dirname(plugin_basename(__FILE__)) . '/languages'); 27 } 28 add_action('plugins_loaded', 'dpap_load_textdomain'); 29 30 31 // Add the field to the general settings page 32 function dpap_add_author_setting_field() { 33 add_settings_field( 34 'default_post_author', // ID of the settings field 35 __('Default Post Author', 'default-post-author'), // Title of the field 36 'dpap_default_post_author_field_html', // Function to display the field 37 'general' // Page to add the field to (General Settings page) 14 */ 15 16 if ( ! defined( 'ABSPATH' ) ) { 17 exit; // Exit if accessed directly. 18 } 19 20 /** 21 * Option name constant. 22 */ 23 if ( ! defined( 'DPAP_OPTION_NAME' ) ) { 24 define( 'DPAP_OPTION_NAME', 'default_post_author' ); 25 } 26 27 /** 28 * Register setting for storing default author ID. 29 */ 30 function dpap_register_setting() { 31 register_setting( 32 'dpap_options_group', 33 DPAP_OPTION_NAME, 34 array( 35 'type' => 'integer', 36 'sanitize_callback' => 'absint', 37 'default' => 1, 38 ) 38 39 ); 39 40 // Register the setting 41 register_setting('general', 'default_post_author', array( 42 'type' => 'integer', 43 'description' => 'Default author ID for new posts', 44 'sanitize_callback' => 'absint', // Ensure the value is an absolute integer 45 'default' => 1 // Default value if not set 46 )); 47 } 48 add_action('admin_init', 'dpap_add_author_setting_field'); 49 50 // HTML for the settings field 51 function dpap_default_post_author_field_html() { 52 $value = get_option('default_post_author', 1); // Get the current value, default to 1 53 54 // Fetch users with 'Author', 'Editor', or 'Administrator' roles 55 $user_query = new WP_User_Query(array( 56 'role__in' => array('Author', 'Editor', 'Administrator'), // Array of roles 57 'orderby' => 'display_name', 58 'order' => 'ASC' 59 )); 40 } 41 add_action( 'admin_init', 'dpap_register_setting' ); 42 43 /** 44 * Add settings page under Settings menu. 45 */ 46 function dpap_add_admin_menu() { 47 add_options_page( 48 __( 'Default Post Author', 'default-post-author' ), 49 __( 'Default Post Author', 'default-post-author' ), 50 'manage_options', 51 'default-post-author', 52 'dpap_render_options_page' 53 ); 54 } 55 add_action( 'admin_menu', 'dpap_add_admin_menu' ); 56 57 /** 58 * Render the options page HTML. The form posts to admin-post.php handlers. 59 */ 60 function dpap_render_options_page() { 61 if ( ! current_user_can( 'manage_options' ) ) { 62 return; 63 } 64 65 $current_value = get_option( DPAP_OPTION_NAME, 1 ); 66 67 // Fetch users with roles author, editor, administrator. 68 $user_query = new WP_User_Query( array( 69 'role__in' => array( 'author', 'editor', 'administrator' ), 70 'orderby' => 'display_name', 71 'order' => 'ASC', 72 ) ); 60 73 61 74 $users = $user_query->get_results(); 62 63 // Create a dropdown list of users 64 echo '<select id="default_post_author" name="default_post_author">'; 65 foreach ($users as $user) { 66 echo '<option value="' . esc_attr($user->ID) . '"' . selected($user->ID, $value, false) . '>' . esc_html($user->display_name) . '</option>'; 67 } 68 echo '</select>'; 69 } 70 71 // Set the default author for new posts 75 ?> 76 <div class="wrap"> 77 <h1><?php esc_html_e( 'Default Post Author Settings', 'default-post-author' ); ?></h1> 78 79 <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"> 80 <?php // Settings fields for WP Settings API (keeps option group consistent). 81 settings_fields( 'dpap_options_group' ); ?> 82 83 <table class="form-table" role="presentation"> 84 <tr> 85 <th scope="row"><label for="default_post_author"><?php esc_html_e( 'Default Post Author', 'default-post-author' ); ?></label></th> 86 <td> 87 <select id="default_post_author" name="default_post_author"> 88 <?php if ( empty( $users ) ) : ?> 89 <option value="0"><?php esc_html_e( 'No eligible users found', 'default-post-author' ); ?></option> 90 <?php else : ?> 91 <?php foreach ( $users as $user ) : ?> 92 <option value="<?php echo esc_attr( $user->ID ); ?>" <?php selected( $user->ID, $current_value ); ?>> 93 <?php echo esc_html( $user->display_name ); ?> 94 </option> 95 <?php endforeach; ?> 96 <?php endif; ?> 97 </select> 98 <p class="description"><?php esc_html_e( 'Select the default author for new posts.', 'default-post-author' ); ?></p> 99 </td> 100 </tr> 101 </table> 102 103 <?php // Nonce and action for saving settings. 104 wp_nonce_field( 'dpap_save_settings_action', 'dpap_save_settings_nonce' ); ?> 105 <input type="hidden" name="action" value="dpap_save_settings"> 106 <?php submit_button( __( 'Save Changes', 'default-post-author' ), 'primary', 'submit' ); ?> 107 </form> 108 109 <hr /> 110 111 <h2><?php esc_html_e( 'Update Existing Posts Authors', 'default-post-author' ); ?></h2> 112 <p><?php esc_html_e( "Click the button below to change all existing posts' authors to the selected default author. This operation uses batch updates to avoid timeouts and will respect WordPress hooks for each post update.", 'default-post-author' ); ?></p> 113 114 <form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>"> 115 <?php wp_nonce_field( 'dpap_update_old_posts_action', 'dpap_update_old_posts_nonce' ); ?> 116 <input type="hidden" name="action" value="dpap_update_old_posts"> 117 <input type="hidden" name="default_post_author" value="<?php echo esc_attr( $current_value ); ?>"> 118 <?php submit_button( __( 'Update All Existing Posts to Default Author', 'default-post-author' ), 'secondary', 'dpap_update_old_authors' ); ?> 119 </form> 120 </div> 121 <?php 122 } 123 124 /** 125 * Handle save settings via admin-post action. 126 */ 127 function dpap_handle_save_settings() { 128 if ( ! current_user_can( 'manage_options' ) ) { 129 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'default-post-author' ) ); 130 } 131 132 $nonce = isset( $_POST['dpap_save_settings_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['dpap_save_settings_nonce'] ) ) : ''; 133 134 if ( ! wp_verify_nonce( $nonce, 'dpap_save_settings_action' ) ) { 135 wp_die( esc_html__( 'Security check failed.', 'default-post-author' ) ); 136 } 137 138 if ( isset( $_POST['default_post_author'] ) ) { 139 $new_author = absint( wp_unslash( $_POST['default_post_author'] ) ); 140 update_option( DPAP_OPTION_NAME, $new_author ); 141 } 142 143 wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'options-general.php?page=default-post-author' ) ); 144 exit; 145 } 146 add_action( 'admin_post_dpap_save_settings', 'dpap_handle_save_settings' ); 147 148 /** 149 * Handle update of existing posts to the selected default author. 150 * Processes posts in batches to avoid memory/timeouts and uses wp_update_post so hooks run. 151 */ 152 function dpap_handle_update_old_posts() { 153 if ( ! current_user_can( 'manage_options' ) ) { 154 wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'default-post-author' ) ); 155 } 156 157 $nonce = isset( $_POST['dpap_update_old_posts_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['dpap_update_old_posts_nonce'] ) ) : ''; 158 159 if ( ! wp_verify_nonce( $nonce, 'dpap_update_old_posts_action' ) ) { 160 wp_die( esc_html__( 'Security check failed.', 'default-post-author' ) ); 161 } 162 163 $default_author_id = get_option( DPAP_OPTION_NAME, 1 ); 164 165 if ( isset( $_POST['default_post_author'] ) ) { 166 $default_author_id = absint( wp_unslash( $_POST['default_post_author'] ) ); 167 update_option( DPAP_OPTION_NAME, $default_author_id ); 168 } 169 170 $user = get_userdata( $default_author_id ); 171 if ( ! $user || ! array_intersect( array( 'author', 'editor', 'administrator' ), $user->roles ) ) { 172 wp_die( esc_html__( 'Selected default author is invalid.', 'default-post-author' ) ); 173 } 174 175 // Batch process posts to avoid timeout/memory issues. 176 $args = array( 177 'post_type' => 'post', 178 'post_status' => 'any', 179 'posts_per_page' => 100, 180 'fields' => 'ids', 181 'orderby' => 'ID', 182 'order' => 'ASC', 183 'paged' => 1, 184 ); 185 186 $total_updated = 0; 187 188 while ( true ) { 189 $query = new WP_Query( $args ); 190 if ( ! $query->have_posts() ) { 191 break; 192 } 193 194 foreach ( $query->posts as $post_id ) { 195 // Skip auto-drafts. 196 $post_status = get_post_status( $post_id ); 197 if ( 'auto-draft' === $post_status ) { 198 continue; 199 } 200 201 // Only update if different. 202 $current_author = (int) get_post_field( 'post_author', $post_id ); 203 if ( $current_author === $default_author_id ) { 204 continue; 205 } 206 207 // Use wp_update_post so hooks & cache invalidation run as expected. 208 $updated_post_id = wp_update_post( array( 209 'ID' => $post_id, 210 'post_author' => $default_author_id, 211 ), true ); 212 213 if ( is_wp_error( $updated_post_id ) ) { 214 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 215 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 216 error_log( sprintf( 'dpap: failed to update post %d: %s', $post_id, $updated_post_id->get_error_message() ) ); 217 } 218 continue; 219 } 220 221 $total_updated++; 222 } 223 224 // Move to next page. 225 $args['paged']++; 226 227 // Avoid infinite loops - break if no more found. 228 if ( 0 === count( $query->posts ) ) { 229 break; 230 } 231 232 // Clean up. 233 wp_reset_postdata(); 234 } 235 236 /* translators: %d: number of posts updated */ 237 $message = sprintf( esc_html( _n( '%d post author updated.', '%d post authors updated.', $total_updated, 'default-post-author' ) ), $total_updated ); 238 239 // Store message as transient to display after redirect. 240 set_transient( 'dpap_update_result', $message, 30 ); 241 242 wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'options-general.php?page=default-post-author' ) ); 243 exit; 244 } 245 add_action( 'admin_post_dpap_update_old_posts', 'dpap_handle_update_old_posts' ); 246 247 /** 248 * Show admin notices for the batch update result (transient-based). 249 */ 250 function dpap_admin_notices() { 251 if ( ! current_user_can( 'manage_options' ) ) { 252 return; 253 } 254 255 $message = get_transient( 'dpap_update_result' ); 256 if ( $message ) { 257 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $message ) . '</p></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 258 delete_transient( 'dpap_update_result' ); 259 } 260 } 261 add_action( 'admin_notices', 'dpap_admin_notices' ); 262 263 /** 264 * Set default author for new posts during creation only. 265 * Uses wp_insert_post_data filter. 266 * 267 * @param array $data Array of slashed post data. 268 * @param array $postarr Original post data. 269 * @return array Modified post data. 270 */ 72 271 function dpap_force_post_author( $data, $postarr ) { 73 // Retrieve the default author ID from WordPress options, default to 1 if not set 74 $default_author_id = get_option('default_post_author', 1); 75 76 // Set the author for new posts 77 if (empty($postarr['ID'])) { 272 $default_author_id = (int) get_option( DPAP_OPTION_NAME, 1 ); 273 274 if ( empty( $postarr['ID'] ) ) { 78 275 $data['post_author'] = $default_author_id; 79 276 } 277 80 278 return $data; 81 279 } 82 280 add_filter( 'wp_insert_post_data', 'dpap_force_post_author', 10, 2 ); 83 281 84 // Set the revision author to the same author as the post 85 function dpap_set_revision_author($post_has_changed, $last_revision, $post) { 86 global $wpdb; 87 88 // Update the post_author of the revision to match the original post 89 $result = $wpdb->update( 90 $wpdb->posts, 91 array('post_author' => $post->post_author), 92 array('ID' => $last_revision->ID), 93 array('%d'), 94 array('%d') 95 ); 96 97 // Basic error handling 98 if (false === $result) { 99 error_log('Failed to update revision author for post ID ' . $post->ID); 100 } 101 102 return $post_has_changed; 103 } 104 add_filter('wp_save_post_revision_check_for_changes', 'dpap_set_revision_author', 10, 3); 282 /** 283 * Ensure revision author matches original post author. 284 * Hook into wp_save_post_revision which provides revision ID and original post. 285 * Use wp_update_post to avoid direct DB queries. 286 * 287 * @param int $revision_id Revision post ID. 288 * @param WP_Post $post The original post object. 289 */ 290 function dpap_set_revision_author( $revision_id, $post ) { 291 $revision_id = (int) $revision_id; 292 $post_author = (int) $post->post_author; 293 294 $result = wp_update_post( array( 295 'ID' => $revision_id, 296 'post_author' => $post_author, 297 ), true ); 298 299 if ( is_wp_error( $result ) ) { 300 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { 301 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log 302 error_log( 'dpap: Failed to update revision author for post ID ' . $post->ID . ': ' . $result->get_error_message() ); 303 } 304 } 305 } 306 add_action( 'wp_save_post_revision', 'dpap_set_revision_author', 10, 2 ); 307 308 /** 309 * Uninstall cleanup: remove option when plugin is uninstalled. 310 */ 311 function dpap_uninstall() { 312 delete_option( DPAP_OPTION_NAME ); 313 } 314 register_uninstall_hook( __FILE__, 'dpap_uninstall' ); 315 316 /* End of file */ 317 -
default-post-author/trunk/readme.txt
r3230273 r3343286 3 3 Tags: post author, default post author, wp post, posts 4 4 Requires at least: 6.1 5 Tested up to: 6. 76 Requires PHP: 7.47 Stable tag: 1.1.55 Tested up to: 6.8 6 Requires PHP: 8.0 7 Stable tag: 2.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 73 73 == Upgrade Notice == 74 74 75 = 2.0 - (August 12, 2025) = 76 - Security Update 77 - Performance Update 78 - Ability to Update All Existing Posts to Default Author 79 75 80 = 1.1.5 - (January 28, 2025) = 76 81 - Security Update … … 110 115 == Changelog == 111 116 117 = 2.0 - (August 28, 2025) = 118 - Security Update 119 - Performance Update 120 - Ability to Update All Existing Posts to Default Author 121 112 122 = 1.1.5 - (January 28, 2025) = 113 123 - Security Update
Note: See TracChangeset
for help on using the changeset viewer.