PluginProbe
Polylang / 3.3.2
Polylang v3.3.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.3.2, at admin/admin-classic-editor.php

363 lines 10.8 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|null
19 */
20 public $links;
21
22 /**
23 * Current language (used to filter the content).
24 *
25 * @var PLL_Language|null
26 */
27 public $curlang;
28
29 /**
30 * Preferred language to assign to new contents.
31 *
32 * @var PLL_Language|null
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( 'The request is missing the parameter "post_type", "lang" and/or "post_id".' );
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_slug = sanitize_key( $_POST['lang'] );
168 $lang = $this->model->get_language( $lang_slug );
169 $post_type = sanitize_key( $_POST['post_type'] );
170
171 if ( empty( $lang ) ) {
172 wp_die( esc_html( "{$lang_slug} is not a valid language code." ) );
173 }
174
175 $post_type_object = get_post_type_object( $post_type );
176
177 if ( empty( $post_type_object ) ) {
178 wp_die( esc_html( "{$post_type} is not a valid post type." ) );
179 }
180
181 if ( ! current_user_can( $post_type_object->cap->edit_post, $post_ID ) ) {
182 wp_die( 'You are not allowed to edit this post.' );
183 }
184
185 $this->model->post->update_language( $post_ID, $lang );
186
187 ob_start();
188 if ( 'attachment' === $post_type ) {
189 include __DIR__ . '/view-translations-media.php';
190 } else {
191 include __DIR__ . '/view-translations-post.php';
192 }
193 $x = new WP_Ajax_Response( array( 'what' => 'translations', 'data' => ob_get_contents() ) );
194 ob_end_clean();
195
196 // Categories
197 if ( isset( $_POST['taxonomies'] ) ) { // Not set for pages
198 $supplemental = array();
199
200 foreach ( array_map( 'sanitize_key', $_POST['taxonomies'] ) as $taxname ) {
201 $taxonomy = get_taxonomy( $taxname );
202
203 if ( ! empty( $taxonomy ) ) {
204 ob_start();
205 $popular_ids = wp_popular_terms_checklist( $taxonomy->name );
206 $supplemental['populars'] = ob_get_contents();
207 ob_end_clean();
208
209 ob_start();
210 // Use $post_ID to remember checked terms in case we come back to the original language
211 wp_terms_checklist( $post_ID, array( 'taxonomy' => $taxonomy->name, 'popular_cats' => $popular_ids ) );
212 $supplemental['all'] = ob_get_contents();
213 ob_end_clean();
214
215 $supplemental['dropdown'] = wp_dropdown_categories(
216 array(
217 'taxonomy' => $taxonomy->name,
218 'hide_empty' => 0,
219 'name' => 'new' . $taxonomy->name . '_parent',
220 'orderby' => 'name',
221 'hierarchical' => 1,
222 'show_option_none' => '&mdash; ' . $taxonomy->labels->parent_item . ' &mdash;',
223 'echo' => 0,
224 )
225 );
226
227 $x->Add( array( 'what' => 'taxonomy', 'data' => $taxonomy->name, 'supplemental' => $supplemental ) );
228 }
229 }
230 }
231
232 // Parent dropdown list ( only for hierarchical post types )
233 if ( in_array( $post_type, get_post_types( array( 'hierarchical' => true ) ) ) ) {
234 $post = get_post( $post_ID );
235
236 if ( ! empty( $post ) ) {
237 // Args and filter from 'page_attributes_meta_box' in wp-admin/includes/meta-boxes.php of WP 4.2.1
238 $dropdown_args = array(
239 'post_type' => $post->post_type,
240 'exclude_tree' => $post->ID,
241 'selected' => $post->post_parent,
242 'name' => 'parent_id',
243 'show_option_none' => __( '(no parent)', 'polylang' ),
244 'sort_column' => 'menu_order, post_title',
245 'echo' => 0,
246 );
247
248 /** This filter is documented in wp-admin/includes/meta-boxes.php */
249 $dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post ); // Since WP 3.3
250
251 $x->Add( array( 'what' => 'pages', 'data' => wp_dropdown_pages( $dropdown_args ) ) ); // phpcs:ignore WordPress.Security.EscapeOutput
252 }
253 }
254
255 // Flag
256 $x->Add( array( 'what' => 'flag', 'data' => empty( $lang->flag ) ? esc_html( $lang->slug ) : $lang->flag ) );
257
258 // Sample permalink
259 $x->Add( array( 'what' => 'permalink', 'data' => get_sample_permalink_html( $post_ID ) ) );
260
261 $x->send();
262 }
263
264 /**
265 * Ajax response for input in translation autocomplete input box
266 *
267 * @since 1.5
268 *
269 * @return void
270 */
271 public function ajax_posts_not_translated() {
272 check_ajax_referer( 'pll_language', '_pll_nonce' );
273
274 if ( ! isset( $_GET['post_type'], $_GET['post_language'], $_GET['translation_language'], $_GET['term'], $_GET['pll_post_id'] ) ) {
275 wp_die( 0 );
276 }
277
278 $post_type = sanitize_key( $_GET['post_type'] );
279
280 if ( ! post_type_exists( $post_type ) ) {
281 wp_die( 0 );
282 }
283
284 $term = wp_unslash( $_GET['term'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
285
286 $post_language = $this->model->get_language( sanitize_key( $_GET['post_language'] ) );
287 $translation_language = $this->model->get_language( sanitize_key( $_GET['translation_language'] ) );
288
289 $return = array();
290
291 $untranslated_posts = $this->model->post->get_untranslated( $post_type, $post_language, $translation_language, $term );
292
293 // format output
294 foreach ( $untranslated_posts as $post ) {
295 $return[] = array(
296 'id' => $post->ID,
297 'value' => $post->post_title,
298 'link' => $this->links->edit_post_translation_link( $post->ID ),
299 );
300 }
301
302 // Add current translation in list
303 if ( $post_id = $this->model->post->get_translation( (int) $_GET['pll_post_id'], $translation_language ) ) {
304 $post = get_post( $post_id );
305
306 if ( ! empty( $post ) ) {
307 array_unshift(
308 $return,
309 array(
310 'id' => $post_id,
311 'value' => $post->post_title,
312 'link' => $this->links->edit_post_translation_link( $post_id ),
313 )
314 );
315 }
316 }
317
318 wp_die( wp_json_encode( $return ) );
319 }
320
321 /**
322 * Filters the pages by language in the parent dropdown list in the page attributes metabox.
323 *
324 * @since 0.6
325 *
326 * @param array $dropdown_args Arguments passed to wp_dropdown_pages().
327 * @param WP_Post $post The page being edited.
328 * @return array Modified arguments.
329 */
330 public function page_attributes_dropdown_pages_args( $dropdown_args, $post ) {
331 $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
332 if ( ! $dropdown_args['lang'] ) {
333 $dropdown_args['lang'] = $this->pref_lang;
334 }
335
336 return $dropdown_args;
337 }
338
339 /**
340 * Displays a notice if the user has not sufficient rights to overwrite synchronized taxonomies and metas.
341 *
342 * @since 2.6
343 *
344 * @param WP_Post $post the post currently being edited.
345 * @return void
346 */
347 public function edit_form_top( $post ) {
348 if ( ! $this->model->post->current_user_can_synchronize( $post->ID ) ) {
349 ?>
350 <div class="pll-notice notice notice-warning">
351 <p>
352 <?php
353 esc_html_e( 'Some taxonomies or metadata may be synchronized with existing translations that you are not allowed to modify.', 'polylang' );
354 echo ' ';
355 esc_html_e( 'If you attempt to modify them anyway, your changes will not be saved.', 'polylang' );
356 ?>
357 </p>
358 </div>
359 <?php
360 }
361 }
362 }
363