Cyr-To-Lat - Version 4.5.0

Version Description

(18.05.2020) = * Added Greek and Armenian languages * Added background conversion of attachments and thumbnails * Fixed background conversion of existing slugs

Download this release

Release Info

Developer mihdan
Plugin Icon 128x128 Cyr-To-Lat
Version 4.5.0
Comparing to
See all releases

Code changes from version 4.4.0 to 4.5.0

classes/background-processes/class-post-conversion-process.php CHANGED
@@ -41,10 +41,10 @@ class Post_Conversion_Process extends Conversion_Process {
41
  * @param Main $main Plugin main class.
42
  */
43
  public function __construct( $main ) {
44
- parent::__construct( $main );
45
-
46
  $this->action = constant( 'CYR_TO_LAT_POST_CONVERSION_ACTION' );
47
  $this->locale = get_locale();
 
 
48
  }
49
 
50
  /**
@@ -70,11 +70,124 @@ class Post_Conversion_Process extends Conversion_Process {
70
  $wpdb->update( $wpdb->posts, [ 'post_name' => rawurlencode( $transliterated_name ) ], [ 'ID' => $post->ID ] );
71
 
72
  $this->log( __( 'Post slug converted:', 'cyr2lat' ) . ' ' . $post_name . ' => ' . $transliterated_name );
 
 
 
 
 
 
73
  }
74
 
75
  return false;
76
  }
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  /**
79
  * Complete
80
  */
41
  * @param Main $main Plugin main class.
42
  */
43
  public function __construct( $main ) {
 
 
44
  $this->action = constant( 'CYR_TO_LAT_POST_CONVERSION_ACTION' );
45
  $this->locale = get_locale();
46
+
47
+ parent::__construct( $main );
48
  }
49
 
50
  /**
70
  $wpdb->update( $wpdb->posts, [ 'post_name' => rawurlencode( $transliterated_name ) ], [ 'ID' => $post->ID ] );
71
 
72
  $this->log( __( 'Post slug converted:', 'cyr2lat' ) . ' ' . $post_name . ' => ' . $transliterated_name );
73
+
74
+ if ( 'attachment' === $post->post_type ) {
75
+ $this->rename_attachment( $post->ID );
76
+ $this->rename_thumbnails( $post->ID );
77
+ $this->update_attachment_metadata( $post->ID );
78
+ }
79
  }
80
 
81
  return false;
82
  }
83
 
84
+ /**
85
+ * Rename attachment.
86
+ *
87
+ * @param int $post_id Post ID.
88
+ */
89
+ protected function rename_attachment( $post_id ) {
90
+ $file = get_attached_file( $post_id );
91
+
92
+ if ( $file ) {
93
+ $updated = false;
94
+ $transliterated_file = $this->get_transliterated_file( $file );
95
+ $rename = $this->rename_file( $file, $transliterated_file );
96
+ if ( $rename ) {
97
+ $updated = update_attached_file( $post_id, $transliterated_file );
98
+ }
99
+
100
+ if ( $updated ) {
101
+ $this->log( __( 'Attachment file converted:', 'cyr2lat' ) . ' ' . $file . ' => ' . $transliterated_file );
102
+
103
+ return;
104
+ }
105
+ }
106
+
107
+ $this->log( __( 'Cannot convert attachment file for attachment id:', 'cyr2lat' ) . ' ' . $post_id );
108
+ }
109
+
110
+ /**
111
+ * Rename thumbnails.
112
+ *
113
+ * @param int $post_id Post ID.
114
+ */
115
+ protected function rename_thumbnails( $post_id ) {
116
+ $sizes = get_intermediate_image_sizes();
117
+
118
+ foreach ( $sizes as $size ) {
119
+ $url = wp_get_attachment_image_src( $post_id, $size )[0];
120
+ $file = untrailingslashit( constant( 'ABSPATH' ) ) . wp_make_link_relative( $url );
121
+ $transliterated_file = $this->get_transliterated_file( $file );
122
+
123
+ $rename = $this->rename_file( $file, $transliterated_file );
124
+ if ( $rename ) {
125
+ $this->log( __( 'Thumbnail file renamed:', 'cyr2lat' ) . ' ' . $file . ' => ' . $transliterated_file );
126
+ }
127
+ if ( false === $rename ) {
128
+ $this->log( __( 'Cannot rename thumbnail file:', 'cyr2lat' ) . ' ' . $file );
129
+ }
130
+ }
131
+ }
132
+
133
+ /**
134
+ * Update attachment metadata.
135
+ *
136
+ * @param int $attachment_id Attachment ID.
137
+ */
138
+ protected function update_attachment_metadata( $attachment_id ) {
139
+ $meta = wp_get_attachment_metadata( $attachment_id );
140
+
141
+ if ( isset( $meta['file'] ) ) {
142
+ $meta['file'] = $this->main->transliterate( $meta['file'] );
143
+ }
144
+
145
+ if ( isset( $meta['sizes'] ) ) {
146
+ foreach ( $meta['sizes'] as $key => $size ) {
147
+ $meta['sizes'][ $key ]['file'] = $this->main->transliterate( $meta['sizes'][ $key ]['file'] );
148
+ }
149
+ }
150
+
151
+ wp_update_attachment_metadata( $attachment_id, $meta );
152
+ }
153
+
154
+ /**
155
+ * Get transliterated filename with path.
156
+ *
157
+ * @param string $file Filename.
158
+ *
159
+ * @return string
160
+ */
161
+ protected function get_transliterated_file( $file ) {
162
+ $path = pathinfo( $file );
163
+ $transliterated_filename = $this->main->transliterate( $path['filename'] );
164
+
165
+ return $path['dirname'] . '/' . $transliterated_filename . '.' . $path['extension'];
166
+ }
167
+
168
+ /**
169
+ * Rename file.
170
+ * Return false if rename failed.
171
+ *
172
+ * @param string $file Full filename.
173
+ * @param string $new_file New full filename.
174
+ *
175
+ * @return bool|null
176
+ */
177
+ protected function rename_file( $file, $new_file ) {
178
+ $path = pathinfo( $file );
179
+ $new_path = pathinfo( $new_file );
180
+
181
+ $filename = $path['filename'];
182
+ $new_filename = $new_path['filename'];
183
+
184
+ if ( $new_filename !== $filename ) {
185
+ return rename( $file, $new_file );
186
+ }
187
+
188
+ return null;
189
+ }
190
+
191
  /**
192
  * Complete
193
  */
classes/background-processes/class-term-conversion-process.php CHANGED
@@ -41,10 +41,10 @@ class Term_Conversion_Process extends Conversion_Process {
41
  * @param Main $main Plugin main class.
42
  */
43
  public function __construct( $main ) {
44
- parent::__construct( $main );
45
-
46
  $this->action = constant( 'CYR_TO_LAT_TERM_CONVERSION_ACTION' );
47
  $this->locale = get_locale();
 
 
48
  }
49
 
50
  /**
41
  * @param Main $main Plugin main class.
42
  */
43
  public function __construct( $main ) {
 
 
44
  $this->action = constant( 'CYR_TO_LAT_TERM_CONVERSION_ACTION' );
45
  $this->locale = get_locale();
46
+
47
+ parent::__construct( $main );
48
  }
49
 
50
  /**
classes/class-conversion-tables.php CHANGED
@@ -375,6 +375,146 @@ class Conversion_Tables {
375
  'ш' => 's',
376
  ];
377
  break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  // Georgian.
379
  case 'ka_GE':
380
  $table = [
375
  'ш' => 's',
376
  ];
377
  break;
378
+ // Greek.
379
+ // @link https://en.wikipedia.org/wiki/Greek_alphabet.
380
+ case 'el':
381
+ $table = [
382
+ 'Α' => 'A',
383
+ 'Β' => 'B',
384
+ 'Γ' => 'G',
385
+ 'Δ' => 'D',
386
+ 'Ε' => 'E',
387
+ 'Ζ' => 'Z',
388
+ 'Η' => 'E',
389
+ 'Θ' => 'TH',
390
+ 'Ι' => 'I',
391
+ 'Κ' => 'K',
392
+ 'Λ' => 'L',
393
+ 'Μ' => 'M',
394
+ 'Ν' => 'N',
395
+ 'Ξ' => 'X',
396
+ 'Ο' => 'O',
397
+ 'Π' => 'P',
398
+ 'Ρ' => 'R',
399
+ 'Σ' => 'S',
400
+ 'Τ' => 'T',
401
+ 'Υ' => 'U',
402
+ 'Φ' => 'PH',
403
+ 'Χ' => 'KH',
404
+ 'Ψ' => 'PS',
405
+ 'Ω' => 'O',
406
+ 'α' => 'a',
407
+ 'β' => 'b',
408
+ 'γ' => 'g',
409
+ 'δ' => 'd',
410
+ 'ε' => 'e',
411
+ 'ζ' => 'z',
412
+ 'η' => 'e',
413
+ 'θ' => 'th',
414
+ 'ι' => 'i',
415
+ 'κ' => 'k',
416
+ 'λ' => 'l',
417
+ 'μ' => 'm',
418
+ 'ν' => 'n',
419
+ 'ξ' => 'x',
420
+ 'ο' => 'o',
421
+ 'π' => 'p',
422
+ 'ρ' => 'r',
423
+ 'σ' => 's',
424
+ 'ς' => 's',
425
+ 'τ' => 't',
426
+ 'υ' => 'u',
427
+ 'φ' => 'ph',
428
+ 'χ' => 'kh',
429
+ 'ψ' => 'ps',
430
+ 'ω' => 'o',
431
+ ];
432
+ break;
433
+ // Armenian.
434
+ // @link https://en.wikipedia.org/wiki/Romanization_of_Armenian.
435
+ case 'hy':
436
+ $table = [
437
+ 'Ա' => 'A',
438
+ 'Բ' => 'B',
439
+ 'Գ' => 'G',
440
+ 'Դ' => 'D',
441
+ 'Ե' => 'E',
442
+ 'Զ' => 'Z',
443
+ 'Է' => 'E',
444
+ 'Ը' => 'Y',
445
+ 'Թ' => 'T',
446
+ 'Ժ' => 'ZH',
447
+ 'Ի' => 'I',
448
+ 'Լ' => 'L',
449
+ 'Խ' => 'X',
450
+ 'Ծ' => 'C',
451
+ 'Կ' => 'K',
452
+ 'Հ' => 'H',
453
+ 'Ձ' => 'J',
454
+ 'Ղ' => 'GH',
455
+ 'Ճ' => 'CH',
456
+ 'Մ' => 'M',
457
+ 'Յ' => 'Y',
458
+ 'Ն' => 'N',
459
+ 'Շ' => 'SH',
460
+ 'Ո' => 'O',
461
+ 'Չ' => 'CH',
462
+ 'Պ' => 'P',
463
+ 'Ջ' => 'J',
464
+ 'Ռ' => 'RR',
465
+ 'Ս' => 'S',
466
+ 'Վ' => 'V',
467
+ 'Տ' => 'T',
468
+ 'Ր' => 'R',
469
+ 'Ց' => 'C',
470
+ 'Ւ' => 'W',
471
+ 'Փ' => 'P',
472
+ 'Ք' => 'Q',
473
+ 'Օ' => 'O',
474
+ 'Ֆ' => 'F',
475
+ 'ՈՒ' => 'U',
476
+ 'ա' => 'a',
477
+ 'բ' => 'b',
478
+ 'գ' => 'g',
479
+ 'դ' => 'd',
480
+ 'ե' => 'e',
481
+ 'զ' => 'z',
482
+ 'է' => 'e',
483
+ 'ը' => 'y',
484
+ 'թ' => 't',
485
+ 'ժ' => 'zh',
486
+ 'ի' => 'i',
487
+ 'լ' => 'l',
488
+ 'խ' => 'x',
489
+ 'ծ' => 'c',
490
+ 'կ' => 'k',
491
+ 'հ' => 'h',
492
+ 'ձ' => 'j',
493
+ 'ղ' => 'gh',
494
+ 'ճ' => 'ch',
495
+ 'մ' => 'm',
496
+ 'յ' => 'y',
497
+ 'ն' => 'n',
498
+ 'շ' => 'sh',
499
+ 'ո' => 'o',
500
+ 'չ' => 'ch',
501
+ 'պ' => 'p',
502
+ 'ջ' => 'j',
503
+ 'ռ' => 'rr',
504
+ 'ս' => 's',
505
+ 'վ' => 'v',
506
+ 'տ' => 't',
507
+ 'ր' => 'r',
508
+ 'ց' => 'c',
509
+ 'ւ' => 'w',
510
+ 'փ' => 'p',
511
+ 'ք' => 'q',
512
+ 'օ' => 'o',
513
+ 'ֆ' => 'f',
514
+ 'ու' => 'u',
515
+ 'և' => 'ew',
516
+ ];
517
+ break;
518
  // Georgian.
519
  case 'ka_GE':
520
  $table = [
classes/class-converter.php CHANGED
@@ -19,6 +19,16 @@ class Converter {
19
  */
20
  const QUERY_ARG = 'cyr-to-lat-convert';
21
 
 
 
 
 
 
 
 
 
 
 
22
  /**
23
  * Plugin main class.
24
  *
@@ -161,14 +171,21 @@ class Converter {
161
  * @param array $args Arguments for query.
162
  */
163
  public function convert_existing_slugs( $args = [] ) {
 
 
 
 
 
 
 
 
 
 
164
  global $wpdb;
165
 
166
- $regexp = Main::PROHIBITED_CHARS_REGEX . '+';
167
 
168
- $post_types = get_post_types( [ 'public' => true ] );
169
- $post_types += [
170
- 'nav_menu_item' => 'nav_menu_item',
171
- ];
172
 
173
  $defaults = [
174
  'post_type' => apply_filters( 'ctl_post_types', $post_types ),
@@ -177,18 +194,30 @@ class Converter {
177
 
178
  $args = wp_parse_args( $args, $defaults );
179
 
 
 
 
 
 
 
 
 
 
 
180
  // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
181
  // phpcs:ignore WordPress.DB.DirectDatabaseQuery
182
- $posts = $wpdb->get_results(
183
- $wpdb->prepare(
184
- "SELECT ID, post_name FROM $wpdb->posts WHERE post_name REGEXP(%s) AND post_status IN (" .
185
- $this->main->ctl_prepare_in( $args['post_status'] ) . ') AND post_type IN (' .
186
- $this->main->ctl_prepare_in( $args['post_type'] ) . ')',
187
- $regexp
188
- )
189
- );
190
  // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
191
 
 
 
 
 
 
 
 
 
 
192
  if ( $posts ) {
193
  foreach ( (array) $posts as $post ) {
194
  $this->process_all_posts->push_to_queue( $post );
@@ -201,22 +230,33 @@ class Converter {
201
  );
202
 
203
  $this->process_all_posts->save()->dispatch();
204
- } else {
205
- $this->admin_notices->add_notice(
206
- __( 'Cyr To Lat has not found existing post slugs for conversion.', 'cyr2lat' ),
207
- 'notice notice-info is-dismissible'
208
- );
209
  }
 
 
 
 
 
 
 
210
 
211
  // phpcs:ignore WordPress.DB.DirectDatabaseQuery
212
  $terms = $wpdb->get_results(
213
  $wpdb->prepare(
214
  "SELECT t.term_id, slug, tt.taxonomy, tt.term_taxonomy_id FROM $wpdb->terms t, $wpdb->term_taxonomy tt
215
  WHERE t.slug REGEXP(%s) AND tt.term_id = t.term_id",
216
- $regexp
217
  )
218
  );
219
 
 
 
 
 
 
 
 
 
 
220
  if ( $terms ) {
221
  foreach ( (array) $terms as $term ) {
222
  $this->process_all_terms->push_to_queue( $term );
@@ -229,16 +269,11 @@ class Converter {
229
  );
230
 
231
  $this->process_all_terms->save()->dispatch();
232
- } else {
233
- $this->admin_notices->add_notice(
234
- __( 'Cyr To Lat has not found existing term slugs for conversion.', 'cyr2lat' ),
235
- 'notice notice-info is-dismissible'
236
- );
237
  }
238
  }
239
 
240
  /**
241
- * Log
242
  *
243
  * @param string $message Message to log.
244
  */
19
  */
20
  const QUERY_ARG = 'cyr-to-lat-convert';
21
 
22
+ /**
23
+ * Regex of prohibited chars in slugs
24
+ * [^A-Za-z0-9[.apostrophe.][.underscore.][.period.][.hyphen.]]+
25
+ * So, allowed chars are A-Za-z0-9[.apostrophe.][.underscore.][.period.][.hyphen.]
26
+ * % is not allowed in the slug, but could present if slug is url_encoded
27
+ *
28
+ * @link https://dev.mysql.com/doc/refman/5.6/en/regexp.html
29
+ */
30
+ const PROHIBITED_CHARS_REGEX = "[^A-Za-z0-9'_\.\-]+";
31
+
32
  /**
33
  * Plugin main class.
34
  *
171
  * @param array $args Arguments for query.
172
  */
173
  public function convert_existing_slugs( $args = [] ) {
174
+ $this->convert_existing_post_slugs( $args );
175
+ $this->convert_existing_term_slugs();
176
+ }
177
+
178
+ /**
179
+ * Convert existing post slugs.
180
+ *
181
+ * @param array $args Arguments for query.
182
+ */
183
+ protected function convert_existing_post_slugs( $args = [] ) {
184
  global $wpdb;
185
 
186
+ $post_types = get_post_types( [ 'public' => true ] );
187
 
188
+ $post_types += [ 'nav_menu_item' => 'nav_menu_item' ];
 
 
 
189
 
190
  $defaults = [
191
  'post_type' => apply_filters( 'ctl_post_types', $post_types ),
194
 
195
  $args = wp_parse_args( $args, $defaults );
196
 
197
+ $regexp = $wpdb->prepare( '%s', self::PROHIBITED_CHARS_REGEX );
198
+
199
+ $post_sql =
200
+ 'post_status IN (' . $this->main->prepare_in( $args['post_status'] ) . ')' .
201
+ ' AND post_type IN (' . $this->main->prepare_in( $args['post_type'] ) . ')';
202
+ $media_sql = "post_status = 'inherit' AND post_type = 'attachment'";
203
+ $all_posts_sql = '(' . $post_sql . ') OR (' . $media_sql . ')';
204
+
205
+ $sql = "SELECT ID, post_name, post_type FROM $wpdb->posts WHERE post_name REGEXP($regexp) AND ($all_posts_sql)";
206
+
207
  // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
208
  // phpcs:ignore WordPress.DB.DirectDatabaseQuery
209
+ $posts = $wpdb->get_results( $sql );
 
 
 
 
 
 
 
210
  // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
211
 
212
+ if ( ! $posts ) {
213
+ $this->admin_notices->add_notice(
214
+ __( 'Cyr To Lat has not found existing post slugs for conversion.', 'cyr2lat' ),
215
+ 'notice notice-info is-dismissible'
216
+ );
217
+
218
+ return;
219
+ }
220
+
221
  if ( $posts ) {
222
  foreach ( (array) $posts as $post ) {
223
  $this->process_all_posts->push_to_queue( $post );
230
  );
231
 
232
  $this->process_all_posts->save()->dispatch();
 
 
 
 
 
233
  }
234
+ }
235
+
236
+ /**
237
+ * Convert existing term slugs.
238
+ */
239
+ protected function convert_existing_term_slugs() {
240
+ global $wpdb;
241
 
242
  // phpcs:ignore WordPress.DB.DirectDatabaseQuery
243
  $terms = $wpdb->get_results(
244
  $wpdb->prepare(
245
  "SELECT t.term_id, slug, tt.taxonomy, tt.term_taxonomy_id FROM $wpdb->terms t, $wpdb->term_taxonomy tt
246
  WHERE t.slug REGEXP(%s) AND tt.term_id = t.term_id",
247
+ self::PROHIBITED_CHARS_REGEX
248
  )
249
  );
250
 
251
+ if ( ! $terms ) {
252
+ $this->admin_notices->add_notice(
253
+ __( 'Cyr To Lat has not found existing term slugs for conversion.', 'cyr2lat' ),
254
+ 'notice notice-info is-dismissible'
255
+ );
256
+
257
+ return;
258
+ }
259
+
260
  if ( $terms ) {
261
  foreach ( (array) $terms as $term ) {
262
  $this->process_all_terms->push_to_queue( $term );
269
  );
270
 
271
  $this->process_all_terms->save()->dispatch();
 
 
 
 
 
272
  }
273
  }
274
 
275
  /**
276
+ * Log.
277
  *
278
  * @param string $message Message to log.
279
  */
classes/class-main.php CHANGED
@@ -16,14 +16,6 @@ use Cyr_To_Lat\Symfony\Polyfill\Mbstring\Mbstring;
16
  */
17
  class Main {
18
 
19
- /**
20
- * Regex of prohibited chars in slugs
21
- * [^A-Za-z0-9[.apostrophe.][.underscore.][.period.][.hyphen.]]+
22
- *
23
- * @link https://dev.mysql.com/doc/refman/5.6/en/regexp.html
24
- */
25
- const PROHIBITED_CHARS_REGEX = "[^A-Za-z0-9'_\.\-]";
26
-
27
  /**
28
  * Plugin settings.
29
  *
@@ -122,9 +114,9 @@ class Main {
122
  * Init class hooks.
123
  */
124
  public function init_hooks() {
125
- add_filter( 'sanitize_title', [ $this, 'ctl_sanitize_title' ], 9, 3 );
126
- add_filter( 'sanitize_file_name', [ $this, 'ctl_sanitize_filename' ], 10, 2 );
127
- add_filter( 'wp_insert_post_data', [ $this, 'ctl_sanitize_post_name' ], 10, 2 );
128
  }
129
 
130
  /**
@@ -136,7 +128,7 @@ class Main {
136
  *
137
  * @return string
138
  */
139
- public function ctl_sanitize_title( $title, $raw_title = '', $context = '' ) {
140
  global $wpdb;
141
 
142
  if ( ! $title ) {
@@ -210,7 +202,7 @@ class Main {
210
  *
211
  * @return string
212
  */
213
- public function ctl_sanitize_filename( $filename, $filename_raw ) {
214
  $pre = apply_filters( 'ctl_pre_sanitize_filename', false, $filename );
215
 
216
  if ( false !== $pre ) {
@@ -310,12 +302,12 @@ class Main {
310
  *
311
  * @return bool
312
  */
313
- private function ctl_is_classic_editor_plugin_active() {
 
314
  if ( ! function_exists( 'is_plugin_active' ) ) {
315
- // @codeCoverageIgnoreStart
316
  include_once ABSPATH . 'wp-admin/includes/plugin.php';
317
- // @codeCoverageIgnoreEnd
318
  }
 
319
 
320
  return is_plugin_active( 'classic-editor/classic-editor.php' );
321
  }
@@ -328,7 +320,7 @@ class Main {
328
  *
329
  * @return bool
330
  */
331
- private function ctl_is_gutenberg_editor_active() {
332
 
333
  // Gutenberg plugin is installed and activated.
334
  $gutenberg = ! ( false === has_filter( 'replace_editor', 'gutenberg_init' ) );
@@ -340,7 +332,7 @@ class Main {
340
  return false;
341
  }
342
 
343
- if ( $this->ctl_is_classic_editor_plugin_active() ) {
344
  $editor_option = get_option( 'classic-editor-replace' );
345
  $block_editor_active = [ 'no-replace', 'block' ];
346
 
@@ -358,10 +350,10 @@ class Main {
358
  *
359
  * @return mixed
360
  */
361
- public function ctl_sanitize_post_name( $data, $postarr = [] ) {
362
  global $current_screen;
363
 
364
- if ( ! $this->ctl_is_gutenberg_editor_active() ) {
365
  return $data;
366
  }
367
 
@@ -391,7 +383,7 @@ class Main {
391
  *
392
  * @return string Items separated by comma and sql-escaped
393
  */
394
- public function ctl_prepare_in( $items, $format = '%s' ) {
395
  global $wpdb;
396
 
397
  $items = (array) $items;
16
  */
17
  class Main {
18
 
 
 
 
 
 
 
 
 
19
  /**
20
  * Plugin settings.
21
  *
114
  * Init class hooks.
115
  */
116
  public function init_hooks() {
117
+ add_filter( 'sanitize_title', [ $this, 'sanitize_title' ], 9, 3 );
118
+ add_filter( 'sanitize_file_name', [ $this, 'sanitize_filename' ], 10, 2 );
119
+ add_filter( 'wp_insert_post_data', [ $this, 'sanitize_post_name' ], 10, 2 );
120
  }
121
 
122
  /**
128
  *
129
  * @return string
130
  */
131
+ public function sanitize_title( $title, $raw_title = '', $context = '' ) {
132
  global $wpdb;
133
 
134
  if ( ! $title ) {
202
  *
203
  * @return string
204
  */
205
+ public function sanitize_filename( $filename, $filename_raw ) {
206
  $pre = apply_filters( 'ctl_pre_sanitize_filename', false, $filename );
207
 
208
  if ( false !== $pre ) {
302
  *
303
  * @return bool
304
  */
305
+ private function is_classic_editor_plugin_active() {
306
+ // @codeCoverageIgnoreStart
307
  if ( ! function_exists( 'is_plugin_active' ) ) {
 
308
  include_once ABSPATH . 'wp-admin/includes/plugin.php';
 
309
  }
310
+ // @codeCoverageIgnoreEnd
311
 
312
  return is_plugin_active( 'classic-editor/classic-editor.php' );
313
  }
320
  *
321
  * @return bool
322
  */
323
+ private function is_gutenberg_editor_active() {
324
 
325
  // Gutenberg plugin is installed and activated.
326
  $gutenberg = ! ( false === has_filter( 'replace_editor', 'gutenberg_init' ) );
332
  return false;
333
  }
334
 
335
+ if ( $this->is_classic_editor_plugin_active() ) {
336
  $editor_option = get_option( 'classic-editor-replace' );
337
  $block_editor_active = [ 'no-replace', 'block' ];
338
 
350
  *
351
  * @return mixed
352
  */
353
+ public function sanitize_post_name( $data, $postarr = [] ) {
354
  global $current_screen;
355
 
356
+ if ( ! $this->is_gutenberg_editor_active() ) {
357
  return $data;
358
  }
359
 
383
  *
384
  * @return string Items separated by comma and sql-escaped
385
  */
386
+ public function prepare_in( $items, $format = '%s' ) {
387
  global $wpdb;
388
 
389
  $items = (array) $items;
classes/class-requirements.php CHANGED
@@ -51,11 +51,11 @@ if ( ! class_exists( __NAMESPACE__ . '\Requirements' ) ) {
51
 
52
  $this->cyr2lat_page = [ 'page' => Settings::SCREEN_ID ];
53
 
 
54
  if ( ! function_exists( 'WP_Filesystem' ) ) {
55
- // @codeCoverageIgnoreStart
56
  require_once ABSPATH . 'wp-admin/includes/file.php';
57
- // @codeCoverageIgnoreEnd
58
  }
 
59
 
60
  if ( ! WP_Filesystem() ) {
61
  return;
51
 
52
  $this->cyr2lat_page = [ 'page' => Settings::SCREEN_ID ];
53
 
54
+ // @codeCoverageIgnoreStart
55
  if ( ! function_exists( 'WP_Filesystem' ) ) {
 
56
  require_once ABSPATH . 'wp-admin/includes/file.php';
 
57
  }
58
+ // @codeCoverageIgnoreEnd
59
 
60
  if ( ! WP_Filesystem() ) {
61
  return;
classes/class-settings.php CHANGED
@@ -160,6 +160,12 @@ class Settings {
160
  'sr_RS' => [
161
  'label' => __( 'sr_RS Table', 'cyr2lat' ),
162
  ],
 
 
 
 
 
 
163
  'ka_GE' => [
164
  'label' => __( 'ka_GE Table', 'cyr2lat' ),
165
  ],
@@ -268,15 +274,15 @@ class Settings {
268
  $menu_title = __( 'Cyr To Lat', 'cyr2lat' );
269
  $capability = 'manage_options';
270
  $slug = self::PAGE;
271
- $callback = [ $this, 'ctl_settings_page' ];
272
  add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $slug, $callback );
273
  }
274
 
275
  /**
276
  * Settings page.
277
  */
278
- public function ctl_settings_page() {
279
- if ( ! $this->is_ctl_options_screen() ) {
280
  return;
281
  }
282
 
@@ -339,7 +345,7 @@ class Settings {
339
  * Setup settings sections.
340
  */
341
  public function setup_sections() {
342
- if ( ! $this->is_ctl_options_screen() ) {
343
  return;
344
  }
345
 
@@ -347,7 +353,7 @@ class Settings {
347
  add_settings_section(
348
  $form_field['section'],
349
  $form_field['label'],
350
- [ $this, 'cyr_to_lat_section' ],
351
  self::PAGE
352
  );
353
  }
@@ -358,7 +364,7 @@ class Settings {
358
  *
359
  * @param array $arguments Section arguments.
360
  */
361
- public function cyr_to_lat_section( $arguments ) {
362
  $locale = str_replace( '_section', '', $arguments['id'] );
363
  if ( $this->get_current_locale() === $locale ) {
364
  echo '<div id="ctl-current"></div>';
@@ -369,7 +375,7 @@ class Settings {
369
  * Setup settings fields.
370
  */
371
  public function setup_fields() {
372
- if ( ! $this->is_ctl_options_screen() ) {
373
  return;
374
  }
375
 
@@ -666,7 +672,7 @@ class Settings {
666
  * Enqueue class scripts.
667
  */
668
  public function admin_enqueue_scripts() {
669
- if ( ! $this->is_ctl_options_screen() ) {
670
  return;
671
  }
672
 
@@ -754,7 +760,7 @@ class Settings {
754
  *
755
  * @return bool
756
  */
757
- protected function is_ctl_options_screen() {
758
  $current_screen = get_current_screen();
759
 
760
  return $current_screen && ( 'options' === $current_screen->id || self::SCREEN_ID === $current_screen->id );
160
  'sr_RS' => [
161
  'label' => __( 'sr_RS Table', 'cyr2lat' ),
162
  ],
163
+ 'el' => [
164
+ 'label' => __( 'el Table', 'cyr2lat' ),
165
+ ],
166
+ 'hy' => [
167
+ 'label' => __( 'hy Table', 'cyr2lat' ),
168
+ ],
169
  'ka_GE' => [
170
  'label' => __( 'ka_GE Table', 'cyr2lat' ),
171
  ],
274
  $menu_title = __( 'Cyr To Lat', 'cyr2lat' );
275
  $capability = 'manage_options';
276
  $slug = self::PAGE;
277
+ $callback = [ $this, 'settings_page' ];
278
  add_submenu_page( $parent_slug, $page_title, $menu_title, $capability, $slug, $callback );
279
  }
280
 
281
  /**
282
  * Settings page.
283
  */
284
+ public function settings_page() {
285
+ if ( ! $this->is_options_screen() ) {
286
  return;
287
  }
288
 
345
  * Setup settings sections.
346
  */
347
  public function setup_sections() {
348
+ if ( ! $this->is_options_screen() ) {
349
  return;
350
  }
351
 
353
  add_settings_section(
354
  $form_field['section'],
355
  $form_field['label'],
356
+ [ $this, 'section_callback' ],
357
  self::PAGE
358
  );
359
  }
364
  *
365
  * @param array $arguments Section arguments.
366
  */
367
+ public function section_callback( $arguments ) {
368
  $locale = str_replace( '_section', '', $arguments['id'] );
369
  if ( $this->get_current_locale() === $locale ) {
370
  echo '<div id="ctl-current"></div>';
375
  * Setup settings fields.
376
  */
377
  public function setup_fields() {
378
+ if ( ! $this->is_options_screen() ) {
379
  return;
380
  }
381
 
672
  * Enqueue class scripts.
673
  */
674
  public function admin_enqueue_scripts() {
675
+ if ( ! $this->is_options_screen() ) {
676
  return;
677
  }
678
 
760
  *
761
  * @return bool
762
  */
763
+ protected function is_options_screen() {
764
  $current_screen = get_current_screen();
765
 
766
  return $current_screen && ( 'options' === $current_screen->id || self::SCREEN_ID === $current_screen->id );
cyr-to-lat.php CHANGED
@@ -9,8 +9,8 @@
9
  * Author URI: https://profiles.wordpress.org/sergeybiryukov/
10
  * Requires at least: 5.1
11
  * Tested up to: 5.4
12
- * Version: 4.4.0
13
- * Stable tag: 4.4.0
14
  *
15
  * Text Domain: cyr2lat
16
  * Domain Path: /languages/
@@ -34,7 +34,7 @@ if ( defined( 'CYR_TO_LAT_VERSION' ) ) {
34
  /**
35
  * Plugin version.
36
  */
37
- define( 'CYR_TO_LAT_VERSION', '4.4.0' );
38
 
39
  /**
40
  * Path to the plugin dir.
9
  * Author URI: https://profiles.wordpress.org/sergeybiryukov/
10
  * Requires at least: 5.1
11
  * Tested up to: 5.4
12
+ * Version: 4.5.0
13
+ * Stable tag: 4.5.0
14
  *
15
  * Text Domain: cyr2lat
16
  * Domain Path: /languages/
34
  /**
35
  * Plugin version.
36
  */
37
+ define( 'CYR_TO_LAT_VERSION', '4.5.0' );
38
 
39
  /**
40
  * Path to the plugin dir.
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: SergeyBiryukov, mihdan, karevn, webvitaly, kaggdesign
3
  Tags: cyrillic, belorussian, ukrainian, bulgarian, macedonian, georgian, kazakh, latin, l10n, russian, cyr-to-lat, cyr2lat, rustolat, slugs, translations, transliteration
4
  Requires at least: 5.1
5
  Tested up to: 5.4
6
- Stable tag: 4.4.0
7
  Requires PHP: 5.6.20
8
 
9
  Converts Cyrillic characters in post, page and term slugs to Latin characters.
@@ -17,7 +17,8 @@ Converts Cyrillic characters in post, page and term slugs to Latin characters. U
17
  * Converts any number of existing post, page and term slugs in background processes
18
  * Saves existing post and page permalinks integrity
19
  * Performs transliteration of attachment file names
20
- * Includes Russian, Belorussian, Ukrainian, Bulgarian, Macedonian, Serbian, Georgian, Kazakh, Hebrew, and Chinese characters
 
21
  * [Officially compatible with WPML](https://wpml.org/plugin/cyr-to-lat/)
22
 
23
  ![WPML Certificate](https://ps.w.org/cyr2lat/assets/Cyr-To-Lat---WPML-Compatibility-Certificate-240x250.png)
@@ -38,13 +39,20 @@ Based on the original Rus-To-Lat plugin by Anton Skorobogatov.
38
  Add this code to your theme's `functions.php` file:
39
 
40
  `
41
- function my_cyr_to_lat_table( $ctl_table ) {
42
- $ctl_table['Ъ'] = 'U';
43
- $ctl_table['ъ'] = 'u';
 
 
 
 
 
 
 
44
 
45
- return $ctl_table;
46
  }
47
- add_filter( 'ctl_table', 'my_cyr_to_lat_table' );
48
  `
49
 
50
  = How can I redefine non-standard locale ? =
@@ -91,6 +99,11 @@ Yes you can!
91
 
92
  == Changelog ==
93
 
 
 
 
 
 
94
  = 4.4.0 (18.04.2020) =
95
  * Full flexibility to edit transliteration table: now it is possible to add/remove transliteration pairs on the settings page
96
  * Ability to edit not only values in the transliteration table, but also keys
3
  Tags: cyrillic, belorussian, ukrainian, bulgarian, macedonian, georgian, kazakh, latin, l10n, russian, cyr-to-lat, cyr2lat, rustolat, slugs, translations, transliteration
4
  Requires at least: 5.1
5
  Tested up to: 5.4
6
+ Stable tag: 4.5.0
7
  Requires PHP: 5.6.20
8
 
9
  Converts Cyrillic characters in post, page and term slugs to Latin characters.
17
  * Converts any number of existing post, page and term slugs in background processes
18
  * Saves existing post and page permalinks integrity
19
  * Performs transliteration of attachment file names
20
+ * Includes Russian, Belorussian, Ukrainian, Bulgarian, Macedonian, Serbian, Greek, Armenian, Georgian, Kazakh, Hebrew, and Chinese characters
21
+ * [Has many advantages over similar plugins](https://kagg.eu/en/the-benefits-of-cyr-to-lat/)
22
  * [Officially compatible with WPML](https://wpml.org/plugin/cyr-to-lat/)
23
 
24
  ![WPML Certificate](https://ps.w.org/cyr2lat/assets/Cyr-To-Lat---WPML-Compatibility-Certificate-240x250.png)
39
  Add this code to your theme's `functions.php` file:
40
 
41
  `
42
+ /**
43
+ * Modify conversion table.
44
+ *
45
+ * @param array $table Conversion table.
46
+ *
47
+ * @return array
48
+ */
49
+ function my_ctl_table( $table ) {
50
+ $table['Ъ'] = 'U';
51
+ $table['ъ'] = 'u';
52
 
53
+ return $table;
54
  }
55
+ add_filter( 'ctl_table', 'my_ctl_table' );
56
  `
57
 
58
  = How can I redefine non-standard locale ? =
99
 
100
  == Changelog ==
101
 
102
+ = 4.5.0 (18.05.2020) =
103
+ * Added Greek and Armenian languages
104
+ * Added background conversion of attachments and thumbnails
105
+ * Fixed background conversion of existing slugs
106
+
107
  = 4.4.0 (18.04.2020) =
108
  * Full flexibility to edit transliteration table: now it is possible to add/remove transliteration pairs on the settings page
109
  * Ability to edit not only values in the transliteration table, but also keys