PluginProbe
Polylang / 2.3.10
Polylang v2.3.10
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 / settings / table-string.php

table-string.php in Polylang 2.3.10, at settings/table-string.php

346 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 if ( ! class_exists( 'WP_List_Table' ) ) {
4 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; // since WP 3.1
5 }
6
7 /**
8 * A class to create the strings translations table
9 * Thanks to Matt Van Andel ( http://www.mattvanandel.com ) for its plugin "Custom List Table Example" !
10 *
11 * @since 0.6
12 */
13 class PLL_Table_String extends WP_List_Table {
14 protected $languages, $strings, $groups, $selected_group;
15
16 /**
17 * Constructor
18 *
19 * @since 0.6
20 *
21 * @param array $languages list of languages
22 */
23 function __construct( $languages ) {
24 parent::__construct( array(
25 'plural' => 'Strings translations', // Do not translate ( used for css class )
26 'ajax' => false,
27 ) );
28
29 $this->languages = $languages;
30 $this->strings = PLL_Admin_Strings::get_strings();
31 $this->groups = array_unique( wp_list_pluck( $this->strings, 'context' ) );
32 $this->selected_group = empty( $_GET['group'] ) || ! in_array( $_GET['group'], $this->groups ) ? -1 : $_GET['group'];
33
34 add_action( 'mlang_action_string-translation', array( $this, 'save_translations' ) );
35 }
36
37 /**
38 * Displays the item information in a column ( default case )
39 *
40 * @since 0.6
41 *
42 * @param array $item
43 * @param string $column_name
44 * @return string
45 */
46 function column_default( $item, $column_name ) {
47 return $item[ $column_name ];
48 }
49
50 /**
51 * Displays the checkbox in first column
52 *
53 * @since 1.1
54 *
55 * @param array $item
56 * @return string
57 */
58 function column_cb( $item ) {
59 return sprintf(
60 '<label class="screen-reader-text" for="cb-select-%1$s">%2$s</label><input id="cb-select-%1$s" type="checkbox" name="strings[]" value="%1$s" %3$s />',
61 esc_attr( $item['row'] ),
62 /* translators: accessibility text, %s is a string potentially in any language */
63 sprintf( __( 'Select %s' ), format_to_edit( $item['string'] ) ),
64 empty( $item['icl'] ) ? 'disabled' : '' // Only strings registered with WPML API can be removed
65 );
66 }
67
68 /**
69 * Displays the string to translate
70 *
71 * @since 1.0
72 *
73 * @param array $item
74 * @return string
75 */
76 function column_string( $item ) {
77 return format_to_edit( $item['string'] ); // Don't interpret special chars for the string column
78 }
79
80 /**
81 * Displays the translations to edit
82 *
83 * @since 0.6
84 *
85 * @param array $item
86 * @return string
87 */
88 function column_translations( $item ) {
89 $languages = array_combine( wp_list_pluck( $this->languages, 'slug' ), wp_list_pluck( $this->languages, 'name' ) );
90 $out = '';
91
92 foreach ( $item['translations'] as $key => $translation ) {
93 $input_type = $item['multiline'] ?
94 '<textarea name="translation[%1$s][%2$s]" id="%1$s-%2$s">%4$s</textarea>' :
95 '<input type="text" name="translation[%1$s][%2$s]" id="%1$s-%2$s" value="%4$s" />';
96 $out .= sprintf( '<div class="translation"><label for="%1$s-%2$s">%3$s</label>' . $input_type . '</div>' . "\n",
97 esc_attr( $key ),
98 esc_attr( $item['row'] ),
99 esc_html( $languages[ $key ] ),
100 format_to_edit( $translation ) ); // Don't interpret special chars
101 }
102
103 return $out;
104 }
105
106 /**
107 * Gets the list of columns
108 *
109 * @since 0.6
110 *
111 * @return array the list of column titles
112 */
113 function get_columns() {
114 return array(
115 'cb' => '<input type="checkbox" />', // Checkbox
116 'string' => esc_html__( 'String', 'polylang' ),
117 'name' => esc_html__( 'Name', 'polylang' ),
118 'context' => esc_html__( 'Group', 'polylang' ),
119 'translations' => esc_html__( 'Translations', 'polylang' ),
120 );
121 }
122
123 /**
124 * Gets the list of sortable columns
125 *
126 * @since 0.6
127 *
128 * @return array
129 */
130 function get_sortable_columns() {
131 return array(
132 'string' => array( 'string', false ),
133 'name' => array( 'name', false ),
134 'context' => array( 'context', false ),
135 );
136 }
137
138 /**
139 * Gets the name of the default primary column.
140 *
141 * @since 2.1
142 *
143 * @return string Name of the default primary column, in this case, 'string'.
144 */
145 protected function get_default_primary_column_name() {
146 return 'string';
147 }
148
149 /**
150 * Sort items
151 *
152 * @since 0.6
153 *
154 * @param object $a The first object to compare
155 * @param object $b The second object to compare
156 * @return int -1 or 1 if $a is considered to be respectively less than or greater than $b.
157 */
158 protected function usort_reorder( $a, $b ) {
159 $result = strcmp( $a[ $_GET['orderby'] ], $b[ $_GET['orderby'] ] ); // determine sort order
160 return ( empty( $_GET['order'] ) || 'asc' === $_GET['order'] ) ? $result : -$result; // send final sort direction to usort
161 }
162
163 /**
164 * Prepares the list of items for displaying
165 *
166 * @since 0.6
167 */
168 function prepare_items() {
169 $data = $this->strings;
170
171 // Filter for search string
172 $s = empty( $_GET['s'] ) ? '' : wp_unslash( $_GET['s'] );
173 foreach ( $data as $key => $row ) {
174 if ( ( -1 !== $this->selected_group && $row['context'] !== $this->selected_group ) || ( ! empty( $s ) && stripos( $row['name'], $s ) === false && stripos( $row['string'], $s ) === false ) ) {
175 unset( $data[ $key ] );
176 }
177 }
178
179 // Load translations
180 foreach ( $this->languages as $language ) {
181 // Filters by language if requested
182 if ( ( $lg = get_user_meta( get_current_user_id(), 'pll_filter_content', true ) ) && $language->slug !== $lg ) {
183 continue;
184 }
185
186 $mo = new PLL_MO();
187 $mo->import_from_db( $language );
188 foreach ( $data as $key => $row ) {
189 $data[ $key ]['translations'][ $language->slug ] = $mo->translate( $row['string'] );
190 $data[ $key ]['row'] = $key; // Store the row number for convenience
191 }
192 }
193
194 $per_page = $this->get_items_per_page( 'pll_strings_per_page' );
195 $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
196
197 if ( ! empty( $_GET['orderby'] ) ) { // No sort by default
198 usort( $data, array( $this, 'usort_reorder' ) );
199 }
200
201 $total_items = count( $data );
202 $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
203
204 $this->set_pagination_args( array(
205 'total_items' => $total_items,
206 'per_page' => $per_page,
207 'total_pages' => ceil( $total_items / $per_page ),
208 ) );
209 }
210
211 /**
212 * Get the list of possible bulk actions
213 *
214 * @since 1.1
215 *
216 * @return array
217 */
218 function get_bulk_actions() {
219 return array( 'delete' => __( 'Delete', 'polylang' ) );
220 }
221
222 /**
223 * Get the current action selected from the bulk actions dropdown.
224 * overrides parent function to avoid submit button to trigger bulk actions
225 *
226 * @since 1.8
227 *
228 * @return string|false The action name or False if no action was selected
229 */
230 public function current_action() {
231 return empty( $_POST['submit'] ) ? parent::current_action() : false;
232 }
233
234 /**
235 * Displays the dropdown list to filter strings per group
236 *
237 * @since 1.1
238 *
239 * @param string $which only 'top' is supported
240 */
241 function extra_tablenav( $which ) {
242 if ( 'top' !== $which ) {
243 return;
244 }
245
246 echo '<div class="alignleft actions">';
247 printf(
248 '<label class="screen-reader-text" for="select-group" >%s</label>',
249 /* translators: accessibility text */
250 esc_html__( 'Filter by group', 'polylang' )
251 );
252 echo '<select id="select-group" name="group">' . "\n";
253 printf(
254 '<option value="-1"%s>%s</option>' . "\n",
255 -1 === $this->group_selected ? ' selected="selected"' : '',
256 esc_html__( 'View all groups', 'polylang' )
257 );
258
259 foreach ( $this->groups as $group ) {
260 printf(
261 '<option value="%s"%s>%s</option>' . "\n",
262 esc_attr( urlencode( $group ) ),
263 $this->selected_group === $group ? ' selected="selected"' : '',
264 esc_html( $group )
265 );
266 }
267 echo '</select>' . "\n";
268
269 submit_button( __( 'Filter' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
270 echo '</div>';
271 }
272
273 /**
274 * Saves the strings translations in DB
275 * Optionaly clean the DB
276 *
277 * @since 1.9
278 */
279 public function save_translations() {
280 check_admin_referer( 'string-translation', '_wpnonce_string-translation' );
281
282 if ( ! empty( $_POST['submit'] ) ) {
283 foreach ( $this->languages as $language ) {
284 if ( empty( $_POST['translation'][ $language->slug ] ) ) { // In case the language filter is active ( thanks to John P. Bloch )
285 continue;
286 }
287
288 $mo = new PLL_MO();
289 $mo->import_from_db( $language );
290
291 foreach ( $_POST['translation'][ $language->slug ] as $key => $translation ) {
292 /**
293 * Filter the string translation before it is saved in DB
294 * Allows to sanitize strings registered with pll_register_string
295 *
296 * @since 1.6
297 *
298 * @param string $translation the string translation
299 * @param string $name the name as defined in pll_register_string
300 * @param string $context the context as defined in pll_register_string
301 */
302 $translation = apply_filters( 'pll_sanitize_string_translation', $translation, $this->strings[ $key ]['name'], $this->strings[ $key ]['context'] );
303 $mo->add_entry( $mo->make_entry( $this->strings[ $key ]['string'], $translation ) );
304 }
305
306 // Clean database ( removes all strings which were registered some day but are no more )
307 if ( ! empty( $_POST['clean'] ) ) {
308 $new_mo = new PLL_MO();
309
310 foreach ( $this->strings as $string ) {
311 $new_mo->add_entry( $mo->make_entry( $string['string'], $mo->translate( $string['string'] ) ) );
312 }
313 }
314
315 isset( $new_mo ) ? $new_mo->export_to_db( $language ) : $mo->export_to_db( $language );
316 }
317
318 add_settings_error( 'general', 'pll_strings_translations_updated', __( 'Translations updated.', 'polylang' ), 'updated' );
319
320 /**
321 * Fires after the strings translations are saved in DB
322 *
323 * @since 1.2
324 */
325 do_action( 'pll_save_strings_translations' );
326 }
327
328 // Unregisters strings registered through WPML API
329 if ( $this->current_action() === 'delete' && ! empty( $_POST['strings'] ) && function_exists( 'icl_unregister_string' ) ) {
330 foreach ( $_POST['strings'] as $key ) {
331 icl_unregister_string( $this->strings[ $key ]['context'], $this->strings[ $key ]['name'] );
332 }
333 }
334
335 // To refresh the page ( possible thanks to the $_GET['noheader']=true )
336 $args = array_intersect_key( $_REQUEST, array_flip( array( 's', 'paged', 'group' ) ) );
337 if ( ! empty( $_GET['paged'] ) && ! empty( $_POST['submit'] ) ) {
338 $args['paged'] = (int) $_GET['paged']; // Don't rely on $_REQUEST['paged'] or $_POST['paged']. See #14
339 }
340 if ( ! empty( $args['s'] ) ) {
341 $args['s'] = urlencode( $args['s'] ); // Searched string needs to be encoded as it comes from $_POST
342 }
343 PLL_Settings::redirect( $args );
344 }
345 }
346