Edit Author Slug - Version 1.3.0

Version Description

  • Fix a potential bug where a sanitized author base could end up with double forward slashes.
  • Introduce the %ba_eas_author_role% permalink structure tag. This can be used to customize role-based author bases.
  • Bonus: All alternative facts are now free!
Download this release

Release Info

Developer thebrandonallen
Plugin Icon 128x128 Edit Author Slug
Version 1.3.0
Comparing to
See all releases

Version 1.3.0

edit-author-slug.php ADDED
@@ -0,0 +1,527 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Plugin Name: Edit Author Slug
4
+ * Plugin URI: https://github.com/thebrandonallen/edit-author-slug/
5
+ * Description: Allows an Admin (or capable user) to edit the author slug of a user, and change the Author Base. <em>i.e. - (WordPress default structure) http://example.com/author/username/ (Plugin allows) http://example.com/ninja/master-ninja/</em>
6
+ * Version: 1.3.0
7
+ * Tested With: 4.3.7, 4.4.6, 4.5.5, 4.6.2, 4.7.1
8
+ * Author: Brandon Allen
9
+ * Author URI: https://github.com/thebrandonallen/
10
+ * License: GPLv2 or later
11
+ * Text Domain: edit-author-slug
12
+ * Domain Path: /languages
13
+ *
14
+ * @package Edit_Author_Slug
15
+ * @subpackage Main
16
+ * @author Brandon Allen
17
+ * @version 1.3.0
18
+ */
19
+
20
+ /*
21
+ Copyright 2009-2016 Brandon Allen (email : plugins ([at]) brandonallen ([dot]) me)
22
+
23
+ This program is free software; you can redistribute it and/or modify
24
+ it under the terms of the GNU General Public License as published by
25
+ the Free Software Foundation; either version 2 of the License, or
26
+ (at your option) any later version.
27
+
28
+ This program is distributed in the hope that it will be useful,
29
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
30
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31
+ GNU General Public License for more details.
32
+
33
+ You should have received a copy of the GNU General Public License
34
+ along with this program; if not, write to the Free Software
35
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
36
+
37
+ http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt
38
+ */
39
+
40
+ // Exit if accessed directly.
41
+ defined( 'ABSPATH' ) || exit;
42
+
43
+ /**
44
+ * Main Edit Author Slug class.
45
+ */
46
+ if ( ! class_exists( 'BA_Edit_Author_Slug' ) ) :
47
+
48
+ /**
49
+ * Final BA_Edit_Author_Slug class.
50
+ *
51
+ * @since 0.1.0
52
+ *
53
+ * @final
54
+ */
55
+ final class BA_Edit_Author_Slug {
56
+
57
+ /**
58
+ * The plugin version.
59
+ *
60
+ * @since 0.8.0
61
+ * @access public
62
+ * @var string
63
+ */
64
+ public $version = '1.3.0';
65
+
66
+ /**
67
+ * The database version.
68
+ *
69
+ * @since 0.8.0
70
+ * @access public
71
+ * @var int
72
+ */
73
+ public $db_version = 411;
74
+
75
+ /**
76
+ * The current installed database version.
77
+ *
78
+ * @since 0.8.0
79
+ * @access public
80
+ * @var int
81
+ */
82
+ public $current_db_version = 0;
83
+
84
+ /**
85
+ * The path to this file.
86
+ *
87
+ * @since 0.7.0
88
+ * @access public
89
+ * @var string
90
+ */
91
+ public $file = __FILE__;
92
+
93
+ /**
94
+ * The path to the Edit AUthor Slug directory.
95
+ *
96
+ * @since 0.7.0
97
+ * @access public
98
+ * @var string
99
+ */
100
+ public $plugin_dir = '';
101
+
102
+ /**
103
+ * The URL for the Edit Author Slug directory.
104
+ *
105
+ * @since 0.7.0
106
+ * @access public
107
+ * @var string
108
+ */
109
+ public $plugin_url = '';
110
+
111
+ /**
112
+ * The basename for the Edit Author Slug directory.
113
+ *
114
+ * @since 0.8.0
115
+ * @access public
116
+ * @var string
117
+ */
118
+ public $plugin_basename = '';
119
+
120
+ /**
121
+ * The text domain for Edit Author Slug.
122
+ *
123
+ * @since 0.9.6
124
+ * @access public
125
+ * @var string
126
+ */
127
+ public $domain = 'edit-author-slug';
128
+
129
+ /**
130
+ * The author base.
131
+ *
132
+ * @since 0.7.0
133
+ * @access public
134
+ * @var string
135
+ */
136
+ public $author_base = 'author';
137
+
138
+ /**
139
+ * The remove front option.
140
+ *
141
+ * @since 1.2.0
142
+ * @access public
143
+ * @var bool
144
+ */
145
+ public $remove_front = false;
146
+
147
+ /**
148
+ * The auto update option.
149
+ *
150
+ * @since 1.0.0
151
+ * @access public
152
+ * @var bool
153
+ */
154
+ public $do_auto_update = false;
155
+
156
+ /**
157
+ * The default user nicename option.
158
+ *
159
+ * @since 1.0.0
160
+ * @access public
161
+ * @var string
162
+ */
163
+ public $default_user_nicename = 'username';
164
+
165
+ /**
166
+ * The role-based option.
167
+ *
168
+ * @since 1.0.0
169
+ * @access public
170
+ * @var bool
171
+ */
172
+ public $do_role_based = false;
173
+
174
+ /**
175
+ * The role slugs array.
176
+ *
177
+ * @since 1.0.0
178
+ * @access public
179
+ * @var array
180
+ */
181
+ public $role_slugs = array();
182
+
183
+ /** Singleton *********************************************************/
184
+
185
+ /**
186
+ * Main BA_Edit_Author_Slug Instance
187
+ *
188
+ * Insures that only one instance of BA_Edit_Author_Slug exists in memory
189
+ * at any one time. Also prevents needing to define globals all over the
190
+ * place.
191
+ *
192
+ * @since 1.0.0
193
+ *
194
+ * @staticvar object $instance
195
+ *
196
+ * @see ba_eas()
197
+ *
198
+ * @return BA_Edit_Author_Slug|null The one true BA_Edit_Author_Slug.
199
+ */
200
+ public static function instance() {
201
+
202
+ // Store the instance locally to avoid private static replication.
203
+ static $instance = null;
204
+
205
+ // Only run these methods if they haven't been ran previously.
206
+ if ( null === $instance ) {
207
+ $instance = new BA_Edit_Author_Slug;
208
+ $instance->setup_globals();
209
+ $instance->includes();
210
+ $instance->options_back_compat();
211
+ $instance->setup_actions();
212
+ }
213
+
214
+ // Always return the instance.
215
+ return $instance;
216
+ }
217
+
218
+ /**
219
+ * Magic method to prevent notices and errors from invalid method calls.
220
+ *
221
+ * @since 1.0.0
222
+ *
223
+ * @param string $name The method name being called.
224
+ * @param array $args The method arguments.
225
+ *
226
+ * @return null
227
+ */
228
+ public function __call( $name = '', $args = array() ) {
229
+
230
+ if ( 'author_base_rewrite' === $name ) {
231
+ _deprecated_function( 'BA_Edit_Author_Slug::author_base_rewrite', '1.2.0', 'ba_eas_wp_rewrite_overrides' );
232
+ ba_eas_wp_rewrite_overrides();
233
+ } else {
234
+ _doing_it_wrong( "BA_Edit_Author_Slug::{$name}", esc_html__( 'Method does not exist.', 'edit-author-slug' ), '1.0.0' );
235
+ }
236
+
237
+ unset( $name, $args );
238
+ return null;
239
+ }
240
+
241
+ /** Magic Methods *****************************************************/
242
+
243
+ /**
244
+ * A dummy magic method to prevent BA_Edit_Author_Slug from being cloned.
245
+ *
246
+ * @since 1.0.0
247
+ *
248
+ * @codeCoverageIgnore
249
+ *
250
+ * @return void
251
+ */
252
+ private function __clone() {
253
+ _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'edit-author-slug' ), '1.0' );
254
+ }
255
+
256
+ /**
257
+ * A dummy magic method to prevent BA_Edit_Author_Slug from being unserialized.
258
+ *
259
+ * @since 1.0.0
260
+ *
261
+ * @codeCoverageIgnore
262
+ *
263
+ * @return void
264
+ */
265
+ private function __wakeup() {
266
+ _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'edit-author-slug' ), '1.0' );
267
+ }
268
+
269
+ /* Private Methods ****************************************************/
270
+
271
+ /**
272
+ * Edit Author Slug global variables.
273
+ *
274
+ * @since 0.7.0
275
+ *
276
+ * @return void
277
+ */
278
+ private function setup_globals() {
279
+
280
+ /* Paths **********************************************************/
281
+
282
+ $this->plugin_dir = plugin_dir_path( $this->file );
283
+ $this->plugin_url = plugin_dir_url( $this->file );
284
+ $this->plugin_basename = plugin_basename( $this->file );
285
+
286
+ /* Options ********************************************************/
287
+
288
+ // Load the remove front option.
289
+ $this->remove_front = (bool) absint( get_option( '_ba_eas_remove_front', 0 ) );
290
+
291
+ // Load auto-update option.
292
+ $this->do_auto_update = (bool) absint( get_option( '_ba_eas_do_auto_update', 0 ) );
293
+
294
+ // Load the default nicename structure for auto-update.
295
+ $default_user_nicename = get_option( '_ba_eas_default_user_nicename' );
296
+ $default_user_nicename = sanitize_key( $default_user_nicename );
297
+ if ( ! empty( $default_user_nicename ) ) {
298
+ $this->default_user_nicename = $default_user_nicename;
299
+ }
300
+
301
+ // Load role-based author slug option.
302
+ $this->do_role_based = (bool) absint( get_option( '_ba_eas_do_role_based', 0 ) );
303
+ }
304
+
305
+ /**
306
+ * Include necessary files.
307
+ *
308
+ * @since 0.7.0
309
+ *
310
+ * @return void
311
+ */
312
+ private function includes() {
313
+
314
+ // Load the core functions.
315
+ require_once( $this->plugin_dir . 'includes/functions.php' );
316
+ require_once( $this->plugin_dir . 'includes/hooks.php' );
317
+
318
+ // Maybe load the admin functions.
319
+ if ( is_admin() ) {
320
+ require_once( $this->plugin_dir . 'includes/admin.php' );
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Display Author slug edit field on User/Profile edit page.
326
+ *
327
+ * @since 0.7.0
328
+ *
329
+ * @return void
330
+ */
331
+ private function setup_actions() {
332
+ // Register Edit Author Slug activation/deactivation sequences.
333
+ register_activation_hook( $this->file, 'ba_eas_activation' );
334
+ register_deactivation_hook( $this->file, 'ba_eas_deactivation' );
335
+
336
+ // Author Base Actions.
337
+ add_action( 'after_setup_theme', array( $this, 'set_role_slugs' ) );
338
+ add_action( 'init', 'ba_eas_wp_rewrite_overrides', 4 );
339
+ add_action( 'init', array( $this, 'add_rewrite_tags' ), 20 );
340
+
341
+ // Localize.
342
+ add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
343
+ }
344
+
345
+ /**
346
+ * Sets the author base and db version with support for previous
347
+ * versions of the plugin.
348
+ *
349
+ * @since 1.2.0
350
+ *
351
+ * @return void
352
+ */
353
+ private function options_back_compat() {
354
+
355
+ // Options.
356
+ if ( $base = get_option( '_ba_eas_author_base' ) ) {
357
+
358
+ // Sanitize the db value.
359
+ $base = ba_eas_sanitize_author_base( $base );
360
+
361
+ // Author base.
362
+ if ( ! empty( $base ) ) {
363
+ $this->author_base = $base;
364
+ }
365
+
366
+ // Current DB version.
367
+ $this->current_db_version = absint( get_option( '_ba_eas_db_version' ) );
368
+
369
+ // Pre-0.9 Back compat.
370
+ } elseif ( $options = get_option( 'ba_edit_author_slug' ) ) {
371
+
372
+ // Sanitize the db value.
373
+ if ( ! empty( $options['author_base'] ) ) {
374
+ $base = ba_eas_sanitize_author_base( $options['author_base'] );
375
+ }
376
+
377
+ // Author base.
378
+ if ( ! empty( $base ) ) {
379
+ $this->author_base = $base;
380
+ }
381
+
382
+ // Current DB version.
383
+ if ( ! empty( $options['db_version'] ) ) {
384
+ $this->current_db_version = absint( $options['db_version'] );
385
+ }
386
+ }
387
+ }
388
+
389
+ /** Public Methods ****************************************************/
390
+
391
+ /**
392
+ * Load the translation file for current language. Checks the Edit Author
393
+ * Slug languages folder first, then inside the default WP language
394
+ * plugins folder.
395
+ *
396
+ * Note that custom translation files inside the Edit Author Slug plugin
397
+ * folder will be removed on edit-author-slug updates. If you're creating
398
+ * custom translation files, please use the global language folder
399
+ * (ie - wp-content/languages/plugins).
400
+ *
401
+ * @since 0.9.6
402
+ *
403
+ * @return void
404
+ */
405
+ public function load_textdomain() {
406
+
407
+ // Look in wp-content/plugins/edit-author-slug/languages first.
408
+ // Fallback to wp-content/languages/plugins.
409
+ load_plugin_textdomain( $this->domain, false, dirname( $this->plugin_basename ) . '/languages/' );
410
+ }
411
+
412
+ /**
413
+ * Set the role_slugs global
414
+ *
415
+ * @since 1.0.0
416
+ *
417
+ * @return void
418
+ */
419
+ public function set_role_slugs() {
420
+
421
+ // Get the default role slugs.
422
+ $defaults = ba_eas_get_default_role_slugs();
423
+
424
+ // Merge system roles with any customizations we may have.
425
+ $role_slugs = array_replace_recursive(
426
+ $defaults,
427
+ get_option( '_ba_eas_role_slugs', array() )
428
+ );
429
+
430
+ foreach ( $role_slugs as $role => $details ) {
431
+
432
+ if ( empty( $defaults[ $role ] ) ) {
433
+ unset( $role_slugs[ $role ] );
434
+ }
435
+ }
436
+
437
+ $this->role_slugs = $role_slugs;
438
+ }
439
+
440
+ /** Custom Rewrite Rules **********************************************/
441
+
442
+ /**
443
+ * Add the Edit Author Slug rewrite tags
444
+ *
445
+ * @since 1.0.0
446
+ *
447
+ * @return void
448
+ */
449
+ public function add_rewrite_tags() {
450
+
451
+ // Should we be here?
452
+ if ( ! ba_eas_do_role_based_author_base() ) {
453
+ return;
454
+ }
455
+
456
+ // Get the role slugs to add the rewrite tag.
457
+ $role_slugs = wp_list_pluck( $this->role_slugs, 'slug' );
458
+ $role_slugs = array_filter( array_values( $role_slugs ) );
459
+
460
+ // Grab the author base.
461
+ $author_base = ba_eas()->author_base;
462
+
463
+ // Add a fallback.
464
+ if ( false === strpos( $author_base, '%ba_eas_author_role%' ) && false === strpos( $author_base, '/' ) ) {
465
+ $role_slugs[] = $author_base;
466
+ } else {
467
+ $role_slugs[] = 'author';
468
+ }
469
+
470
+ // Add the role-based rewrite tag, and the expected role slugs.
471
+ add_rewrite_tag( '%ba_eas_author_role%', '(' . implode( '|', array_unique( $role_slugs ) ) . ')' );
472
+ }
473
+ }
474
+
475
+ /**
476
+ * The main function responsible for returning the one true BA_Edit_Author_Slug
477
+ * Instance to functions everywhere.
478
+ *
479
+ * Use this function like you would a global variable, except without needing
480
+ * to declare the global.
481
+ *
482
+ * Example: <?php $ba_eas = ba_eas(); ?>
483
+ *
484
+ * @return BA_Edit_Author_Slug|null The one true BA_Edit_Author_Slug Instance.
485
+ */
486
+ function ba_eas() {
487
+ return BA_Edit_Author_Slug::instance();
488
+ }
489
+
490
+ // Places everyone! The show is starting!
491
+ ba_eas();
492
+
493
+ endif; // End class BA_Edit_Author_Slug.
494
+
495
+ /**
496
+ * Runs on Edit Author Slug activation.
497
+ *
498
+ * @since 0.7.0
499
+ *
500
+ * @return void
501
+ */
502
+ function ba_eas_activation() {
503
+
504
+ /**
505
+ * Fires on Edit Author Slug activation.
506
+ *
507
+ * @since 0.7.0
508
+ */
509
+ do_action( 'ba_eas_activation' );
510
+ }
511
+
512
+ /**
513
+ * Runs on Edit Author Slug deactivation.
514
+ *
515
+ * @since 0.7.0
516
+ *
517
+ * @return void
518
+ */
519
+ function ba_eas_deactivation() {
520
+
521
+ /**
522
+ * Fires on Edit Author Slug deactivation.
523
+ *
524
+ * @since 0.7.0
525
+ */
526
+ do_action( 'ba_eas_deactivation' );
527
+ }
includes/admin.php ADDED
@@ -0,0 +1,995 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Edit Author Slug Admin Functions.
4
+ *
5
+ * @package Edit_Author_Slug
6
+ * @subpackage Administration
7
+ *
8
+ * @author Brandon Allen
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ defined( 'ABSPATH' ) || exit;
13
+
14
+ /** Nicename ******************************************************************/
15
+
16
+ /**
17
+ * Display Author slug edit field on User/Profile edit page.
18
+ *
19
+ * Displays the Author slug edit field on User/Profile edit page.
20
+ * Runs with the 'show_user_profile' and 'edit_user_profile' actions.
21
+ *
22
+ * @since 0.1.0
23
+ *
24
+ * @param WP_User $user The WP_User object.
25
+ */
26
+ function ba_eas_show_user_nicename( $user ) {
27
+
28
+ // Return early if the user can't edit the author slug.
29
+ if ( ! ba_eas_can_edit_author_slug() ) {
30
+ return;
31
+ }
32
+
33
+ // Setup the nicename.
34
+ $nicename = '';
35
+ if ( ! empty( $user->user_nicename ) ) {
36
+ $nicename = $user->user_nicename;
37
+ }
38
+
39
+ // Setup options array.
40
+ $options = array();
41
+ $options['username'] = ba_eas_sanitize_nicename( $user->nickname );
42
+ $options['displayname'] = ba_eas_sanitize_nicename( $user->display_name );
43
+
44
+ // Setup the first name.
45
+ if ( ! empty( $user->first_name ) ) {
46
+ $options['firstname'] = ba_eas_sanitize_nicename( $user->first_name );
47
+ }
48
+
49
+ // Setup the last name.
50
+ if ( ! empty( $user->last_name ) ) {
51
+ $options['lastname'] = ba_eas_sanitize_nicename( $user->last_name );
52
+ }
53
+
54
+ // Setup the first/last name combos.
55
+ if ( ! empty( $options['firstname'] ) && ! empty( $options['lastname'] ) ) {
56
+ $options['firslast'] = $options['firstname'] . '-' . $options['lastname'];
57
+ $options['lastfirst'] = $options['lastname'] . '-' . $options['firstname'];
58
+ }
59
+
60
+ // Setup the user id.
61
+ $options['userid'] = (int) $user->ID;
62
+
63
+ /**
64
+ * Filters the array of user nicename options.
65
+ *
66
+ * @since 0.9.0
67
+ *
68
+ * @param array $options An array of of user nicename options.
69
+ * @param WP_User $user The WP_User object.
70
+ */
71
+ $options = apply_filters( 'ba_eas_show_user_nicename_options_list', $options, $user );
72
+
73
+ // Trim nicenames to 50 characters, and filter out any duplicates or empties.
74
+ $options = array_map( 'ba_eas_trim_nicename', (array) $options );
75
+ $options = array_unique( array_filter( $options ) );
76
+
77
+ // Set default for checked status.
78
+ $checked = true;
79
+ ?>
80
+
81
+ <h2><?php esc_html_e( 'Edit Author Slug', 'edit-author-slug' ); ?></h2>
82
+ <p><?php esc_html_e( 'Choose an Author Slug based on the above profile information, or create your own.', 'edit-author-slug' ); ?> <br /><span class="description"><?php esc_html_e( "ie. - 'user-name', 'firstname-lastname', or 'master-ninja'", 'edit-author-slug' ); ?></span></p>
83
+ <table class="form-table">
84
+ <tbody><tr>
85
+ <th scope="row"><?php esc_html_e( 'Author Slug', 'edit-author-slug' ); ?></th>
86
+ <td>
87
+ <fieldset><legend class="screen-reader-text"><span><?php esc_html_e( 'Author Slug', 'edit-author-slug' ); ?></span></legend>
88
+ <?php foreach ( (array) $options as $item ) {
89
+
90
+ // Checked?
91
+ $checked_text = checked( $item, $nicename, false );
92
+
93
+ // Flip the switch if we're checked to block custom from being checked.
94
+ if ( ! empty( $checked_text ) ) {
95
+ $checked = false;
96
+ }
97
+ ?>
98
+ <label title="<?php echo ba_eas_esc_nicename( $item ); ?>">
99
+ <input type="radio" id="ba_eas_author_slug" name="ba_eas_author_slug" value="<?php echo ba_eas_esc_nicename( $item ); ?>" autocapitalize="none" autocorrect="off" maxlength="50"<?php echo $checked_text; ?>>
100
+ <span><?php echo ba_eas_esc_nicename( $item ); ?></span>
101
+ </label><br />
102
+ <?php } ?>
103
+ <label for="ba_eas_author_slug_custom_radio">
104
+ <input type="radio" id="ba_eas_author_slug_custom_radio" name="ba_eas_author_slug" value="\c\u\s\t\o\m" autocapitalize="none" autocorrect="off" maxlength="50"<?php checked( $checked ); ?>>
105
+ <?php esc_html_e( 'Custom:', 'edit-author-slug' ); ?>
106
+ <span class="screen-reader-text"><?php esc_html_e( 'Enter a custom author slug in the following field', 'edit-author-slug' ); ?></span>
107
+ </label>
108
+ <label for="ba_eas_author_slug_custom" class="screen-reader-text"><?php esc_html_e( 'Custom author slug:', 'edit-author-slug' ); ?></label>
109
+ <input type="text" name="ba_eas_author_slug_custom" id="ba_eas_author_slug_custom" value="<?php echo ba_eas_esc_nicename( $nicename ); ?>" class="regular-text" />
110
+ </fieldset>
111
+ </td>
112
+ </tr></tbody>
113
+ </table>
114
+
115
+ <?php
116
+ }
117
+
118
+ /**
119
+ * Prepare the user nicename for updating if applicable.
120
+ *
121
+ * The actual updating is handled by WP as long as no errors are thrown by WP,
122
+ * some third party, or us.
123
+ *
124
+ * @since 0.1.0
125
+ *
126
+ * @param WP_Errors $errors The WP_Errors object.
127
+ * @param bool $update True if user is being updated.
128
+ * @param WP_User $user The WP_User object.
129
+ */
130
+ function ba_eas_update_user_nicename( $errors, $update, $user ) {
131
+
132
+ // Bail early if user can't edit the slug.
133
+ if ( ! ba_eas_can_edit_author_slug() ) {
134
+ return;
135
+ }
136
+
137
+ // Don't run the auto-update if the current user can update their own nicename.
138
+ remove_action( 'profile_update', 'ba_eas_auto_update_user_nicename' );
139
+
140
+ // We shouldn't be here if we're not updating.
141
+ if ( ! $update ) {
142
+ return;
143
+ }
144
+
145
+ // Validate the user_id.
146
+ if ( empty( $user->ID ) ) {
147
+ return;
148
+ }
149
+
150
+ // Check the nonce.
151
+ check_admin_referer( 'update-user_' . $user->ID );
152
+
153
+ // Stash the original user object.
154
+ $_user = get_userdata( $user->ID );
155
+
156
+ $user_nicename = $user_nicename_custom = '';
157
+
158
+ if ( isset( $_POST['ba_eas_author_slug'] ) ) {
159
+ $user_nicename = trim( wp_unslash( $_POST['ba_eas_author_slug'] ) );
160
+ }
161
+
162
+ if ( isset( $_POST['ba_eas_author_slug_custom'] ) ) {
163
+ $user_nicename_custom = trim( wp_unslash( $_POST['ba_eas_author_slug_custom'] ) );
164
+ }
165
+
166
+ // Check for a custom author slug.
167
+ if ( '\c\u\s\t\o\m' === $user_nicename ) {
168
+ $user_nicename = $user_nicename_custom;
169
+ }
170
+
171
+ // Do we have an author slug?
172
+ if ( empty( $user_nicename ) ) {
173
+ $errors->add(
174
+ 'user_nicename_empty',
175
+ __( '<strong>ERROR</strong>: An author slug cannot be blank. Please try again.', 'edit-author-slug' )
176
+ );
177
+ return;
178
+ }
179
+
180
+ // Stash author slug as it was, mostly, passed.
181
+ $raw_nicename = $user_nicename;
182
+
183
+ // Check to see if the passed nicename contains any invalid characters.
184
+ $ascii = ba_eas_nicename_is_ascii( $user_nicename );
185
+
186
+ // Sanitize the author slug and cache the pre-filtered, sanitized version.
187
+ $user_nicename = $raw_nicename_sanitized = ba_eas_sanitize_nicename( $user_nicename );
188
+
189
+ /**
190
+ * Filters the sanitized user nicename before any final checks are run.
191
+ *
192
+ * @since 1.1.0
193
+ *
194
+ * @param string $user_nicename The sanitized user nicename.
195
+ * @param int $user_id The user id.
196
+ * @param string $raw_nicename The un-sanitized user nicename.
197
+ * @param bool $ascii True if the nicename contains only characters
198
+ * that can be converted to allowed ASCII characters.
199
+ */
200
+ $user_nicename = ba_eas_sanitize_nicename( apply_filters(
201
+ 'ba_eas_pre_update_user_nicename',
202
+ $user_nicename,
203
+ $user->ID,
204
+ $raw_nicename,
205
+ $ascii
206
+ ) );
207
+
208
+ // Was the nicename filtered?
209
+ $changed = ( $raw_nicename_sanitized !== $user_nicename );
210
+
211
+ // Reset `$ascii` if the nicename was filtered.
212
+ if ( $changed ) {
213
+ $ascii = ba_eas_nicename_is_ascii( $user_nicename );
214
+ }
215
+
216
+ // Bail and throw an error if the nicename contains invalid characters.
217
+ if ( ! $ascii ) {
218
+ $errors->add(
219
+ 'user_nicename_invalid_characters',
220
+ __( '<strong>ERROR</strong>: An author slug can only contain alphanumeric characters, underscores (_) and dashes (-).', 'edit-author-slug' )
221
+ );
222
+ return;
223
+ }
224
+
225
+ // Bail and throw an error if the nicename is empty after sanitization.
226
+ if ( empty( $user_nicename ) ) {
227
+ $errors->add(
228
+ 'user_nicename_invalid',
229
+ __( '<strong>ERROR</strong>: That author slug appears to be invalid. Please try something different.', 'edit-author-slug' )
230
+ );
231
+ return;
232
+ }
233
+
234
+ // Bail and throw an error if the nicename contains more than 50 characters.
235
+ if ( mb_strlen( $user_nicename ) > 50 ) {
236
+ $errors->add(
237
+ 'user_nicename_too_long',
238
+ __( '<strong>ERROR</strong>: An author slug may not be longer than 50 characters.', 'edit-author-slug' )
239
+ );
240
+ return;
241
+ }
242
+
243
+ // Make sure the passed nicename is different from the user's current nicename.
244
+ if ( $user_nicename !== $_user->user_nicename ) {
245
+
246
+ // Bail and throw an error if the nicename already exists.
247
+ $exists = get_user_by( 'slug', $user_nicename );
248
+ if ( $exists && (int) $exists->ID !== $user->ID ) {
249
+
250
+ // Setup the error message.
251
+ $message = __(
252
+ '<strong>ERROR</strong>: The author slug, %1$s, already exists. Please try something different.',
253
+ 'edit-author-slug'
254
+ );
255
+
256
+ // Add the error message.
257
+ $errors->add(
258
+ 'user_nicename_exists',
259
+ sprintf(
260
+ $message,
261
+ '<strong><em>' . ba_eas_esc_nicename( $user_nicename ) . '</em></strong>'
262
+ )
263
+ );
264
+
265
+ return;
266
+ }
267
+
268
+ // Looks like we made it, so let's update.
269
+ $user->user_nicename = $user_nicename;
270
+
271
+ // Update the nicename cache.
272
+ add_action( 'profile_update', 'ba_eas_update_nicename_cache', 10, 2 );
273
+ }
274
+ }
275
+
276
+ /**
277
+ * Can the current user edit the author slug?
278
+ *
279
+ * @since 0.8.0
280
+ *
281
+ * @return bool True if edit privileges. Defaults to false.
282
+ */
283
+ function ba_eas_can_edit_author_slug() {
284
+
285
+ // Default to false.
286
+ $retval = false;
287
+
288
+ // True if user is allowed to edit the author slug.
289
+ if ( is_super_admin() || current_user_can( 'edit_users' ) || current_user_can( 'edit_author_slug' ) ) {
290
+ $retval = true;
291
+ }
292
+
293
+ /**
294
+ * Filters the return of `ba_eas_can_edit_author_slug()`.
295
+ *
296
+ * @since 0.8.0
297
+ *
298
+ * @param bool $retval True if a user can edit the author slug.
299
+ */
300
+ return (bool) apply_filters( 'ba_eas_can_edit_author_slug', $retval );
301
+ }
302
+
303
+ /**
304
+ * Adds the 'Author Slug' column and column heading to the users list table.
305
+ *
306
+ * @since 0.5.0
307
+ *
308
+ * @param array $defaults Array of current columns/column headings.
309
+ *
310
+ * @return array Array of current columns/column headings.
311
+ */
312
+ function ba_eas_author_slug_column( $defaults ) {
313
+
314
+ // Set the new column name to "Author Slug".
315
+ $defaults['ba-eas-author-slug'] = esc_html__( 'Author Slug', 'edit-author-slug' );
316
+
317
+ return $defaults;
318
+ }
319
+
320
+ /**
321
+ * Fill in user_nicename for 'Author Slug' column.
322
+ *
323
+ * Adds the user's corresponding user_nicename to the 'Author Slug' column.
324
+ *
325
+ * @since 0.5.0
326
+ *
327
+ * @param string $default Value for column data. Defaults to empty string.
328
+ * @param string $column_name Column name currently being filtered.
329
+ * @param int $user_id The user id.
330
+ *
331
+ * @return string Value for column data. Defaults to empty string.
332
+ */
333
+ function ba_eas_author_slug_custom_column( $default, $column_name, $user_id ) {
334
+
335
+ // Set row value to user_nicename if applicable.
336
+ if ( 'ba-eas-author-slug' === $column_name ) {
337
+ $user = get_userdata( $user_id );
338
+
339
+ if ( ! empty( $user->user_nicename ) ) {
340
+ $default = ba_eas_esc_nicename( $user->user_nicename );
341
+ }
342
+ }
343
+
344
+ return $default;
345
+ }
346
+
347
+ /**
348
+ * Add javascript to appropriate admin pages.
349
+ *
350
+ * Add javascript to user-edit.php and profile.php pages to update custom field
351
+ * when other radio buttons are selected.
352
+ *
353
+ * Add javascript to Edit Author Slug settings page to show/hide the role slugs.
354
+ *
355
+ * @since 0.9.0
356
+ *
357
+ * @param string $hook_suffix The current admin page.
358
+ *
359
+ * @return void
360
+ */
361
+ function ba_eas_show_user_nicename_scripts( $hook_suffix = '' ) {
362
+
363
+ // Set an array of pages to add our js.
364
+ $user_pages = array(
365
+ 'profile.php',
366
+ 'user-edit.php',
367
+ 'settings_page_edit-author-slug',
368
+ );
369
+
370
+ // Bail if we shouldn't add our js.
371
+ if ( ! in_array( $hook_suffix, $user_pages ) || ! ba_eas_can_edit_author_slug() ) {
372
+ return;
373
+ }
374
+
375
+ // Decide whether to load the dev version of the js.
376
+ $min = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
377
+
378
+ // Add our js to the appropriate pages.
379
+ wp_register_script(
380
+ 'edit-author-slug',
381
+ ba_eas()->plugin_url . "js/edit-author-slug{$min}.js",
382
+ array( 'jquery' ),
383
+ ba_eas()->version
384
+ );
385
+ wp_enqueue_script( 'edit-author-slug' );
386
+ }
387
+
388
+ /** Settings *****************************************************************/
389
+
390
+ /**
391
+ * Add the Edit Author Slug Settings Menu.
392
+ *
393
+ * @since 0.9.0
394
+ */
395
+ function ba_eas_add_settings_menu() {
396
+ add_options_page(
397
+ __( 'Edit Author Slug Settings', 'edit-author-slug' ),
398
+ __( 'Edit Author Slug', 'edit-author-slug' ),
399
+ 'edit_users',
400
+ 'edit-author-slug',
401
+ 'ba_eas_settings_page_html'
402
+ );
403
+ }
404
+
405
+ /**
406
+ * Output HTML for settings page.
407
+ *
408
+ * @since 0.9.0
409
+ */
410
+ function ba_eas_settings_page_html() {
411
+ ?>
412
+
413
+ <div class="wrap">
414
+
415
+ <h1><?php esc_html_e( 'Edit Author Slug Settings', 'edit-author-slug' ); ?></h1>
416
+
417
+ <form action="options.php" method="post">
418
+
419
+ <?php settings_fields( 'edit-author-slug' ); ?>
420
+
421
+ <?php do_settings_sections( 'edit-author-slug' ); ?>
422
+
423
+ <?php submit_button(); ?>
424
+ </form>
425
+ </div>
426
+
427
+ <?php
428
+ }
429
+
430
+ /**
431
+ * Add Author Base settings settings page.
432
+ *
433
+ * @since 0.9.0
434
+ */
435
+ function ba_eas_register_admin_settings() {
436
+ // Add the Author Base section.
437
+ add_settings_section(
438
+ 'ba_eas_author_base',
439
+ __( 'Author Base', 'edit-author-slug' ),
440
+ 'ba_eas_admin_setting_callback_author_base_section',
441
+ 'edit-author-slug'
442
+ );
443
+
444
+ // Author Base setting.
445
+ add_settings_field(
446
+ '_ba_eas_author_base',
447
+ __( 'Author Base', 'edit-author-slug' ),
448
+ 'ba_eas_admin_setting_callback_author_base',
449
+ 'edit-author-slug',
450
+ 'ba_eas_author_base',
451
+ array( 'label_for' => '_ba_eas_author_base' )
452
+ );
453
+ register_setting( 'edit-author-slug', '_ba_eas_author_base', 'ba_eas_sanitize_author_base' );
454
+
455
+ // Remove front setting.
456
+ if ( ba_eas_has_front() ) {
457
+ add_settings_field(
458
+ '_ba_eas_remove_front',
459
+ __( 'Remove Front', 'edit-author-slug' ),
460
+ 'ba_eas_admin_setting_callback_remove_front',
461
+ 'edit-author-slug',
462
+ 'ba_eas_author_base',
463
+ array( 'label_for' => '_ba_eas_remove_front' )
464
+ );
465
+ register_setting( 'edit-author-slug', '_ba_eas_remove_front', 'intval' );
466
+ }
467
+
468
+ // Role-Based Author Base setting.
469
+ add_settings_field(
470
+ '_ba_eas_do_role_based',
471
+ __( 'Role-Based Author Base', 'edit-author-slug' ),
472
+ 'ba_eas_admin_setting_callback_do_role_based',
473
+ 'edit-author-slug',
474
+ 'ba_eas_author_base',
475
+ array( 'label_for' => '_ba_eas_do_role_based' )
476
+ );
477
+ register_setting( 'edit-author-slug', '_ba_eas_do_role_based', 'intval' );
478
+
479
+ // Role-Based Author Base slugs.
480
+ add_settings_field(
481
+ '_ba_eas_role_slugs',
482
+ __( 'Role Slugs', 'edit-author-slug' ),
483
+ 'ba_eas_admin_setting_callback_role_slugs',
484
+ 'edit-author-slug',
485
+ 'ba_eas_author_base'
486
+ );
487
+ register_setting( 'edit-author-slug', '_ba_eas_role_slugs', 'ba_eas_admin_setting_sanitize_callback_role_slugs' );
488
+
489
+ // Add the default user nicename section.
490
+ add_settings_section(
491
+ 'ba_eas_auto_update',
492
+ __( 'Automatic Author Slug Creation', 'edit-author-slug' ),
493
+ 'ba_eas_admin_setting_callback_auto_update_section',
494
+ 'edit-author-slug'
495
+ );
496
+
497
+ // Auto-update on/off.
498
+ add_settings_field(
499
+ '_ba_eas_do_auto_update',
500
+ __( 'Automatically Update', 'edit-author-slug' ),
501
+ 'ba_eas_admin_setting_callback_do_auto_update',
502
+ 'edit-author-slug',
503
+ 'ba_eas_auto_update',
504
+ array( 'label_for' => '_ba_eas_do_auto_update' )
505
+ );
506
+ register_setting( 'edit-author-slug', '_ba_eas_do_auto_update', 'intval' );
507
+
508
+ // Default user nicename setting.
509
+ add_settings_field(
510
+ '_ba_eas_default_user_nicename',
511
+ __( 'Author Slug Structure', 'edit-author-slug' ),
512
+ 'ba_eas_admin_setting_callback_default_user_nicename',
513
+ 'edit-author-slug',
514
+ 'ba_eas_auto_update',
515
+ array( 'label_for' => '_ba_eas_default_user_nicename' )
516
+ );
517
+ register_setting( 'edit-author-slug', '_ba_eas_default_user_nicename', 'sanitize_key' );
518
+
519
+ // Add the Bulk Update section.
520
+ add_settings_section(
521
+ 'ba_eas_bulk_update',
522
+ __( 'Bulk Update Author Slugs', 'edit-author-slug' ),
523
+ 'ba_eas_admin_setting_callback_bulk_update_section',
524
+ 'edit-author-slug'
525
+ );
526
+
527
+ // Bulk update.
528
+ add_settings_field(
529
+ '_ba_eas_bulk_update',
530
+ __( 'Bulk Update', 'edit-author-slug' ),
531
+ 'ba_eas_admin_setting_callback_bulk_update',
532
+ 'edit-author-slug',
533
+ 'ba_eas_bulk_update',
534
+ array( 'label_for' => '_ba_eas_bulk_update' )
535
+ );
536
+ register_setting( 'edit-author-slug', '_ba_eas_bulk_update', 'ba_eas_auto_update_user_nicename_bulk' );
537
+
538
+ // Bulk update.
539
+ add_settings_field(
540
+ '_ba_eas_bulk_update_structure',
541
+ __( 'Author Slug Structure', 'edit-author-slug' ),
542
+ 'ba_eas_admin_setting_callback_bulk_update_structure',
543
+ 'edit-author-slug',
544
+ 'ba_eas_bulk_update',
545
+ array( 'label_for' => '_ba_eas_bulk_update_structure' )
546
+ );
547
+ register_setting( 'edit-author-slug', '_ba_eas_bulk_update_structure', '__return_false' );
548
+ }
549
+
550
+ /**
551
+ * Add Author Base settings section.
552
+ *
553
+ * @since 0.9.0
554
+ */
555
+ function ba_eas_admin_setting_callback_author_base_section() {
556
+ ?>
557
+
558
+ <p><?php esc_html_e( 'Change your author base to something more fun!', 'edit-author-slug' ); ?></p>
559
+
560
+ <?php
561
+ }
562
+
563
+ /**
564
+ * Add default user nicename settings section.
565
+ *
566
+ * @since 0.9.0
567
+ */
568
+ function ba_eas_admin_setting_callback_auto_update_section() {
569
+ ?>
570
+
571
+ <p><?php esc_html_e( "Allow Author Slugs to be automatically updated, and set the default Author Slug structure for users. Automatic updating will only occur when a user can't edit Author Slugs on their own.", 'edit-author-slug' ); ?> <br /><strong><em><?php esc_html_e( 'This could have SEO repercussions if users update their profiles frequently, and it will override any manual editing of the Author Slug you may have previously completed.', 'edit-author-slug' ); ?></em></strong></p>
572
+
573
+ <?php
574
+ }
575
+
576
+ /**
577
+ * Add Author Base settings field.
578
+ *
579
+ * @since 0.9.0
580
+ */
581
+ function ba_eas_admin_setting_callback_author_base() {
582
+
583
+ $author_base = ba_eas_sanitize_author_base( ba_eas()->author_base );
584
+
585
+ // Build the demo author link.
586
+ $author_link = esc_url( home_url( '/' ) );
587
+ $author_link = $author_link . '<span class="eas-demo-author-base-front">' . esc_html( trim( $GLOBALS['wp_rewrite']->front, '/' ) ) . '/</span>';
588
+ $author_link = $author_link . '<span class="eas-demo-author-base">' . $author_base . '</span>';
589
+ $author_link = $author_link . user_trailingslashit( '/author-slug' );
590
+ ?>
591
+
592
+ <input id="_ba_eas_author_base" name="_ba_eas_author_base" type="text" value="<?php echo esc_attr( $author_base ); ?>" class="regular-text code" />
593
+ <em><?php esc_html_e( "Defaults to 'author'", 'edit-author-slug' ); ?></em>
594
+ <br /><br />
595
+ <strong>Demo:</strong> <em><?php echo $author_link; ?></em>
596
+
597
+ <?php
598
+ }
599
+
600
+ /**
601
+ * Add the remove front settings field.
602
+ *
603
+ * @since 1.2.0
604
+ *
605
+ * @return void
606
+ */
607
+ function ba_eas_admin_setting_callback_remove_front() {
608
+ ?>
609
+
610
+ <input name="_ba_eas_remove_front" id="_ba_eas_remove_front" value="1"<?php checked( ba_eas()->remove_front ); ?> type="checkbox" />
611
+ <?php esc_html_e( 'Remove the "front" portion of the author permalink structure.', 'edit-author-slug' ); ?>
612
+
613
+ <?php
614
+ }
615
+
616
+ /**
617
+ * Add Role-Based Author Base checkbox.
618
+ *
619
+ * @since 1.0.0
620
+ */
621
+ function ba_eas_admin_setting_callback_do_role_based() {
622
+ ?>
623
+
624
+ <input class="eas-checkbox" name="_ba_eas_do_role_based" id="_ba_eas_do_role_based" value="1"<?php checked( ba_eas()->do_role_based ); ?> type="checkbox" />
625
+ <?php esc_html_e( "Set user's Author Base according to their role.", 'edit-author-slug' ); ?>
626
+ <br /><br />
627
+ <?php echo sprintf(
628
+ esc_html__(
629
+ 'Use the %1$s rewrite tag to customize the role-based author base. If you set the author base to "%2$s", the resulting author structure will be something like "%3$s".',
630
+ 'edit-author-slug'
631
+ ),
632
+ '<code>%ba_eas_author_role%</code>',
633
+ '<em>cool-people/&#37;ba_eas_author_role&#37;</em>',
634
+ '<em>http://example.com/cool-people/role-slug/author-slug</em>'
635
+ ); ?>
636
+
637
+ <?php
638
+ }
639
+
640
+ /**
641
+ * Output the Role-Based Author Base slugs for editing.
642
+ *
643
+ * @since 1.0.0
644
+ */
645
+ function ba_eas_admin_setting_callback_role_slugs() {
646
+
647
+ // Get the default role slugs.
648
+ $defaults = ba_eas_get_default_role_slugs();
649
+
650
+ // Make sure we didn't pick up any dynamic roles between now and initialization.
651
+ $roles = array_replace_recursive( $defaults, ba_eas()->role_slugs );
652
+
653
+ // Display the role slug customization fields.
654
+ foreach ( $roles as $role => $details ) {
655
+
656
+ // Don't display a role slug if the role has been removed.
657
+ if ( empty( $defaults[ $role ] ) ) {
658
+ continue;
659
+ }
660
+
661
+ // Don't display a role slug, if the user can't see a name.
662
+ if ( empty( $details['name'] ) ) {
663
+ continue;
664
+ }
665
+
666
+ // Sanitize the slug.
667
+ $details['slug'] = sanitize_title( $details['slug'] );
668
+
669
+ // Check for empty slugs when picking up a dynamic role.
670
+ if ( empty( $details['slug'] ) ) {
671
+ $details['slug'] = sanitize_title( translate_user_role( $details['name'] ) );
672
+ }
673
+ ?>
674
+
675
+ <input name="_ba_eas_role_slugs[<?php echo esc_attr( $role ); ?>][slug]" id="_ba_eas_role_slugs[<?php echo esc_attr( $role ); ?>][slug]" type="text" value="<?php echo ba_eas_esc_nicename( $details['slug'] ); ?>" class="regular-text code" />
676
+ <label for="_ba_eas_role_slugs[<?php echo esc_attr( $role ); ?>][slug]"><?php echo esc_html( translate_user_role( $details['name'] ) ); ?></label><br />
677
+
678
+ <?php
679
+ }
680
+ }
681
+
682
+ /**
683
+ * Sanitize the custom Role-Based Author Base slugs.
684
+ *
685
+ * @since 1.0.0
686
+ *
687
+ * @param array $role_slugs An array of role slugs.
688
+ *
689
+ * @return array An array of sanitized, role-based author slugs.
690
+ */
691
+ function ba_eas_admin_setting_sanitize_callback_role_slugs( $role_slugs = array() ) {
692
+
693
+ // Get default role slugs.
694
+ $defaults = ba_eas_get_default_role_slugs();
695
+
696
+ // Sanitize the slugs passed via POST.
697
+ foreach ( $role_slugs as $role => $details ) {
698
+
699
+ // If the role has been removed, we don't need to save it.
700
+ if ( empty( $defaults[ $role ] ) ) {
701
+ unset( $role_slugs[ $role ] );
702
+ continue;
703
+ }
704
+
705
+ // Sanitize the passed role slug.
706
+ $slug = sanitize_title( $details['slug'] );
707
+
708
+ // Make sure we have a slug.
709
+ if ( empty( $slug ) && ! empty( $defaults[ $role ]['slug'] ) ) {
710
+ $slug = $defaults[ $role ]['slug'];
711
+ }
712
+
713
+ // Remove the role if we don't have a slug.
714
+ if ( empty( $slug ) ) {
715
+ unset( $role_slugs[ $role ] );
716
+
717
+ // We made it through, so set the slug.
718
+ } else {
719
+ $role_slugs[ $role ]['slug'] = $slug;
720
+ }
721
+ }
722
+
723
+ // Merge our changes to make sure we've got everything.
724
+ $role_slugs = array_replace_recursive( $defaults, $role_slugs );
725
+
726
+ // Set BA_Edit_Author_Slug::role_slugs for later use.
727
+ ba_eas()->role_slugs = $role_slugs;
728
+
729
+ return $role_slugs;
730
+ }
731
+
732
+ /**
733
+ * Add auto-update checkbox.
734
+ *
735
+ * @since 0.9.0
736
+ */
737
+ function ba_eas_admin_setting_callback_do_auto_update() {
738
+ ?>
739
+
740
+ <input class="eas-checkbox" name="_ba_eas_do_auto_update" id="_ba_eas_do_auto_update" value="1"<?php checked( ba_eas()->do_auto_update ); ?> type="checkbox" />
741
+ <?php esc_html_e( 'Automatically update Author Slug when a user updates their profile.', 'edit-author-slug' ); ?>
742
+
743
+ <?php
744
+ }
745
+
746
+ /**
747
+ * Add default user nicename options.
748
+ *
749
+ * @since 0.9.0
750
+ */
751
+ function ba_eas_admin_setting_callback_default_user_nicename() {
752
+
753
+ // Get the nicename structure.
754
+ $structure = ba_eas()->default_user_nicename;
755
+
756
+ // Set to default nicename structure if needed.
757
+ if ( empty( $structure ) ) {
758
+ $structure = 'username';
759
+ }
760
+
761
+ // Get the default nicename options.
762
+ $options = ba_eas_default_user_nicename_options_list();
763
+ ?>
764
+
765
+ <span class="screen-reader-text"><?php esc_html_e( 'Default author slug options', 'edit-author-slug' ); ?></span>
766
+ <select id="_ba_eas_default_user_nicename" name="_ba_eas_default_user_nicename">
767
+ <?php foreach ( (array) $options as $id => $item ) { ?>
768
+ <option id="<?php echo esc_attr( $id ); ?>" value="<?php echo esc_attr( $id ); ?>"<?php selected( $structure, $id ); ?>><?php echo esc_html( $item ); ?></option>
769
+ <?php } ?>
770
+ </select>
771
+
772
+ <?php
773
+ }
774
+
775
+ /**
776
+ * Add bulk update option.
777
+ *
778
+ * @since 1.1.0
779
+ *
780
+ * @return void
781
+ */
782
+ function ba_eas_admin_setting_callback_bulk_update_section() {
783
+ ?>
784
+
785
+ <p><?php esc_html_e( 'Update all users at once based on the specified Author Slug structure.', 'edit-author-slug' ); ?></p>
786
+
787
+ <?php
788
+ }
789
+
790
+ /**
791
+ * Add bulk update option.
792
+ *
793
+ * @since 1.1.0
794
+ *
795
+ * @return void
796
+ */
797
+ function ba_eas_admin_setting_callback_bulk_update() {
798
+ ?>
799
+
800
+ <input class="eas-checkbox" name="_ba_eas_bulk_update" id="_ba_eas_bulk_update" value="1" type="checkbox" />
801
+ <?php esc_html_e( 'Update all users according to the below Author Slug setting. This will only be run after clicking "Save Changes".', 'edit-author-slug' ); ?>
802
+
803
+ <?php
804
+ }
805
+
806
+ /**
807
+ * Add default user nicename options.
808
+ *
809
+ * @since 0.9.0
810
+ */
811
+ function ba_eas_admin_setting_callback_bulk_update_structure() {
812
+
813
+ // Get the nicename structure.
814
+ $structure = ba_eas()->default_user_nicename;
815
+
816
+ // Set to default nicename structure if needed.
817
+ if ( empty( $structure ) ) {
818
+ $structure = 'username';
819
+ }
820
+
821
+ // Get the default nicename options.
822
+ $options = ba_eas_default_user_nicename_options_list();
823
+ ?>
824
+
825
+ <span class="screen-reader-text"><?php esc_html_e( 'Default bulk update author slug options', 'edit-author-slug' ); ?></span>
826
+ <select id="_ba_eas_bulk_update_structure" name="_ba_eas_bulk_update_structure">
827
+ <?php foreach ( (array) $options as $id => $item ) { ?>
828
+ <option id="<?php echo esc_attr( $id ); ?>" value="<?php echo esc_attr( $id ); ?>"<?php selected( $structure, $id ); ?>><?php echo esc_html( $item ); ?></option>
829
+ <?php } ?>
830
+ </select>
831
+
832
+ <?php
833
+ }
834
+
835
+ /**
836
+ * Add settings link to plugin listing.
837
+ *
838
+ * @since 0.9.1
839
+ *
840
+ * @param array $links Links array in which we would prepend our link.
841
+ * @param string $file Current plugin basename.
842
+ *
843
+ * @return string The array of plugin action links.
844
+ */
845
+ function ba_eas_add_settings_link( $links, $file ) {
846
+
847
+ if ( ba_eas()->plugin_basename === $file ) {
848
+ $settings_link = '<a href="' . esc_url( add_query_arg( array( 'page' => 'edit-author-slug' ), admin_url( 'options-general.php' ) ) ) . '">' . esc_html__( 'Settings', 'edit-author-slug' ) . '</a>';
849
+ array_unshift( $links, $settings_link );
850
+ }
851
+
852
+ return $links;
853
+ }
854
+
855
+ /**
856
+ * Returns the default nicename options list.
857
+ *
858
+ * @since 1.2.0
859
+ *
860
+ * @return array
861
+ */
862
+ function ba_eas_default_user_nicename_options_list() {
863
+
864
+ /**
865
+ * Filters the array of user nicename structure options.
866
+ *
867
+ * @since 0.9.0
868
+ * @since 1.2.0 Moved filter into it's own wrapper function.
869
+ *
870
+ * @param array $options An array of of user nicename structure options.
871
+ */
872
+ $options = apply_filters( 'ba_eas_default_user_nicename_options_list', array(
873
+ 'username' => __( 'username (Default)', 'edit-author-slug' ),
874
+ 'nickname' => __( 'nickname', 'edit-author-slug' ),
875
+ 'displayname' => __( 'displayname', 'edit-author-slug' ),
876
+ 'firstname' => __( 'firstname', 'edit-author-slug' ),
877
+ 'lastname' => __( 'lastname', 'edit-author-slug' ),
878
+ 'firstlast' => __( 'firstname-lastname', 'edit-author-slug' ),
879
+ 'lastfirst' => __( 'lastname-firstname', 'edit-author-slug' ),
880
+ 'userid' => __( 'userid (Experimental)', 'edit-author-slug' ),
881
+ ) );
882
+
883
+ return (array) $options;
884
+ }
885
+
886
+ /**
887
+ * Checks to see that we are updating Edit Author Slug settings. If so, we call
888
+ * `ba_eas_settings_updated` hook.
889
+ *
890
+ * This function is called by `admin_action_update` which tells us that the
891
+ * *intention* is to update. Unfortunately, we can't tell if there are errors at
892
+ * this point, and there are no (good) hooks to determine this. The benefit to
893
+ * method, however, is that we can check the nonce for better security than
894
+ * the other methods. This way, the `ba_eas_settings_updated` is only called if
895
+ * it's safe to do so.
896
+ *
897
+ * @since 1.2.0
898
+ *
899
+ * @return void
900
+ */
901
+ function ba_eas_settings_updated() {
902
+
903
+ // Make sure we're on the Edit Author Slug settings page.
904
+ if ( ! isset( $_REQUEST['option_page'] ) || 'edit-author-slug' !== $_REQUEST['option_page'] ) {
905
+ return;
906
+ }
907
+
908
+ // Check that a valid nonce was passed.
909
+ if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'edit-author-slug-options' ) ) {
910
+ return;
911
+ }
912
+
913
+ /**
914
+ * Fires when `$POST['action'] = update` on our settings page.
915
+ *
916
+ * @since 1.2.0
917
+ */
918
+ do_action( 'ba_eas_settings_updated' );
919
+ }
920
+
921
+ /** Install/Upgrade ***********************************************************/
922
+
923
+ /**
924
+ * Install Edit Author Slug.
925
+ *
926
+ * Add options on install to reduce calls to the db.
927
+ *
928
+ * @since 1.0.0
929
+ */
930
+ function ba_eas_install() {
931
+
932
+ // Edit Author Slug instance.
933
+ $ba_eas = ba_eas();
934
+
935
+ // Bail if it's not a new install.
936
+ if ( 0 !== $ba_eas->current_db_version ) {
937
+ return;
938
+ }
939
+
940
+ // Add the options.
941
+ add_option( '_ba_eas_author_base', $ba_eas->author_base );
942
+ add_option( '_ba_eas_db_version', $ba_eas->db_version );
943
+ add_option( '_ba_eas_do_auto_update', (int) $ba_eas->do_auto_update );
944
+ add_option( '_ba_eas_default_user_nicename', $ba_eas->default_user_nicename );
945
+ add_option( '_ba_eas_do_role_based', (int) $ba_eas->do_role_based );
946
+ add_option( '_ba_eas_role_slugs', $ba_eas->role_slugs );
947
+ add_option( '_ba_eas_remove_front', (int) $ba_eas->remove_front );
948
+ }
949
+
950
+ /**
951
+ * Upgrade Edit Author Slug.
952
+ *
953
+ * Just cleans up some options for now.
954
+ *
955
+ * @since 0.8.0
956
+ */
957
+ function ba_eas_upgrade() {
958
+
959
+ // Edit Author Slug instance.
960
+ $ba_eas = ba_eas();
961
+
962
+ // We're up-to-date, so let's move on.
963
+ if ( $ba_eas->current_db_version === $ba_eas->db_version ) {
964
+ return;
965
+ }
966
+
967
+ // < 0.8.0.
968
+ if ( $ba_eas->current_db_version < 132 ) {
969
+ // Add new options.
970
+ add_option( '_ba_eas_author_base', $ba_eas->author_base );
971
+
972
+ // Rename the old option for safe keeping.
973
+ update_option( '_ba_eas_old_options', get_option( 'ba_edit_author_slug' ) );
974
+ delete_option( 'ba_edit_author_slug' );
975
+ }
976
+
977
+ // < 1.0.0.
978
+ if ( $ba_eas->current_db_version < 133 ) {
979
+ add_option( '_ba_eas_do_auto_update', (int) $ba_eas->do_auto_update );
980
+ add_option( '_ba_eas_default_user_nicename', $ba_eas->default_user_nicename );
981
+ add_option( '_ba_eas_do_role_based', (int) $ba_eas->do_role_based );
982
+ add_option( '_ba_eas_role_slugs', $ba_eas->role_slugs );
983
+ }
984
+
985
+ // < 1.2.0.
986
+ if ( $ba_eas->current_db_version < 411 ) {
987
+ add_option( '_ba_eas_remove_front', (int) $ba_eas->remove_front );
988
+ }
989
+
990
+ // Version bump.
991
+ update_option( '_ba_eas_db_version', $ba_eas->db_version );
992
+
993
+ // Courtesy flush.
994
+ ba_eas_flush_rewrite_rules();
995
+ }
includes/functions.php ADDED
@@ -0,0 +1,901 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Edit Author Slug Core Functions
4
+ *
5
+ * @package Edit_Author_Slug
6
+ * @subpackage Core
7
+ *
8
+ * @author Brandon Allen
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ defined( 'ABSPATH' ) || exit;
13
+
14
+ /** Nicename ******************************************************************/
15
+
16
+ /**
17
+ * Determines if an auto-update should occur
18
+ *
19
+ * @since 0.9.0
20
+ *
21
+ * @return bool True if auto-update enabled.
22
+ */
23
+ function ba_eas_do_auto_update() {
24
+
25
+ /**
26
+ * Filters the return of the `do_auto_update` option.
27
+ *
28
+ * @since 0.9.0
29
+ *
30
+ * @param bool $do_auto_update The `do_auto_update` option.
31
+ */
32
+ return (bool) apply_filters( 'ba_eas_do_auto_update', ba_eas()->do_auto_update );
33
+ }
34
+
35
+ /**
36
+ * Auto-update the user_nicename for a given user.
37
+ *
38
+ * @since 0.9.0
39
+ *
40
+ * @param int $user_id User id.
41
+ * @param bool $bulk Bulk upgrade flag. Defaults to false.
42
+ * @param string $structure The nicename structure to use during update.
43
+ *
44
+ * @return bool|int User id on success. False on failure.
45
+ */
46
+ function ba_eas_auto_update_user_nicename( $user_id, $bulk = false, $structure = '' ) {
47
+
48
+ // Bail if there's no id or object.
49
+ if ( empty( $user_id ) ) {
50
+ return false;
51
+ }
52
+
53
+ // Bail if we're not bulk updating and auto-update is disabled.
54
+ if ( false === $bulk && ! ba_eas_do_auto_update() ) {
55
+ return false;
56
+ }
57
+
58
+ // Get WP_User object.
59
+ $user = get_userdata( $user_id );
60
+
61
+ // Double check we're still good.
62
+ if ( empty( $user->ID ) ) {
63
+ return false;
64
+ }
65
+
66
+ // Setup the user_id.
67
+ $user_id = (int) $user->ID;
68
+
69
+ if ( empty( $structure ) ) {
70
+ $structure = ba_eas()->default_user_nicename;
71
+ }
72
+
73
+ /**
74
+ * Filters the auto-update user nicename structure.
75
+ *
76
+ * @since 0.9.0
77
+ *
78
+ * @param string $structure The auto-update structure.
79
+ * @param int $user_id The user id.
80
+ */
81
+ $structure = apply_filters( 'ba_eas_auto_update_user_nicename_structure', $structure, $user_id );
82
+
83
+ // Make sure we have a structure.
84
+ if ( empty( $structure ) ) {
85
+ $structure = 'username';
86
+ }
87
+
88
+ // Setup the current nicename.
89
+ $old_nicename = $user->user_login;
90
+ if ( ! empty( $user->user_nicename ) ) {
91
+ $old_nicename = $user->user_nicename;
92
+ }
93
+
94
+ // Setup default nicename.
95
+ $nicename = $old_nicename;
96
+
97
+ // Setup the new nicename based on the provided structure.
98
+ switch ( $structure ) {
99
+
100
+ case 'username':
101
+
102
+ if ( ! empty( $user->user_login ) ) {
103
+ $nicename = $user->user_login;
104
+ }
105
+
106
+ break;
107
+
108
+ case 'nickname':
109
+
110
+ if ( ! empty( $user->nickname ) ) {
111
+ $nicename = $user->nickname;
112
+ }
113
+
114
+ break;
115
+
116
+ case 'displayname':
117
+
118
+ if ( ! empty( $user->display_name ) ) {
119
+ $nicename = $user->display_name;
120
+ }
121
+
122
+ break;
123
+
124
+ case 'firstname':
125
+
126
+ if ( ! empty( $user->first_name ) ) {
127
+ $nicename = $user->first_name;
128
+ }
129
+
130
+ break;
131
+
132
+ case 'lastname':
133
+
134
+ if ( ! empty( $user->last_name ) ) {
135
+ $nicename = $user->last_name;
136
+ }
137
+
138
+ break;
139
+
140
+ case 'firstlast':
141
+
142
+ if ( ! empty( $user->first_name ) && ! empty( $user->last_name ) ) {
143
+ $nicename = $user->first_name . '-' . $user->last_name;
144
+ }
145
+
146
+ break;
147
+
148
+ case 'lastfirst':
149
+
150
+ if ( ! empty( $user->first_name ) && ! empty( $user->last_name ) ) {
151
+ $nicename = $user->last_name . '-' . $user->first_name;
152
+ }
153
+
154
+ break;
155
+
156
+ case 'userid':
157
+
158
+ $nicename = $user_id;
159
+
160
+ break;
161
+ }
162
+
163
+ // Sanitize and trim the new user nicename.
164
+ $nicename = ba_eas_trim_nicename( ba_eas_sanitize_nicename( $nicename ) );
165
+
166
+ /**
167
+ * Filters the auto-updated user nicename before being saved.
168
+ *
169
+ * @since 0.9.0
170
+ *
171
+ * @param string $nicename The new user nicename.
172
+ * @param int $user_id The user id.
173
+ * @param string $structure The auto-update structure.
174
+ */
175
+ $nicename = apply_filters( 'ba_eas_pre_auto_update_user_nicename', $nicename, $user_id, $structure );
176
+
177
+ // Bail if nothing changed or the nicename is empty.
178
+ if ( empty( $nicename ) || $nicename === $old_nicename ) {
179
+ return false;
180
+ }
181
+
182
+ // Remove the auto-update actions so we don't find ourselves in a loop.
183
+ remove_action( 'profile_update', 'ba_eas_auto_update_user_nicename' );
184
+
185
+ // Update if there's a change.
186
+ $user_id = wp_update_user( array( 'ID' => $user_id, 'user_nicename' => $nicename ) );
187
+
188
+ // Add it back in case other plugins do some updating.
189
+ add_action( 'profile_update', 'ba_eas_auto_update_user_nicename' );
190
+
191
+ /*
192
+ * Since this is an action taken without the user's knowledge we must fail
193
+ * silently. Therefore, we only want to update the cache if we're successful.
194
+ */
195
+ if ( ! empty( $user_id ) && ! is_wp_error( $user_id ) ) {
196
+
197
+ // Update the nicename cache.
198
+ ba_eas_update_nicename_cache( $user_id, $user, $nicename );
199
+ }
200
+
201
+ return $user_id;
202
+ }
203
+
204
+ /**
205
+ * Auto-update the user_nicename for a given user.
206
+ *
207
+ * Runs on profile updates and registrations
208
+ *
209
+ * @since 0.9.0
210
+ *
211
+ * @deprecated 1.1.0 Use `ba_eas_auto_update_user_nicename()` instead.
212
+ *
213
+ * @param int $user_id The user id.
214
+ *
215
+ * @return bool|int $user_id. False on failure.
216
+ */
217
+ function ba_eas_auto_update_user_nicename_single( $user_id = 0 ) {
218
+ _deprecated_function( __FUNCTION__, '1.1.0', 'ba_eas_auto_update_user_nicename' );
219
+ return ba_eas_auto_update_user_nicename( $user_id );
220
+ }
221
+
222
+ /**
223
+ * Auto-update the user_nicename for a given user.
224
+ *
225
+ * Runs during the bulk upgrade process in the Dashboard.
226
+ *
227
+ * @since 0.9.0
228
+ *
229
+ * @param string $value The option value passed to the settings API.
230
+ *
231
+ * @return bool False to prevent the setting from being saved to the db.
232
+ */
233
+ function ba_eas_auto_update_user_nicename_bulk( $value = false ) {
234
+
235
+ // Nonce check.
236
+ check_admin_referer( 'edit-author-slug-options' );
237
+
238
+ // Default the structure to the auto-update structure.
239
+ $structure = ba_eas()->default_user_nicename;
240
+
241
+ // If a bulk update structure was passed, use that.
242
+ if ( isset( $_POST['_ba_eas_bulk_update_structure'] ) ) {
243
+ $structure = sanitize_key( $_POST['_ba_eas_bulk_update_structure'] );
244
+ }
245
+
246
+ // Sanitize the option value.
247
+ $value = (bool) absint( $value );
248
+
249
+ // Bail if the user didn't ask to run the bulk update.
250
+ if ( ! $value ) {
251
+ return false;
252
+ }
253
+
254
+ // Get an array of ids of all users.
255
+ $users = get_users( array( 'fields' => 'ID' ) );
256
+
257
+ /**
258
+ * Filters the array of user ids who will have their user nicenames updated.
259
+ *
260
+ * @since 1.1.0
261
+ *
262
+ * @param array $users The array of user ids to update.
263
+ */
264
+ $users = (array) apply_filters( 'ba_eas_auto_update_user_nicename_bulk_user_ids', $users );
265
+
266
+ // Set the default updated count.
267
+ $updated = 0;
268
+
269
+ // Loop through all the users and maybe update their nicenames.
270
+ foreach ( $users as $user_id ) {
271
+
272
+ // Maybe update the user nicename.
273
+ $id = ba_eas_auto_update_user_nicename( $user_id, true, $structure );
274
+
275
+ // If updating was a success, the bump the updated count.
276
+ if ( ! empty( $id ) && ! is_wp_error( $id ) ) {
277
+ $updated++;
278
+ }
279
+ }
280
+
281
+ // Add a message to the settings page denoting user how many users were updated.
282
+ add_settings_error(
283
+ '_ba_eas_bulk_auto_update',
284
+ 'bulk_user_nicenames_updated',
285
+ sprintf( __( '%d user author slug(s) updated.', 'edit-author-slug' ), $updated ),
286
+ 'updated'
287
+ );
288
+
289
+ // Return false to short-circuit the update_option routine, and prevent saving.
290
+ return false;
291
+ }
292
+
293
+ /**
294
+ * Helper function to sanitize a nicename in the same manner as the WP function
295
+ * `wp_insert_user()`.
296
+ *
297
+ * If `$strict` is set to true, this function will result in a nicename that
298
+ * only contains the alphanumeric characters, underscores (_) and dashes (-).
299
+ *
300
+ * @since 1.1.0
301
+ *
302
+ * @param string $nicename The nicename being sanitized.
303
+ * @param bool $strict True to return only ASCII characters.
304
+ *
305
+ * @return string The nicename.
306
+ */
307
+ function ba_eas_sanitize_nicename( $nicename = '', $strict = true ) {
308
+ return sanitize_title( sanitize_user( $nicename, (bool) $strict ) );
309
+ }
310
+
311
+ /**
312
+ * Sanitize author base and add to database.
313
+ *
314
+ * @since 0.8.0
315
+ * @since 1.2.0 Removed all non-sanitization code.
316
+ * @since 1.3.0 Allow `%ba_eas_author_role%` rewrite tag in author base.
317
+ *
318
+ * @param string $author_base Author base to be sanitized.
319
+ *
320
+ * @return string The author base.
321
+ */
322
+ function ba_eas_sanitize_author_base( $author_base = 'author' ) {
323
+
324
+ // Store the author base as passed.
325
+ $original_author_base = $author_base;
326
+
327
+ // Only do extra sanitization when needed.
328
+ if ( ! empty( $author_base ) || 'author' !== $author_base ) {
329
+
330
+ // Split the author base string on forward slashes.
331
+ $parts = explode( '/', $author_base );
332
+
333
+ // Sanitize all parts except our rewrite tag, `%ba_eas_author_role%`.
334
+ foreach ( $parts as $key => $part ) {
335
+ if ( '%ba_eas_author_role%' !== $part ) {
336
+ $part = sanitize_title( $part );
337
+ }
338
+
339
+ $parts[ $key ] = $part;
340
+ }
341
+
342
+ // Sanitize the parts, and put them back together.
343
+ $author_base = implode( '/', array_filter( $parts ) );
344
+ }
345
+
346
+ // Always default to `author`.
347
+ if ( empty( $author_base ) ) {
348
+ $author_base = 'author';
349
+ }
350
+
351
+ /**
352
+ * Filters the sanitized author base.
353
+ *
354
+ * @param string $author_base The sanitized author base.
355
+ * @param string $original_author_base The unsanitized author base.
356
+ */
357
+ return apply_filters( 'ba_eas_sanitize_author_base', $author_base, $original_author_base );
358
+ }
359
+
360
+ /**
361
+ * Helper function to escape the nicename in the same manner as other slugs are
362
+ * escaped in WP.
363
+ *
364
+ * @since 1.1.0
365
+ *
366
+ * @param string $nicename The nicename being sanitized.
367
+ *
368
+ * @return string The nicename.
369
+ */
370
+ function ba_eas_esc_nicename( $nicename = '' ) {
371
+ return esc_textarea( urldecode( $nicename ) );
372
+ }
373
+
374
+ /**
375
+ * Helper function to trim the nicename to less than 50 characters, and strip
376
+ * off any leading/trailing hyphens or underscores.
377
+ *
378
+ * @since 1.1.0
379
+ *
380
+ * @param string $nicename The nicename being sanitized.
381
+ *
382
+ * @return string The nicename.
383
+ */
384
+ function ba_eas_trim_nicename( $nicename = '' ) {
385
+ return trim( mb_substr( $nicename, 0, 50 ), '-_' );
386
+ }
387
+
388
+ /**
389
+ * Helper function to check a nicename for characters that won't be converted
390
+ * to ASCII characters.
391
+ *
392
+ * Before being saved to the db, `wp_insert_user()` converts nicenames by
393
+ * running them through `sanitize_user()` with the `$strict` parameter set to
394
+ * `true`, then through `sanitize_title()`. This results in a user nicename that
395
+ * only contains alphanumeric characters, underscores (_) and dashes (-). Rather
396
+ * than silently strip invalid characters, this function allows us to inform the
397
+ * editing user that their passed user nicename contains characters that won't
398
+ * make it through the `wp_insert_user()` sanitization process.
399
+ *
400
+ * @since 1.1.0
401
+ *
402
+ * @param string $nicename The nicename to check for invalid characters.
403
+ *
404
+ * @return bool True if the nicename contains only ASCII characters, or
405
+ * characters that can be converted to ASCII.
406
+ */
407
+ function ba_eas_nicename_is_ascii( $nicename = '' ) {
408
+ return ba_eas_sanitize_nicename( $nicename ) === ba_eas_sanitize_nicename( $nicename, false );
409
+ }
410
+
411
+ /** Author Base ***************************************************************/
412
+
413
+ /**
414
+ * Overrides the WP_Rewrite properties, `author_base` and `author_structure`,
415
+ * when appropriate.
416
+ *
417
+ * @since 1.2.0
418
+ * @since 1.3.0 Allow `%ba_eas_author_role%` rewrite tag in author base.
419
+ *
420
+ * @return void
421
+ */
422
+ function ba_eas_wp_rewrite_overrides() {
423
+
424
+ // Set default author base.
425
+ $author_base = 'author';
426
+
427
+ // Set to our author base if it exists.
428
+ if ( ! empty( ba_eas()->author_base ) ) {
429
+ $author_base = ba_eas()->author_base;
430
+ }
431
+
432
+ // If doing role-based, set accordingly.
433
+ if ( ba_eas_do_role_based_author_base() && false === strpos( $author_base, '%ba_eas_author_role%' ) ) {
434
+ $author_base = '%ba_eas_author_role%';
435
+ }
436
+
437
+ // Override WP_Rewrite::author_base with our new value.
438
+ $GLOBALS['wp_rewrite']->author_base = $author_base;
439
+
440
+ // Override `WP_Rewrite::author_structure` with our new value.
441
+ if ( ba_eas_remove_front() && ba_eas_has_front() ) {
442
+ $GLOBALS['wp_rewrite']->author_structure = '/' . $author_base . '/%author%';
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Determines if we should remove the `front` portion of the author structure.
448
+ *
449
+ * @since 1.2.0
450
+ *
451
+ * @return bool
452
+ */
453
+ function ba_eas_remove_front() {
454
+
455
+ /**
456
+ * Filters the return of the `remove_front` option.
457
+ *
458
+ * @since 1.2.0
459
+ *
460
+ * @param bool $remove_front The `remove_front` option.
461
+ */
462
+ return (bool) apply_filters( 'ba_eas_remove_front', ba_eas()->remove_front );
463
+ }
464
+
465
+ /**
466
+ * Determines if `WP_Rewrite::front` is anything other than `/`.
467
+ *
468
+ * @since 1.2.0
469
+ *
470
+ * @return bool
471
+ */
472
+ function ba_eas_has_front() {
473
+
474
+ /**
475
+ * Filters the return of the `ba_eas_has_front` option.
476
+ *
477
+ * @since 1.2.0
478
+ *
479
+ * @param bool $has_front The `remove_front` option.
480
+ */
481
+ return (bool) apply_filters( 'ba_eas_has_front', '/' !== $GLOBALS['wp_rewrite']->front );
482
+ }
483
+
484
+ /**
485
+ * Determines if we should do a role-based author base
486
+ *
487
+ * @since 1.0.0
488
+ *
489
+ * @return bool True if role-based author base enabled.
490
+ */
491
+ function ba_eas_do_role_based_author_base() {
492
+
493
+ /**
494
+ * Filters the return of the `do_role_based` option.
495
+ *
496
+ * @since 1.0.0
497
+ *
498
+ * @param bool $do_role_based The `do_role_based` option.
499
+ */
500
+ return (bool) apply_filters( 'ba_eas_do_role_based_author_base', ba_eas()->do_role_based );
501
+ }
502
+
503
+ /**
504
+ * Replaces author role rewrite tag with the role of the user.
505
+ *
506
+ * If the user has more than one role, the first role listed in the WP_User::$roles
507
+ * array will be used.
508
+ *
509
+ * @since 1.0.0
510
+ *
511
+ * @param string $link The author link with user role as author base.
512
+ * @param int $user_id The user id.
513
+ *
514
+ * @return string Author archive link.
515
+ */
516
+ function ba_eas_author_link( $link = '', $user_id = 0 ) {
517
+
518
+ // Add a role slug if we're doing role based author bases.
519
+ if ( ba_eas_do_role_based_author_base() && false !== strpos( $link, '%ba_eas_author_role%' ) ) {
520
+
521
+ // Setup the user.
522
+ $user = get_userdata( $user_id );
523
+
524
+ // Grab the first listed role.
525
+ $role = ba_eas_get_user_role( $user->roles, $user_id );
526
+
527
+ // Make sure we have a valid slug.
528
+ $slug = empty( ba_eas()->role_slugs[ $role ]['slug'] ) ? ba_eas()->author_base : ba_eas()->role_slugs[ $role ]['slug'];
529
+
530
+ // Add the role slug to the link.
531
+ $link = str_replace( '%ba_eas_author_role%', $slug, $link );
532
+ }
533
+
534
+ // Remove front if applicable.
535
+ if ( ba_eas_has_front() && ba_eas_remove_front() ) {
536
+ $link = str_replace( $GLOBALS['wp_rewrite']->front, '/', $link );
537
+ }
538
+
539
+ // Return the link.
540
+ return $link;
541
+ }
542
+
543
+ /**
544
+ * Allow author templates to be based on role.
545
+ *
546
+ * Instead of only using author-{user_nicename}.php, author-{ID}.php, and
547
+ * author.php for templates, this allows author-{role}.php or
548
+ * author-{role-slug}.php to be used as well.
549
+ *
550
+ * @since 1.0.0
551
+ *
552
+ * @param string $template Current template according to template hierarchy.
553
+ *
554
+ * @return string Author archive link.
555
+ */
556
+ function ba_eas_template_include( $template ) {
557
+
558
+ // Bail if we're not doing role-based author bases.
559
+ if ( ! ba_eas_do_role_based_author_base() ) {
560
+ return $template;
561
+ }
562
+
563
+ // Get queried object, should be a WP_User object.
564
+ $author = get_queried_object();
565
+
566
+ // Make sure we have a WP_User object.
567
+ if ( ! is_a( $author, 'WP_User' ) ) {
568
+ return $template;
569
+ }
570
+
571
+ // Nicename and ID templates should take priority, so we need to check for their existence.
572
+ $nicename_template = strpos( $template, "author-{$author->user_nicename}.php" );
573
+ $id_template = strpos( $template, "author-{$author->ID}.php" );
574
+
575
+ // If they don't exist, search for a role based template.
576
+ if ( false === $nicename_template && false === $id_template ) {
577
+
578
+ // Grab the first listed role.
579
+ $role = ba_eas_get_user_role( $author->roles, $author->ID );
580
+
581
+ // Get the role slug.
582
+ $role_slug = '';
583
+ if ( ! empty( ba_eas()->role_slugs[ $role ]['slug'] ) ) {
584
+ $role_slug = ba_eas()->role_slugs[ $role ]['slug'];
585
+ }
586
+
587
+ // Set the templates array.
588
+ $templates = array();
589
+
590
+ // Add the role template.
591
+ if ( ! empty( $role ) ) {
592
+ $templates[] = "author-{$role}.php";
593
+ }
594
+
595
+ // Add the role_slug template.
596
+ if ( ! empty( $role_slug ) ) {
597
+ $templates[] = "author-{$role_slug}.php";
598
+ }
599
+
600
+ // Check for the template.
601
+ $new_template = locate_template( $templates );
602
+
603
+ // If we have a role-based template, let's set it to be loaded.
604
+ if ( '' !== $new_template ) {
605
+ $template = $new_template;
606
+ }
607
+ }
608
+
609
+ return $template;
610
+ }
611
+
612
+ /** Miscellaneous *************************************************************/
613
+
614
+ /**
615
+ * Delete WP generated rewrite rules from database.
616
+ *
617
+ * Rules will be recreated on next page load.
618
+ *
619
+ * @since 0.9.5
620
+ */
621
+ function ba_eas_flush_rewrite_rules() {
622
+ update_option( 'rewrite_rules', '' );
623
+ }
624
+
625
+ /**
626
+ * Filter out unnecessary rewrite rules from the author
627
+ * rules array.
628
+ *
629
+ * @param array $author_rewrite_rules Author rewrite rules.
630
+ *
631
+ * @return array Author rewrite rules.
632
+ */
633
+ function ba_eas_author_rewrite_rules( $author_rewrite_rules ) {
634
+
635
+ if ( ba_eas_do_role_based_author_base() ) {
636
+ // Filter out the rules without the author_name parameter. We don't need them.
637
+ foreach ( $author_rewrite_rules as $rule => $query ) {
638
+ if ( false === strpos( $query, 'author_name' ) ) {
639
+ unset( $author_rewrite_rules[ $rule ] );
640
+ }
641
+ }
642
+ }
643
+
644
+ return $author_rewrite_rules;
645
+ }
646
+
647
+ /**
648
+ * Return the first listed role of a user's role array.
649
+ *
650
+ * @since 1.1.0
651
+ *
652
+ * @param array $roles An array of user roles.
653
+ * @param int $user_id The user id.
654
+ *
655
+ * @return string The user's first listed role.
656
+ */
657
+ function ba_eas_get_user_role( $roles = array(), $user_id = 0 ) {
658
+
659
+ // Set the default role to empty.
660
+ $role = '';
661
+
662
+ // Grab the first listed role.
663
+ if ( ! empty( $roles ) && is_array( $roles ) ) {
664
+ $role = array_shift( $roles );
665
+
666
+ // If no roles were passed, try using the user id to get them.
667
+ } elseif ( ! empty( $user_id ) ) {
668
+
669
+ // Get the WP_User object.
670
+ $user = get_userdata( $user_id );
671
+
672
+ // If the roles aren't empty, grab the first listed role.
673
+ if ( ! empty( $user->roles ) ) {
674
+ $role = array_shift( $user->roles );
675
+ }
676
+ }
677
+
678
+ /**
679
+ * Filters the author role.
680
+ *
681
+ * @since 1.1.0
682
+ *
683
+ * @param string $role The first listed user role.
684
+ * @param int $user_id The user id.
685
+ */
686
+ return apply_filters( 'ba_eas_get_user_role', $role, $user_id );
687
+ }
688
+
689
+ /**
690
+ * Returns the WP_Roles object.
691
+ *
692
+ * WP 4.3 added the `wp_roles()` function to facilitate the instantiation of the
693
+ * WP_Roles object. This is a wrapper function for `wp_roles()` with a fallback
694
+ * for those on WP < 4.3.
695
+ *
696
+ * @global WP_Roles $wp_roles
697
+ *
698
+ * @return WP_Roles
699
+ */
700
+ function ba_eas_get_wp_roles() {
701
+
702
+ if ( function_exists( 'wp_roles' ) ) {
703
+ $wp_roles = wp_roles();
704
+
705
+ } else {
706
+
707
+ global $wp_roles;
708
+
709
+ // Make sure the `$wp_roles` global has been set.
710
+ if ( ! isset( $wp_roles ) ) {
711
+ $wp_roles = new WP_Roles();
712
+ }
713
+ }
714
+
715
+ return $wp_roles;
716
+ }
717
+
718
+ /**
719
+ * Return an array of WP roles.
720
+ *
721
+ * The capabilities array for each role have been removed.
722
+ *
723
+ * @since 1.2.0
724
+ *
725
+ * @global WP_Roles $wp_roles
726
+ *
727
+ * @return array
728
+ */
729
+ function ba_eas_get_roles() {
730
+
731
+ // Get the `WP_Roles` object.
732
+ $wp_roles = ba_eas_get_wp_roles();
733
+
734
+ // Pull out just the roles array.
735
+ $_wp_roles = $wp_roles->roles;
736
+
737
+ // Remove user caps.
738
+ foreach ( $_wp_roles as $role => $details ) {
739
+ unset( $_wp_roles[ $role ]['capabilities'] );
740
+ }
741
+
742
+ return $_wp_roles;
743
+ }
744
+
745
+ /**
746
+ * Fetch a filtered list of user roles that the current user is
747
+ * allowed to edit.
748
+ *
749
+ * Simple function who's main purpose is to allow filtering of the
750
+ * list of roles in the $wp_roles object so that plugins can remove
751
+ * inappropriate ones depending on the situation or user making edits.
752
+ * Specifically because without filtering anyone with the edit_users
753
+ * capability can edit others to be administrators, even if they are
754
+ * only editors or authors. This filter allows admins to delegate
755
+ * user management.
756
+ *
757
+ * @since 1.0.0
758
+ *
759
+ * @global WP_Roles $wp_roles The WP_Roles object.
760
+ *
761
+ * @return array $editable_roles List of editable roles.
762
+ */
763
+ function ba_eas_get_editable_roles() {
764
+
765
+ // Get the `WP_Roles` object.
766
+ $wp_roles = ba_eas_get_wp_roles();
767
+
768
+ $roles = array();
769
+ if ( ! empty( $wp_roles->roles ) ) {
770
+ $roles = $wp_roles->roles;
771
+ }
772
+
773
+ /**
774
+ * Filter the list of editable roles.
775
+ *
776
+ * @since 1.0.0
777
+ *
778
+ * @param array $roles The return of WP_Roles::roles.
779
+ */
780
+ $editable_roles = apply_filters( 'editable_roles', $roles );
781
+
782
+ // Remove user caps.
783
+ if ( ! empty( $editable_roles ) ) {
784
+ foreach ( $editable_roles as $role => $details ) {
785
+ unset( $editable_roles[ $role ]['capabilities'] );
786
+ }
787
+ }
788
+
789
+ return $editable_roles;
790
+ }
791
+
792
+ /**
793
+ * Get an list of default role slugs
794
+ *
795
+ * @since 1.0.2
796
+ *
797
+ * @return array Role slugs array.
798
+ */
799
+ function ba_eas_get_default_role_slugs() {
800
+
801
+ // Get the array of WP roles.
802
+ $roles = ba_eas_get_roles();
803
+
804
+ // Convert role names into role slugs.
805
+ foreach ( $roles as $role => $details ) {
806
+ $roles[ $role ]['slug'] = sanitize_title( translate_user_role( $details['name'] ) );
807
+ }
808
+
809
+ return $roles;
810
+ }
811
+
812
+ if ( ! function_exists( 'array_replace_recursive' ) ) {
813
+ /**
814
+ * Add array_replace_recursive() for users of PHP 5.2.x
815
+ *
816
+ * http://php.net/manual/en/function.array-replace-recursive.php#109390
817
+ *
818
+ * @since 1.0.2
819
+ *
820
+ * @codeCoverageIgnore
821
+ *
822
+ * @param array $base The default array.
823
+ * @param array $replacements The new array.
824
+ *
825
+ * @return array Role slugs array.
826
+ */
827
+ function array_replace_recursive( $base, $replacements ) {
828
+ foreach ( array_slice( func_get_args(), 1 ) as $replacements ) {
829
+ $bref_stack = array( &$base );
830
+ $head_stack = array( $replacements );
831
+
832
+ do {
833
+ end( $bref_stack );
834
+
835
+ $bref = &$bref_stack[ key( $bref_stack ) ];
836
+ $head = array_pop( $head_stack );
837
+
838
+ unset( $bref_stack[ key( $bref_stack ) ] );
839
+
840
+ foreach ( array_keys( $head ) as $key ) {
841
+ if ( isset( $key, $bref, $bref[ $key ] ) && is_array( $bref[ $key ] ) && is_array( $head[ $key ] ) ) {
842
+ $bref_stack[] = &$bref[ $key ];
843
+ $head_stack[] = $head[ $key ];
844
+ } else {
845
+ $bref[ $key ] = $head[ $key ];
846
+ }
847
+ }
848
+ } while ( count( $head_stack ) );
849
+ }
850
+
851
+ return $base;
852
+ }
853
+ } // end function exists check.
854
+
855
+ /**
856
+ * Clean and update the nicename cache.
857
+ *
858
+ * @todo This will no longer be necessary when WP 4.5 is the minimum version.
859
+ * @see https://core.trac.wordpress.org/ticket/35750
860
+ *
861
+ * @since 1.0.0
862
+ *
863
+ * @param int $user_id The user id.
864
+ * @param object $old_user_data The WP_User object.
865
+ * @param string $new_nicename The new user nicename.
866
+ */
867
+ function ba_eas_update_nicename_cache( $user_id = 0, $old_user_data = '', $new_nicename = '' ) {
868
+
869
+ // Bail if there's no user.
870
+ if ( empty( $user_id ) && empty( $old_user_data->ID ) ) {
871
+ return;
872
+ }
873
+
874
+ // Get a user_id. This will probably never happen.
875
+ if ( empty( $user_id ) ) {
876
+ $user_id = $old_user_data->ID;
877
+ }
878
+
879
+ // We got here via `profile_update`.
880
+ if ( empty( $new_nicename ) ) {
881
+
882
+ // Get the new nicename.
883
+ $user = get_userdata( $user_id );
884
+ $new_nicename = $user->user_nicename;
885
+ }
886
+
887
+ // Set the old nicename.
888
+ // Note: This check is only for back-compat. You should pass a WP_User object.
889
+ if ( isset( $old_user_data->user_nicename ) ) {
890
+ $old_nicename = $old_user_data->user_nicename;
891
+ } else {
892
+ _doing_it_wrong( __FUNCTION__, ' The function ba_eas_update_nicename_cache() expects $old_user_data to be a WP_User object.', 'Edit Author Slug 1.0.4' );
893
+ $old_nicename = $old_user_data;
894
+ }
895
+
896
+ // Delete the old nicename from the cache.
897
+ wp_cache_delete( $old_nicename, 'userslugs' );
898
+
899
+ // Add the new nicename to the cache.
900
+ wp_cache_add( $new_nicename, $user_id, 'userslugs' );
901
+ }
includes/hooks.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Edit Author Slug Filters & Actions.
4
+ *
5
+ * @package Edit_Author_Slug
6
+ * @subpackage Hooks
7
+ *
8
+ * @author Brandon Allen
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ defined( 'ABSPATH' ) || exit;
13
+
14
+ // Admin.
15
+ if ( is_admin() ) {
16
+
17
+ // Activation.
18
+ add_action( 'ba_eas_activation', 'ba_eas_install' );
19
+ add_action( 'ba_eas_activation', 'ba_eas_flush_rewrite_rules' );
20
+
21
+ // Deactivation.
22
+ add_action( 'ba_eas_deactivation', 'ba_eas_flush_rewrite_rules' );
23
+
24
+ // Upgrade.
25
+ add_action( 'admin_init', 'ba_eas_upgrade', 999 );
26
+
27
+ // Nicename Actions.
28
+ add_action( 'edit_user_profile', 'ba_eas_show_user_nicename' );
29
+ add_action( 'show_user_profile', 'ba_eas_show_user_nicename' );
30
+ add_action( 'user_profile_update_errors', 'ba_eas_update_user_nicename', 10, 3 );
31
+ add_action( 'admin_enqueue_scripts', 'ba_eas_show_user_nicename_scripts' );
32
+
33
+ // Nicename column filters.
34
+ add_filter( 'manage_users_columns', 'ba_eas_author_slug_column' );
35
+ add_filter( 'manage_users_custom_column', 'ba_eas_author_slug_custom_column', 10, 3 );
36
+
37
+ // Settings.
38
+ add_action( 'admin_menu', 'ba_eas_add_settings_menu' );
39
+ add_action( 'admin_init', 'ba_eas_register_admin_settings' );
40
+ add_filter( 'plugin_action_links', 'ba_eas_add_settings_link', 10, 2 );
41
+
42
+ // Settings updated.
43
+ add_action( 'admin_action_update', 'ba_eas_settings_updated' );
44
+ add_action( 'ba_eas_settings_updated', 'ba_eas_flush_rewrite_rules' );
45
+ }
46
+
47
+ // Nicename auto-update actions.
48
+ add_action( 'profile_update', 'ba_eas_auto_update_user_nicename' );
49
+ add_action( 'user_register', 'ba_eas_auto_update_user_nicename' );
50
+
51
+ // Author permalink filtering for role-based author bases.
52
+ add_filter( 'author_link', 'ba_eas_author_link', 20, 2 );
53
+
54
+ // Filter author rewrite rules.
55
+ add_filter( 'author_rewrite_rules', 'ba_eas_author_rewrite_rules' );
56
+
57
+ // Add role-based author templates.
58
+ add_filter( 'author_template', 'ba_eas_template_include' );
includes/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
js/edit-author-slug.js ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( document ).ready(function( $ ) {
2
+
3
+ // Front show/hide.
4
+ if ( $( 'input[name="_ba_eas_remove_front"]' ).prop( 'checked' ) ) {
5
+ $( 'span[class="eas-demo-author-base-front"]' ).addClass( 'hidden' );
6
+ }
7
+
8
+ // Watch for clicks on the `_ba_eas_remove_front` checkbox.
9
+ $( 'input[name="_ba_eas_remove_front"]' ).on( 'click', function() {
10
+ if ( $( this ).prop( 'checked' ) ) {
11
+ $( 'span[class="eas-demo-author-base-front"]' ).fadeOut( 'fast', function() {
12
+ $( this ).addClass( 'hidden' );
13
+ });
14
+ } else {
15
+ $( 'span[class="eas-demo-author-base-front hidden"]' ).fadeIn( 'slow', function() {
16
+ $( this ).removeClass( 'hidden' );
17
+ });
18
+ }
19
+ });
20
+
21
+ // Make example nicenames clickable.
22
+ $( 'input[name="ba_eas_author_slug"]' ).click(function() {
23
+ if ( 'ba_eas_author_slug_custom_radio' !== $( this ).attr( 'id' ) ) {
24
+ $( 'input[name="ba_eas_author_slug_custom"]' ).val( $( this ).val() ).text( $( this ).siblings( 'span' ).text() );
25
+ }
26
+ });
27
+
28
+ // If focus moves to the custom author slug input, select the radio.
29
+ $( 'input[name="ba_eas_author_slug_custom"]' ).focus(function() {
30
+ $( '#ba_eas_author_slug_custom_radio' ).attr( 'checked', 'checked' );
31
+ });
32
+
33
+ // Hide the related fields if `eas-checkbox` is not checked.
34
+ $( 'input[class="eas-checkbox"]' ).not( ':checked' ).parents( 'tr' ).next( 'tr' ).addClass( 'hidden' );
35
+
36
+ // Watch for clicks on the `eas-checkbox` options.
37
+ $( 'input[class="eas-checkbox"]' ).on( 'click', function() {
38
+ if ( $( this ).prop( 'checked' ) ) {
39
+ $( this ).parents( 'tr' ).next( 'tr' ).fadeIn( 'slow', function() {
40
+ $( this ).removeClass( 'hidden' );
41
+ });
42
+ } else {
43
+ $( this ).parents( 'tr' ).next( 'tr' ).fadeOut( 'fast', function() {
44
+ $( this ).addClass( 'hidden' );
45
+ });
46
+ }
47
+ });
48
+ });
js/edit-author-slug.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+ /*! edit-author-slug - v1.3.0 - 2017-01-25 6:16:50 AM UTC - https://github.com/thebrandonallen/edit-author-slug/ */
2
+ jQuery(document).ready(function(a){a('input[name="_ba_eas_remove_front"]').prop("checked")&&a('span[class="eas-demo-author-base-front"]').addClass("hidden"),a('input[name="_ba_eas_remove_front"]').on("click",function(){a(this).prop("checked")?a('span[class="eas-demo-author-base-front"]').fadeOut("fast",function(){a(this).addClass("hidden")}):a('span[class="eas-demo-author-base-front hidden"]').fadeIn("slow",function(){a(this).removeClass("hidden")})}),a('input[name="ba_eas_author_slug"]').click(function(){"ba_eas_author_slug_custom_radio"!==a(this).attr("id")&&a('input[name="ba_eas_author_slug_custom"]').val(a(this).val()).text(a(this).siblings("span").text())}),a('input[name="ba_eas_author_slug_custom"]').focus(function(){a("#ba_eas_author_slug_custom_radio").attr("checked","checked")}),a('input[class="eas-checkbox"]').not(":checked").parents("tr").next("tr").addClass("hidden"),a('input[class="eas-checkbox"]').on("click",function(){a(this).prop("checked")?a(this).parents("tr").next("tr").fadeIn("slow",function(){a(this).removeClass("hidden")}):a(this).parents("tr").next("tr").fadeOut("fast",function(){a(this).addClass("hidden")})})});
languages/edit-author-slug.pot ADDED
@@ -0,0 +1,234 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Copyright (C) 2009-2017 Brandon Allen
2
+ # This file is distributed under the same license as the Edit Author Slug package.
3
+ # Submit translations to https://translate.wordpress.org/projects/wp-plugins/edit-author-slug.
4
+ msgid ""
5
+ msgstr ""
6
+ "Project-Id-Version: Edit Author Slug 1.3.0\n"
7
+ "Report-Msgid-Bugs-To: "
8
+ "https://github.com/thebrandonallen/edit-author-slug/issues\n"
9
+ "POT-Creation-Date: 2017-01-25 06:16:50+00:00\n"
10
+ "MIME-Version: 1.0\n"
11
+ "Content-Type: text/plain; charset=utf-8\n"
12
+ "Content-Transfer-Encoding: 8bit\n"
13
+ "PO-Revision-Date: 2017-MO-DA HO:MI+ZONE\n"
14
+ "Last-Translator: BRANDON ALLEN <plugins@brandonallen.me>\n"
15
+ "Language-Team: ENGLISH <plugins@brandonallen.me>\n"
16
+ "X-Generator: grunt-wp-i18n 0.5.4\n"
17
+ "X-Poedit-KeywordsList: "
18
+ "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
19
+ "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
20
+ "Language: en\n"
21
+ "Plural-Forms: nplurals=2; plural=(n != 1);\n"
22
+ "X-Poedit-Country: United States\n"
23
+ "X-Poedit-SourceCharset: UTF-8\n"
24
+ "X-Poedit-Basepath: ../\n"
25
+ "X-Poedit-SearchPath-0: .\n"
26
+ "X-Poedit-Bookmarks: \n"
27
+ "X-Textdomain-Support: yes\n"
28
+
29
+ #: edit-author-slug.php:234
30
+ msgid "Method does not exist."
31
+ msgstr ""
32
+
33
+ #: edit-author-slug.php:253 edit-author-slug.php:266
34
+ msgid "Cheatin&#8217; huh?"
35
+ msgstr ""
36
+
37
+ #: includes/admin.php:82
38
+ msgid ""
39
+ "Choose an Author Slug based on the above profile information, or create "
40
+ "your own."
41
+ msgstr ""
42
+
43
+ #: includes/admin.php:82
44
+ msgid "ie. - 'user-name', 'firstname-lastname', or 'master-ninja'"
45
+ msgstr ""
46
+
47
+ #: includes/admin.php:85 includes/admin.php:87 includes/admin.php:315
48
+ msgid "Author Slug"
49
+ msgstr ""
50
+
51
+ #: includes/admin.php:105
52
+ msgid "Custom:"
53
+ msgstr ""
54
+
55
+ #: includes/admin.php:106
56
+ msgid "Enter a custom author slug in the following field"
57
+ msgstr ""
58
+
59
+ #: includes/admin.php:108
60
+ msgid "Custom author slug:"
61
+ msgstr ""
62
+
63
+ #: includes/admin.php:175
64
+ msgid "<strong>ERROR</strong>: An author slug cannot be blank. Please try again."
65
+ msgstr ""
66
+
67
+ #: includes/admin.php:220
68
+ msgid ""
69
+ "<strong>ERROR</strong>: An author slug can only contain alphanumeric "
70
+ "characters, underscores (_) and dashes (-)."
71
+ msgstr ""
72
+
73
+ #: includes/admin.php:229
74
+ msgid ""
75
+ "<strong>ERROR</strong>: That author slug appears to be invalid. Please try "
76
+ "something different."
77
+ msgstr ""
78
+
79
+ #: includes/admin.php:238
80
+ msgid "<strong>ERROR</strong>: An author slug may not be longer than 50 characters."
81
+ msgstr ""
82
+
83
+ #: includes/admin.php:251
84
+ msgid ""
85
+ "<strong>ERROR</strong>: The author slug, %1$s, already exists. Please try "
86
+ "something different."
87
+ msgstr ""
88
+
89
+ #: includes/admin.php:397 includes/admin.php:415
90
+ msgid "Edit Author Slug Settings"
91
+ msgstr ""
92
+
93
+ #: includes/admin.php:439 includes/admin.php:447
94
+ msgid "Author Base"
95
+ msgstr ""
96
+
97
+ #: includes/admin.php:459
98
+ msgid "Remove Front"
99
+ msgstr ""
100
+
101
+ #: includes/admin.php:471
102
+ msgid "Role-Based Author Base"
103
+ msgstr ""
104
+
105
+ #: includes/admin.php:482
106
+ msgid "Role Slugs"
107
+ msgstr ""
108
+
109
+ #: includes/admin.php:492
110
+ msgid "Automatic Author Slug Creation"
111
+ msgstr ""
112
+
113
+ #: includes/admin.php:500
114
+ msgid "Automatically Update"
115
+ msgstr ""
116
+
117
+ #: includes/admin.php:511 includes/admin.php:541
118
+ msgid "Author Slug Structure"
119
+ msgstr ""
120
+
121
+ #: includes/admin.php:522
122
+ msgid "Bulk Update Author Slugs"
123
+ msgstr ""
124
+
125
+ #: includes/admin.php:530
126
+ msgid "Bulk Update"
127
+ msgstr ""
128
+
129
+ #: includes/admin.php:558
130
+ msgid "Change your author base to something more fun!"
131
+ msgstr ""
132
+
133
+ #: includes/admin.php:571
134
+ msgid ""
135
+ "Allow Author Slugs to be automatically updated, and set the default Author "
136
+ "Slug structure for users. Automatic updating will only occur when a user "
137
+ "can't edit Author Slugs on their own."
138
+ msgstr ""
139
+
140
+ #: includes/admin.php:571
141
+ msgid ""
142
+ "This could have SEO repercussions if users update their profiles "
143
+ "frequently, and it will override any manual editing of the Author Slug you "
144
+ "may have previously completed."
145
+ msgstr ""
146
+
147
+ #: includes/admin.php:593
148
+ msgid "Defaults to 'author'"
149
+ msgstr ""
150
+
151
+ #: includes/admin.php:611
152
+ msgid "Remove the \"front\" portion of the author permalink structure."
153
+ msgstr ""
154
+
155
+ #: includes/admin.php:625
156
+ msgid "Set user's Author Base according to their role."
157
+ msgstr ""
158
+
159
+ #: includes/admin.php:628
160
+ msgid ""
161
+ "Use the %1$s rewrite tag to customize the role-based author base. If you "
162
+ "set the author base to \"%2$s\", the resulting author structure will be "
163
+ "something like \"%3$s\"."
164
+ msgstr ""
165
+
166
+ #: includes/admin.php:741
167
+ msgid "Automatically update Author Slug when a user updates their profile."
168
+ msgstr ""
169
+
170
+ #: includes/admin.php:765
171
+ msgid "Default author slug options"
172
+ msgstr ""
173
+
174
+ #: includes/admin.php:785
175
+ msgid "Update all users at once based on the specified Author Slug structure."
176
+ msgstr ""
177
+
178
+ #: includes/admin.php:801
179
+ msgid ""
180
+ "Update all users according to the below Author Slug setting. This will only "
181
+ "be run after clicking \"Save Changes\"."
182
+ msgstr ""
183
+
184
+ #: includes/admin.php:825
185
+ msgid "Default bulk update author slug options"
186
+ msgstr ""
187
+
188
+ #: includes/admin.php:848
189
+ msgid "Settings"
190
+ msgstr ""
191
+
192
+ #: includes/admin.php:873 tests/test-admin.php:551
193
+ msgid "username (Default)"
194
+ msgstr ""
195
+
196
+ #: includes/admin.php:874 tests/test-admin.php:552
197
+ msgid "nickname"
198
+ msgstr ""
199
+
200
+ #: includes/admin.php:875 tests/test-admin.php:553
201
+ msgid "displayname"
202
+ msgstr ""
203
+
204
+ #: includes/admin.php:876 tests/test-admin.php:554
205
+ msgid "firstname"
206
+ msgstr ""
207
+
208
+ #: includes/admin.php:877 tests/test-admin.php:555
209
+ msgid "lastname"
210
+ msgstr ""
211
+
212
+ #: includes/admin.php:878 tests/test-admin.php:556
213
+ msgid "firstname-lastname"
214
+ msgstr ""
215
+
216
+ #: includes/admin.php:879 tests/test-admin.php:557
217
+ msgid "lastname-firstname"
218
+ msgstr ""
219
+
220
+ #: includes/admin.php:880 tests/test-admin.php:558
221
+ msgid "userid (Experimental)"
222
+ msgstr ""
223
+
224
+ #: includes/functions.php:285
225
+ msgid "%d user author slug(s) updated."
226
+ msgstr ""
227
+
228
+ #. Description of the plugin/theme
229
+ msgid ""
230
+ "Allows an Admin (or capable user) to edit the author slug of a user, and "
231
+ "change the Author Base. <em>i.e. - (WordPress default structure) "
232
+ "http://example.com/author/username/ (Plugin allows) "
233
+ "http://example.com/ninja/master-ninja/</em>"
234
+ msgstr ""
languages/index.php ADDED
@@ -0,0 +1,2 @@
 
 
1
+ <?php
2
+ // Silence is golden.
readme.md ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Edit Author Slug [![Build Status](https://travis-ci.org/thebrandonallen/edit-author-slug.svg?branch=master)](https://travis-ci.org/thebrandonallen/edit-author-slug) #
2
+ **Contributors:** [thebrandonallen](https://profiles.wordpress.org/thebrandonallen)
3
+ **Tags:** author, author base, author slug, user nicename, nicename, permalink, permalinks, slug, users, user, role, roles
4
+ **Requires at least:** 4.3
5
+ **Tested up to:** 4.7.1
6
+ **Stable tag:** 1.3.0
7
+ **License:** GPLv2 or later
8
+ **License URI:** http://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ Allows an admin (or capable user) to edit the author slug of a user, and change the author base.
11
+
12
+ ## Description ##
13
+
14
+ This plugin allows full control of your user permalinks, allowing you to change both the author base (the '/author/' portion of the author URLs), and the author slug (defaults to the username of the author). You can set the author base globally, or you can set it to be user-specific based on a user's role. You now have the power to craft the perfect URL structure for you Author pages.
15
+
16
+ WordPress default structure *http://example.com/author/username/*.
17
+
18
+ Edit Author Slug allows for *http://example.com/ninja/master-ninja/*.
19
+
20
+ Using a role-based author base would allow for *http://example.com/ida/master-splinter/* (for an Administrator Role), or *http://example.com/koga/leonardo/* (for a Subscriber Role).
21
+
22
+ Development of this plugin takes place on [GitHub](https://github.com/thebrandonallen/edit-author-slug/ "Edit Author Slug on Github"). Pull requests are always welcome!
23
+
24
+ Translations should be submitted to [Translate WordPress](https://translate.wordpress.org/projects/wp-plugins/edit-author-slug).
25
+
26
+ ## Installation ##
27
+
28
+ 1. Upload `edit-author-slug` folder to your WordPress plugins directory (typically 'wp-content/plugins')
29
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
30
+ 3. Go to Users > Your Profile, or Users > All Users > (username), and edit the author slug.
31
+ 4. Click "Update Profile" or "Update User"
32
+ 5. Go to Settings > Edit Author Slug to edit settings
33
+ 6. Click "Save Changes"
34
+
35
+ ## Screenshots ##
36
+
37
+ 1. Settings
38
+ 2. Individual user author slug
39
+
40
+ ## Frequently Asked Questions ##
41
+
42
+ ### Why can't I edit my Author Slug? ###
43
+
44
+ Make sure you are an admin, or have been assigned the `edit_users` capability.
45
+
46
+ ### Why isn't my new Author Slug working? ###
47
+
48
+ While I've made every attempt to prevent this, I may have missed a spot or two. First things first, go to Settings > Permalinks and click "Save Changes." You don't need to actually need to make any changes for this to work. Hopefully, this should kick your new Author Slug into gear.
49
+
50
+ If this doesn't work, make sure you don't have any slug conflicts from other posts/pages/plugins/permalink setting/etc. If you're still experiencing the issue, feel free to post a support request in the forums.
51
+
52
+ ## Changelog ##
53
+
54
+ ### 1.3.0 ###
55
+ * Fix a potential bug where a sanitized author base could end up with double forward slashes.
56
+ * Introduce the `%ba_eas_author_role%` permalink structure tag. This can be used to customize role-based author bases.
57
+ * Bonus: All alternative facts are now free!
58
+
59
+ ### 1.2.1 ###
60
+ * Fixed stupid error where the default user nicename wasn't being properly retrieved from the database. Sorry about that :(
61
+ * Unfortunately, some unicorns were lost during the development of this release, but they are a resilient creature.
62
+
63
+ ### 1.2.0 ###
64
+ * Added the ability to use forward slashes in the author base.
65
+ * Improved display on the settings page, and storing, of role slugs.
66
+ * Packaged translations are now removed. Anyone interested in translating the plugin should do so at [Translate WordPress](https://translate.wordpress.org/projects/wp-plugins/edit-author-slug).
67
+ * EXPERIMENTAL: Added the ability to set the author slug to a user's numeric user id. While I have tested this, I can't be sure that no one's site will implode. If all goes well, the experimental tag will be removed in the next major release (or two).
68
+ * Added ability to remove the front portion of author links.
69
+ * Accessibility improvements to the settings page.
70
+
71
+ ### 1.1.2 ###
72
+ * Fix loading of minified JS in the admin. Props nuyensgert.
73
+
74
+ ### 1.1.1 ###
75
+ * Fix a few minor output escaping issues missed in the 1.1.0 release.
76
+
77
+ ### 1.1.0 ###
78
+ * Added the ability to update all author slugs at once with the "Bulk Update" tool.
79
+ * Greatly improved the checks and error messages when manually updating an author slug for a user.
80
+ * Further accessibility improvements to match WP 4.3.
81
+ * Improved validation of author slugs to better match that of WP.
82
+
83
+ ### 1.0.6 ###
84
+ * Fix potential, although unlikely, persistent XSS vulnerability.
85
+ * Prevent debug notice in admin. Props chesio.
86
+ * Update heading tags to h1 to match WP 4.3.
87
+
88
+ ### 1.0.5.1 ###
89
+ * Identical to 1.0.5, which failed to commit properly.
90
+
91
+ ### 1.0.5 ###
92
+ * Add WP_User object as a parameter passed to the `ba_eas_show_user_nicename_options_list` filter
93
+ * Add Japanese translation files. Props SmokyJp.
94
+ * Fixed possible (although unlikely) cache invalidation issue
95
+ * Minor code improvements and optimizations.
96
+
97
+ ### 1.0.4 ###
98
+ * Improve upgrade routine for older installs
99
+ * Improve output escaping
100
+ * Various minor fixes and improvements
101
+
102
+ ### 1.0.3 ###
103
+ I swear I tested this! :(
104
+
105
+ * Fix custom roles slugs not saving
106
+
107
+ ### 1.0.2 ###
108
+ * A number of localization fixes and improvements
109
+ * Role slug improvements
110
+ * Temporary, semi work-around for Co-Authors Plus [https://github.com/Automattic/Co-Authors-Plus/pull/204]
111
+
112
+ ### 1.0.1 ###
113
+ * Fix possible syntax error when updating a profile (props Christine https://wordpress.org/support/topic/undefined-property-error-1)
114
+
115
+ ### 1.0 ###
116
+ * Added ability to do role-based author bases
117
+ * Added ability to use role-based author templates
118
+ * Moderate code refactoring
119
+ * Various code fixes and improvements
120
+ * Add "nickname" as option for auto-update
121
+ * First pass at unit test (only checks if the plugin is installed, for now)
122
+
123
+ ### 0.9.6 ###
124
+ * Fixed loading of translation files. Looks in wp-content/plugins/edit-author-slug/languages. If you're running 3.7+ (and you are... aren't you?), it will fall back to wp-content/languages/plugins if a proper localization can't be found in the edit-author-slug folder.
125
+
126
+ ### 0.9.5 ###
127
+ * Fixed instances where the Author Base wouldn't change, or would result in a 404
128
+
129
+ ### 0.9.4 ###
130
+ * Update readme references to plugin settings
131
+ * Fix some copy pasta in settings
132
+ * Update screenshots
133
+
134
+ ### 0.9.3 ###
135
+ * Quickly caught a few things I missed, so this release was skipped. See 0.9.4 for changes
136
+
137
+ ### 0.9.2 ###
138
+ * Fix issue where any profile information other than the Author Slug could not be updated
139
+ * Minor code improvement
140
+
141
+ ### 0.9.1 ###
142
+ * Add 'Settings' link to plugins list table
143
+
144
+ ### 0.9 ###
145
+ * Allow Author Slug to be automatically created/updated based on a defined structure
146
+ * Switched to using the Settings API, which also means that all options moved to the Settings > Edit Author Slug page
147
+ * Various code improvements/optimizations
148
+
149
+ ### 0.8.1 ###
150
+ * Fix a bug that prevented non-admin users from updating their profile
151
+
152
+ ### 0.8 ###
153
+ * Drastically improved error handling and feedback for author slug editing.
154
+ * Restore duplicate author slug check as old method could alter the slug without any sort of warning.
155
+ * Further improve the logic for flushing rewrite rules.
156
+ * Introduce ba_eas_can_edit_author_slug() and matching filter to make it even easier to give users the ability to update their own author slug.
157
+ * Add message in plugins list warning users of WP less than 3.2 that 0.8 is the last update they'll receive.
158
+
159
+ ### 0.7.2 ###
160
+ * Remove overzealous cap check.
161
+
162
+ ### 0.7.1 ###
163
+ * Fix some unfortunate errors I missed before tagging 0.7.
164
+
165
+ ### 0.7 ###
166
+ * Significant code refactoring.
167
+ * Added custom capability to give site admins the ability to add author slug access to other roles.
168
+ * Improvements/optimizations to code logic.
169
+ * Fixed an incorrect textdomain string.
170
+ * Removed filter added in 0.6 as it was messy. It's much easier to achieve the same result without the plugin.
171
+ * Got rid of wp_die() statement on duplicate author slugs in favor of WP's built-in duplicate author slug method.
172
+
173
+ ### 0.6.1 ###
174
+ * Added Dutch translation - props Juliette Reinders Folmer.
175
+ * Don't hard code the languages folder path.
176
+ * Improve class check/initialization.
177
+
178
+ ### 0.6 ###
179
+ * Some code cleanup.
180
+ * More security hardening.
181
+ * Added filter to allow for the complete removal of the Author Base (http://brandonallen.org/2010/11/03/how-to-remove-the-author-base-with-edit-author-slug/).
182
+ * Flush rewrite rules only when necessary instead of every page load.
183
+
184
+ ### 0.5 ###
185
+ * Added 'Author Slug' column to Users > Authors & Users (Users > Users in 3.0) page (props Yonat Sharon for the jumpstart).
186
+ * Ended support for the WP 2.8 branch. Most likely still works, but I will not support it.
187
+ * Various bug fixes.
188
+
189
+ ### 0.4 ###
190
+ * Added ability to change the Author Base.
191
+ * Updated documentation.
192
+ * Added some extra security via WP esc_* functions.
193
+ * Added Belorussian translation, props Marcis G.
194
+
195
+ ### 0.3.1 ###
196
+ * Added Hebrew Translation, props Yonat Sharon.
197
+
198
+ ### 0.3 ###
199
+ * Now localization friendly.
200
+
201
+ ### 0.2.1 ###
202
+ * Fixed a bug that prevented updating a user if the author slug did not change.
203
+
204
+ ### 0.2 ###
205
+ * Added a check to avoid duplicate slugs.
206
+ * Properly sanitize slug before comparison and database insertion.
207
+ * Updated plugin URI.
208
+
209
+ ### 0.1.4 ###
210
+ * Update tags to reflect WordPress 2.9.1 compatability.
211
+ * Update link to plugin homepage.
212
+
213
+ ### 0.1.3 ###
214
+ * Update tags to reflect WordPress 2.9 compatability.
215
+
216
+ ### 0.1.2 ###
217
+ * Fix version number issues.
218
+
219
+ ### 0.1.1 ###
220
+ * Remove extra debug functions left behind.
221
+ * Add screenshot.
222
+
223
+ ### 0.1 ###
224
+ * Initial release.
225
+
226
+ ## Upgrade Notice ##
227
+
228
+ ### 1.0 ###
229
+ Role-based author bases are here!
230
+
231
+ ### 0.4 ###
232
+ Adds ability to change the Author Base (not a required upgrade)
233
+
234
+ ### 0.3 ###
235
+ Edit Author Slug can now be localized. You can find edit-author-slug.pot in 'edit-author-slug/languages' to get you started.
236
+
237
+ ### 0.2 ###
238
+ Added a check to avoid duplicate duplicate author slugs, and better sanitization.
239
+
240
+ ### TODO ###
241
+ * Allow Author Slug editing of users from one centralized location
readme.txt ADDED
@@ -0,0 +1,241 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ === Edit Author Slug ===
2
+ Contributors: thebrandonallen
3
+ Tags: author, author base, author slug, user nicename, nicename, permalink, permalinks, slug, users, user, role, roles
4
+ Requires at least: 4.3
5
+ Tested up to: 4.7.1
6
+ Stable tag: 1.3.0
7
+ License: GPLv2 or later
8
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+
10
+ Allows an admin (or capable user) to edit the author slug of a user, and change the author base.
11
+
12
+ == Description ==
13
+
14
+ This plugin allows full control of your user permalinks, allowing you to change both the author base (the '/author/' portion of the author URLs), and the author slug (defaults to the username of the author). You can set the author base globally, or you can set it to be user-specific based on a user's role. You now have the power to craft the perfect URL structure for you Author pages.
15
+
16
+ WordPress default structure *http://example.com/author/username/*.
17
+
18
+ Edit Author Slug allows for *http://example.com/ninja/master-ninja/*.
19
+
20
+ Using a role-based author base would allow for *http://example.com/ida/master-splinter/* (for an Administrator Role), or *http://example.com/koga/leonardo/* (for a Subscriber Role).
21
+
22
+ Development of this plugin takes place on [GitHub](https://github.com/thebrandonallen/edit-author-slug/ "Edit Author Slug on Github"). Pull requests are always welcome!
23
+
24
+ Translations should be submitted to [Translate WordPress](https://translate.wordpress.org/projects/wp-plugins/edit-author-slug).
25
+
26
+ == Installation ==
27
+
28
+ 1. Upload `edit-author-slug` folder to your WordPress plugins directory (typically 'wp-content/plugins')
29
+ 2. Activate the plugin through the 'Plugins' menu in WordPress
30
+ 3. Go to Users > Your Profile, or Users > All Users > (username), and edit the author slug.
31
+ 4. Click "Update Profile" or "Update User"
32
+ 5. Go to Settings > Edit Author Slug to edit settings
33
+ 6. Click "Save Changes"
34
+
35
+ == Screenshots ==
36
+
37
+ 1. Settings
38
+ 2. Individual user author slug
39
+
40
+ == Frequently Asked Questions ==
41
+
42
+ = Why can't I edit my Author Slug? =
43
+
44
+ Make sure you are an admin, or have been assigned the `edit_users` capability.
45
+
46
+ = Why isn't my new Author Slug working? =
47
+
48
+ While I've made every attempt to prevent this, I may have missed a spot or two. First things first, go to Settings > Permalinks and click "Save Changes." You don't need to actually need to make any changes for this to work. Hopefully, this should kick your new Author Slug into gear.
49
+
50
+ If this doesn't work, make sure you don't have any slug conflicts from other posts/pages/plugins/permalink setting/etc. If you're still experiencing the issue, feel free to post a support request in the forums.
51
+
52
+ == Changelog ==
53
+
54
+ = 1.3.0 =
55
+ * Fix a potential bug where a sanitized author base could end up with double forward slashes.
56
+ * Introduce the `%ba_eas_author_role%` permalink structure tag. This can be used to customize role-based author bases.
57
+ * Bonus: All alternative facts are now free!
58
+
59
+ = 1.2.1 =
60
+ * Fixed stupid error where the default user nicename wasn't being properly retrieved from the database. Sorry about that :(
61
+ * Unfortunately, some unicorns were lost during the development of this release, but they are a resilient creature.
62
+
63
+ = 1.2.0 =
64
+ * Added the ability to use forward slashes in the author base.
65
+ * Improved display on the settings page, and storing, of role slugs.
66
+ * Packaged translations are now removed. Anyone interested in translating the plugin should do so at [Translate WordPress](https://translate.wordpress.org/projects/wp-plugins/edit-author-slug).
67
+ * EXPERIMENTAL: Added the ability to set the author slug to a user's numeric user id. While I have tested this, I can't be sure that no one's site will implode. If all goes well, the experimental tag will be removed in the next major release (or two).
68
+ * Added ability to remove the front portion of author links.
69
+ * Accessibility improvements to the settings page.
70
+
71
+ = 1.1.2 =
72
+ * Fix loading of minified JS in the admin. Props nuyensgert.
73
+
74
+ = 1.1.1 =
75
+ * Fix a few minor output escaping issues missed in the 1.1.0 release.
76
+
77
+ = 1.1.0 =
78
+ * Added the ability to update all author slugs at once with the "Bulk Update" tool.
79
+ * Greatly improved the checks and error messages when manually updating an author slug for a user.
80
+ * Further accessibility improvements to match WP 4.3.
81
+ * Improved validation of author slugs to better match that of WP.
82
+
83
+ = 1.0.6 =
84
+ * Fix potential, although unlikely, persistent XSS vulnerability.
85
+ * Prevent debug notice in admin. Props chesio.
86
+ * Update heading tags to h1 to match WP 4.3.
87
+
88
+ = 1.0.5.1 =
89
+ * Identical to 1.0.5, which failed to commit properly.
90
+
91
+ = 1.0.5 =
92
+ * Add WP_User object as a parameter passed to the `ba_eas_show_user_nicename_options_list` filter
93
+ * Add Japanese translation files. Props SmokyJp.
94
+ * Fixed possible (although unlikely) cache invalidation issue
95
+ * Minor code improvements and optimizations.
96
+
97
+ = 1.0.4 =
98
+ * Improve upgrade routine for older installs
99
+ * Improve output escaping
100
+ * Various minor fixes and improvements
101
+
102
+ = 1.0.3 =
103
+ I swear I tested this! :(
104
+
105
+ * Fix custom roles slugs not saving
106
+
107
+ = 1.0.2 =
108
+ * A number of localization fixes and improvements
109
+ * Role slug improvements
110
+ * Temporary, semi work-around for Co-Authors Plus [https://github.com/Automattic/Co-Authors-Plus/pull/204]
111
+
112
+ = 1.0.1 =
113
+ * Fix possible syntax error when updating a profile (props Christine https://wordpress.org/support/topic/undefined-property-error-1)
114
+
115
+ = 1.0 =
116
+ * Added ability to do role-based author bases
117
+ * Added ability to use role-based author templates
118
+ * Moderate code refactoring
119
+ * Various code fixes and improvements
120
+ * Add "nickname" as option for auto-update
121
+ * First pass at unit test (only checks if the plugin is installed, for now)
122
+
123
+ = 0.9.6 =
124
+ * Fixed loading of translation files. Looks in wp-content/plugins/edit-author-slug/languages. If you're running 3.7+ (and you are... aren't you?), it will fall back to wp-content/languages/plugins if a proper localization can't be found in the edit-author-slug folder.
125
+
126
+ = 0.9.5 =
127
+ * Fixed instances where the Author Base wouldn't change, or would result in a 404
128
+
129
+ = 0.9.4 =
130
+ * Update readme references to plugin settings
131
+ * Fix some copy pasta in settings
132
+ * Update screenshots
133
+
134
+ = 0.9.3 =
135
+ * Quickly caught a few things I missed, so this release was skipped. See 0.9.4 for changes
136
+
137
+ = 0.9.2 =
138
+ * Fix issue where any profile information other than the Author Slug could not be updated
139
+ * Minor code improvement
140
+
141
+ = 0.9.1 =
142
+ * Add 'Settings' link to plugins list table
143
+
144
+ = 0.9 =
145
+ * Allow Author Slug to be automatically created/updated based on a defined structure
146
+ * Switched to using the Settings API, which also means that all options moved to the Settings > Edit Author Slug page
147
+ * Various code improvements/optimizations
148
+
149
+ = 0.8.1 =
150
+ * Fix a bug that prevented non-admin users from updating their profile
151
+
152
+ = 0.8 =
153
+ * Drastically improved error handling and feedback for author slug editing.
154
+ * Restore duplicate author slug check as old method could alter the slug without any sort of warning.
155
+ * Further improve the logic for flushing rewrite rules.
156
+ * Introduce ba_eas_can_edit_author_slug() and matching filter to make it even easier to give users the ability to update their own author slug.
157
+ * Add message in plugins list warning users of WP less than 3.2 that 0.8 is the last update they'll receive.
158
+
159
+ = 0.7.2 =
160
+ * Remove overzealous cap check.
161
+
162
+ = 0.7.1 =
163
+ * Fix some unfortunate errors I missed before tagging 0.7.
164
+
165
+ = 0.7 =
166
+ * Significant code refactoring.
167
+ * Added custom capability to give site admins the ability to add author slug access to other roles.
168
+ * Improvements/optimizations to code logic.
169
+ * Fixed an incorrect textdomain string.
170
+ * Removed filter added in 0.6 as it was messy. It's much easier to achieve the same result without the plugin.
171
+ * Got rid of wp_die() statement on duplicate author slugs in favor of WP's built-in duplicate author slug method.
172
+
173
+ = 0.6.1 =
174
+ * Added Dutch translation - props Juliette Reinders Folmer.
175
+ * Don't hard code the languages folder path.
176
+ * Improve class check/initialization.
177
+
178
+ = 0.6 =
179
+ * Some code cleanup.
180
+ * More security hardening.
181
+ * Added filter to allow for the complete removal of the Author Base (http://brandonallen.org/2010/11/03/how-to-remove-the-author-base-with-edit-author-slug/).
182
+ * Flush rewrite rules only when necessary instead of every page load.
183
+
184
+ = 0.5 =
185
+ * Added 'Author Slug' column to Users > Authors & Users (Users > Users in 3.0) page (props Yonat Sharon for the jumpstart).
186
+ * Ended support for the WP 2.8 branch. Most likely still works, but I will not support it.
187
+ * Various bug fixes.
188
+
189
+ = 0.4 =
190
+ * Added ability to change the Author Base.
191
+ * Updated documentation.
192
+ * Added some extra security via WP esc_* functions.
193
+ * Added Belorussian translation, props Marcis G.
194
+
195
+ = 0.3.1 =
196
+ * Added Hebrew Translation, props Yonat Sharon.
197
+
198
+ = 0.3 =
199
+ * Now localization friendly.
200
+
201
+ = 0.2.1 =
202
+ * Fixed a bug that prevented updating a user if the author slug did not change.
203
+
204
+ = 0.2 =
205
+ * Added a check to avoid duplicate slugs.
206
+ * Properly sanitize slug before comparison and database insertion.
207
+ * Updated plugin URI.
208
+
209
+ = 0.1.4 =
210
+ * Update tags to reflect WordPress 2.9.1 compatability.
211
+ * Update link to plugin homepage.
212
+
213
+ = 0.1.3 =
214
+ * Update tags to reflect WordPress 2.9 compatability.
215
+
216
+ = 0.1.2 =
217
+ * Fix version number issues.
218
+
219
+ = 0.1.1 =
220
+ * Remove extra debug functions left behind.
221
+ * Add screenshot.
222
+
223
+ = 0.1 =
224
+ * Initial release.
225
+
226
+ == Upgrade Notice ==
227
+
228
+ = 1.0 =
229
+ Role-based author bases are here!
230
+
231
+ = 0.4 =
232
+ Adds ability to change the Author Base (not a required upgrade)
233
+
234
+ = 0.3 =
235
+ Edit Author Slug can now be localized. You can find edit-author-slug.pot in 'edit-author-slug/languages' to get you started.
236
+
237
+ = 0.2 =
238
+ Added a check to avoid duplicate duplicate author slugs, and better sanitization.
239
+
240
+ = TODO =
241
+ * Allow Author Slug editing of users from one centralized location
uninstall.php ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Edit Author Slug Uninstall Functions.
4
+ *
5
+ * @package Edit_Author_Slug
6
+ * @subpackage Uninstall
7
+ *
8
+ * @author Brandon Allen
9
+ */
10
+
11
+ // Exit if accessed directly.
12
+ defined( 'ABSPATH' ) || exit;
13
+
14
+ // Make sure we're uninstalling.
15
+ if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
16
+ exit();
17
+ }
18
+
19
+ // Delete all the options.
20
+ delete_option( 'ba_edit_author_slug' );
21
+ delete_option( '_ba_eas_author_base' );
22
+ delete_option( '_ba_eas_db_version' );
23
+ delete_option( '_ba_eas_default_user_nicename' );
24
+ delete_option( '_ba_eas_do_auto_update' );
25
+ delete_option( '_ba_eas_do_role_based' );
26
+ delete_option( '_ba_eas_old_options' );
27
+ delete_option( '_ba_eas_role_slugs' );
28
+ delete_option( '_ba_eas_remove_front' );
29
+
30
+ // Final flush for good measure.
31
+ update_option( 'rewrite_rules', '' );