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

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