PluginProbe
Polylang / 3.0.2
Polylang v3.0.2
3.8.9 3.8.8 3.8.7 3.8.6 3.8.5 3.8.4 3.8.3 2.7 2.7.0.1 2.7.1 2.7.2 2.7.3 2.7.4 2.8 2.8.1 2.8.2 2.8.3 2.8.4 2.9 2.9.1 2.9.2 3.0 3.0.1 3.0.2 3.0.3 All 233 releases
polylang / admin / admin-classic-editor.php

admin-classic-editor.php in Polylang 3.0.2, at admin/admin-classic-editor.php

367 lines 10.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package Polylang
4 */
5
6 /**
7 * Manages filters and actions related to the classic editor
8 *
9 * @since 2.4
10 */
11 class PLL_Admin_Classic_Editor {
12 /**
13 * @var PLL_Model
14 */
15 public $model;
16
17 /**
18 * @var PLL_Admin_Links
19 */
20 public $links;
21
22 /**
23 * Current language (used to filter the content).
24 *
25 * @var PLL_Language
26 */
27 public $curlang;
28
29 /**
30 * Preferred language to assign to new contents.
31 *
32 * @var PLL_Language
33 */
34 public $pref_lang;
35
36 /**
37 * Constructor: setups filters and actions
38 *
39 * @since 2.4
40 *
41 * @param object $polylang
42 */
43 public function __construct( &$polylang ) {
44 $this->model = &$polylang->model;
45 $this->links = &$polylang->links;
46 $this->curlang = &$polylang->curlang;
47 $this->pref_lang = &$polylang->pref_lang;
48
49 // Adds the Languages box in the 'Edit Post' and 'Edit Page' panels
50 add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
51
52 // Ajax response for changing the language in the post metabox
53 add_action( 'wp_ajax_post_lang_choice', array( $this, 'post_lang_choice' ) );
54 add_action( 'wp_ajax_pll_posts_not_translated', array( $this, 'ajax_posts_not_translated' ) );
55
56 // Filters the pages by language in the parent dropdown list in the page attributes metabox
57 add_filter( 'page_attributes_dropdown_pages_args', array( $this, 'page_attributes_dropdown_pages_args' ), 10, 2 );
58
59 // Notice
60 add_action( 'edit_form_top', array( $this, 'edit_form_top' ) );
61 }
62
63 /**
64 * Adds the Language box in the 'Edit Post' and 'Edit Page' panels ( as well as in custom post types panels )
65 *
66 * @since 0.1
67 *
68 * @param string $post_type Current post type
69 * @return void
70 */
71 public function add_meta_boxes( $post_type ) {
72 if ( $this->model->is_translated_post_type( $post_type ) ) {
73 add_meta_box(
74 'ml_box',
75 __( 'Languages', 'polylang' ),
76 array( $this, 'post_language' ),
77 $post_type,
78 'side',
79 'high',
80 array(
81 '__back_compat_meta_box' => pll_use_block_editor_plugin(),
82 )
83 );
84 }
85 }
86
87 /**
88 * Displays the Languages metabox in the 'Edit Post' and 'Edit Page' panels
89 *
90 * @since 0.1
91 *
92 * @return void
93 */
94 public function post_language() {
95 global $post_ID;
96 $post_type = get_post_type( $post_ID );
97
98 // phpcs:ignore WordPress.Security.NonceVerification, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
99 $from_post_id = isset( $_GET['from_post'] ) ? (int) $_GET['from_post'] : 0;
100
101 $lang = ( $lg = $this->model->post->get_language( $post_ID ) ) ? $lg :
102 ( isset( $_GET['new_lang'] ) ? $this->model->get_language( sanitize_key( $_GET['new_lang'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification
103 $this->pref_lang );
104
105 $dropdown = new PLL_Walker_Dropdown();
106
107 $id = ( 'attachment' === $post_type ) ? sprintf( 'attachments[%d][language]', (int) $post_ID ) : 'post_lang_choice';
108
109 $dropdown_html = $dropdown->walk(
110 $this->model->get_languages_list(),
111 -1,
112 array(
113 'name' => $id,
114 'class' => 'post_lang_choice tags-input',
115 'selected' => $lang ? $lang->slug : '',
116 'flag' => true,
117 )
118 );
119
120 wp_nonce_field( 'pll_language', '_pll_nonce' );
121
122 // NOTE: the class "tags-input" allows to include the field in the autosave $_POST ( see autosave.js )
123 printf(
124 '<p><strong>%1$s</strong></p>
125 <label class="screen-reader-text" for="%2$s">%1$s</label>
126 <div id="select-%3$s-language">%4$s</div>',
127 esc_html__( 'Language', 'polylang' ),
128 esc_attr( $id ),
129 ( 'attachment' === $post_type ? 'media' : 'post' ),
130 $dropdown_html // phpcs:ignore WordPress.Security.EscapeOutput
131 );
132
133 /**
134 * Fires before displaying the list of translations in the Languages metabox for posts
135 *
136 * @since 1.8
137 */
138 do_action( 'pll_before_post_translations', $post_type );
139
140 echo '<div id="post-translations" class="translations">';
141 if ( $lang ) {
142 if ( 'attachment' === $post_type ) {
143 include __DIR__ . '/view-translations-media.php';
144 } else {
145 include __DIR__ . '/view-translations-post.php';
146 }
147 }
148 echo '</div>' . "\n";
149 }
150
151 /**
152 * Ajax response for changing the language in the post metabox
153 *
154 * @since 0.2
155 *
156 * @return void
157 */
158 public function post_lang_choice() {
159 check_ajax_referer( 'pll_language', '_pll_nonce' );
160
161 if ( ! isset( $_POST['post_id'], $_POST['lang'], $_POST['post_type'] ) ) {
162 wp_die( 0 );
163 }
164
165 global $post_ID; // Obliged to use the global variable for wp_popular_terms_checklist
166 $post_ID = (int) $_POST['post_id'];
167 $lang = $this->model->get_language( sanitize_key( $_POST['lang'] ) );
168 $post_type = sanitize_key( $_POST['post_type'] );
169
170 if ( empty( $lang ) || ! post_type_exists( $post_type ) ) {
171 wp_die( 0 );
172 }
173
174 $post_type_object = get_post_type_object( $post_type );
175
176 if ( empty( $post_type_object ) ) {
177 wp_die( 0 );
178 }
179
180 if ( ! current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
181 wp_die( -1 );
182 }
183
184 $this->model->post->set_language( $post_ID, $lang ); // Save language, useful to set the language when uploading media from post
185
186 // We also need to save the translations to match the language change
187 $translations = $this->model->post->get_translations( $post_ID );
188 $translations = array_diff( $translations, array( $post_ID ) );
189 $this->model->post->save_translations( $post_ID, $translations );
190
191 ob_start();
192 if ( 'attachment' === $post_type ) {
193 include __DIR__ . '/view-translations-media.php';
194 } else {
195 include __DIR__ . '/view-translations-post.php';
196 }
197 $x = new WP_Ajax_Response( array( 'what' => 'translations', 'data' => ob_get_contents() ) );
198 ob_end_clean();
199
200 // Categories
201 if ( isset( $_POST['taxonomies'] ) ) { // Not set for pages
202 $supplemental = array();
203
204 foreach ( array_map( 'sanitize_key', $_POST['taxonomies'] ) as $taxname ) {
205 $taxonomy = get_taxonomy( $taxname );
206
207 if ( ! empty( $taxonomy ) ) {
208 ob_start();
209 $popular_ids = wp_popular_terms_checklist( $taxonomy->name );
210 $supplemental['populars'] = ob_get_contents();
211 ob_end_clean();
212
213 ob_start();
214 // Use $post_ID to remember checked terms in case we come back to the original language
215 wp_terms_checklist( $post_ID, array( 'taxonomy' => $taxonomy->name, 'popular_cats' => $popular_ids ) );
216 $supplemental['all'] = ob_get_contents();
217 ob_end_clean();
218
219 $supplemental['dropdown'] = wp_dropdown_categories(
220 array(
221 'taxonomy' => $taxonomy->name,
222 'hide_empty' => 0,
223 'name' => 'new' . $taxonomy->name . '_parent',
224 'orderby' => 'name',
225 'hierarchical' => 1,
226 'show_option_none' => '&mdash; ' . $taxonomy->labels->parent_item . ' &mdash;',
227 'echo' => 0,
228 )
229 );
230
231 $x->Add( array( 'what' => 'taxonomy', 'data' => $taxonomy->name, 'supplemental' => $supplemental ) );
232 }
233 }
234 }
235
236 // Parent dropdown list ( only for hierarchical post types )
237 if ( in_array( $post_type, get_post_types( array( 'hierarchical' => true ) ) ) ) {
238 $post = get_post( $post_ID );
239
240 if ( ! empty( $post ) ) {
241 // Args and filter from 'page_attributes_meta_box' in wp-admin/includes/meta-boxes.php of WP 4.2.1
242 $dropdown_args = array(
243 'post_type' => $post->post_type,
244 'exclude_tree' => $post->ID,
245 'selected' => $post->post_parent,
246 'name' => 'parent_id',
247 'show_option_none' => __( '(no parent)', 'polylang' ),
248 'sort_column' => 'menu_order, post_title',
249 'echo' => 0,
250 );
251
252 /** This filter is documented in wp-admin/includes/meta-boxes.php */
253 $dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post ); // Since WP 3.3
254
255 $x->Add( array( 'what' => 'pages', 'data' => wp_dropdown_pages( $dropdown_args ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput
256 }
257 }
258
259 // Flag
260 $x->Add( array( 'what' => 'flag', 'data' => empty( $lang->flag ) ? esc_html( $lang->slug ) : $lang->flag ) );
261
262 // Sample permalink
263 $x->Add( array( 'what' => 'permalink', 'data' => get_sample_permalink_html( $post_ID ) ) );
264
265 $x->send();
266 }
267
268 /**
269 * Ajax response for input in translation autocomplete input box
270 *
271 * @since 1.5
272 *
273 * @return void
274 */
275 public function ajax_posts_not_translated() {
276 check_ajax_referer( 'pll_language', '_pll_nonce' );
277
278 if ( ! isset( $_GET['post_type'], $_GET['post_language'], $_GET['translation_language'], $_GET['term'], $_GET['pll_post_id'] ) ) {
279 wp_die( 0 );
280 }
281
282 $post_type = sanitize_key( $_GET['post_type'] );
283
284 if ( ! post_type_exists( $post_type ) ) {
285 wp_die( 0 );
286 }
287
288 $term = wp_unslash( $_GET['term'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
289
290 $post_language = $this->model->get_language( sanitize_key( $_GET['post_language'] ) );
291 $translation_language = $this->model->get_language( sanitize_key( $_GET['translation_language'] ) );
292
293 $return = array();
294
295 $untranslated_posts = $this->model->post->get_untranslated( $post_type, $post_language, $translation_language, $term );
296
297 // format output
298 foreach ( $untranslated_posts as $post ) {
299 $return[] = array(
300 'id' => $post->ID,
301 'value' => $post->post_title,
302 'link' => $this->links->edit_post_translation_link( $post->ID ),
303 );
304 }
305
306 // Add current translation in list
307 if ( $post_id = $this->model->post->get_translation( (int) $_GET['pll_post_id'], $translation_language ) ) {
308 $post = get_post( $post_id );
309
310 if ( ! empty( $post ) ) {
311 array_unshift(
312 $return,
313 array(
314 'id' => $post_id,
315 'value' => $post->post_title,
316 'link' => $this->links->edit_post_translation_link( $post_id ),
317 )
318 );
319 }
320 }
321
322 wp_die( wp_json_encode( $return ) );
323 }
324
325 /**
326 * Filters the pages by language in the parent dropdown list in the page attributes metabox.
327 *
328 * @since 0.6
329 *
330 * @param array $dropdown_args Arguments passed to wp_dropdown_pages().
331 * @param WP_Post $post The page being edited.
332 * @return array Modified arguments.
333 */
334 public function page_attributes_dropdown_pages_args( $dropdown_args, $post ) {
335 $dropdown_args['lang'] = isset( $_POST['lang'] ) ? $this->model->get_language( sanitize_key( $_POST['lang'] ) ) : $this->model->post->get_language( $post->ID ); // phpcs:ignore WordPress.Security.NonceVerification
336 if ( ! $dropdown_args['lang'] ) {
337 $dropdown_args['lang'] = $this->pref_lang;
338 }
339
340 return $dropdown_args;
341 }
342
343 /**
344 * Displays a notice if the user has not sufficient rights to overwrite synchronized taxonomies and metas.
345 *
346 * @since 2.6
347 *
348 * @param WP_Post $post the post currently being edited.
349 * @return void
350 */
351 public function edit_form_top( $post ) {
352 if ( ! $this->model->post->current_user_can_synchronize( $post->ID ) ) {
353 ?>
354 <div class="pll-notice notice notice-warning">
355 <p>
356 <?php
357 esc_html_e( 'Some taxonomies or metadata may be synchronized with existing translations that you are not allowed to modify.', 'polylang' );
358 echo ' ';
359 esc_html_e( 'If you attempt to modify them anyway, your changes will not be saved.', 'polylang' );
360 ?>
361 </p>
362 </div>
363 <?php
364 }
365 }
366 }
367