PluginProbe
Polylang / 2.9
Polylang v2.9
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 2.9, at admin/admin-classic-editor.php

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