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

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

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