PluginProbe
Polylang / 2.0.5
Polylang v2.0.5
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.0.5, at settings/table-string.php

335 lines 10.0 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 * Sort items
140 *
141 * @since 0.6
142 *
143 * @param object $a The first object to compare
144 * @param object $b The second object to compare
145 * @return int -1 or 1 if $a is considered to be respectively less than or greater than $b.
146 */
147 protected function usort_reorder( $a, $b ) {
148 $result = strcmp( $a[ $_GET['orderby'] ], $b[ $_GET['orderby'] ] ); // determine sort order
149 return ( empty( $_GET['order'] ) || 'asc' === $_GET['order'] ) ? $result : -$result; // send final sort direction to usort
150 }
151
152 /**
153 * Prepares the list of items for displaying
154 *
155 * @since 0.6
156 */
157 function prepare_items() {
158 $data = $this->strings;
159
160 // Filter for search string
161 $s = empty( $_GET['s'] ) ? '' : wp_unslash( $_GET['s'] );
162 foreach ( $data as $key => $row ) {
163 if ( ( -1 !== $this->selected_group && $row['context'] !== $this->selected_group ) || ( ! empty( $s ) && stripos( $row['name'], $s ) === false && stripos( $row['string'], $s ) === false ) ) {
164 unset( $data[ $key ] );
165 }
166 }
167
168 // Load translations
169 foreach ( $this->languages as $language ) {
170 // Filters by language if requested
171 if ( ( $lg = get_user_meta( get_current_user_id(), 'pll_filter_content', true ) ) && $language->slug !== $lg ) {
172 continue;
173 }
174
175 $mo = new PLL_MO();
176 $mo->import_from_db( $language );
177 foreach ( $data as $key => $row ) {
178 $data[ $key ]['translations'][ $language->slug ] = $mo->translate( $row['string'] );
179 $data[ $key ]['row'] = $key; // Store the row number for convenience
180 }
181 }
182
183 $per_page = $this->get_items_per_page( 'pll_strings_per_page' );
184 $this->_column_headers = array( $this->get_columns(), array(), $this->get_sortable_columns() );
185
186 if ( ! empty( $_GET['orderby'] ) ) { // No sort by default
187 usort( $data, array( $this, 'usort_reorder' ) );
188 }
189
190 $total_items = count( $data );
191 $this->items = array_slice( $data, ( $this->get_pagenum() - 1 ) * $per_page, $per_page );
192
193 $this->set_pagination_args( array(
194 'total_items' => $total_items,
195 'per_page' => $per_page,
196 'total_pages' => ceil( $total_items / $per_page ),
197 ) );
198 }
199
200 /**
201 * Get the list of possible bulk actions
202 *
203 * @since 1.1
204 *
205 * @return array
206 */
207 function get_bulk_actions() {
208 return array( 'delete' => __( 'Delete','polylang' ) );
209 }
210
211 /**
212 * Get the current action selected from the bulk actions dropdown.
213 * overrides parent function to avoid submit button to trigger bulk actions
214 *
215 * @since 1.8
216 *
217 * @return string|false The action name or False if no action was selected
218 */
219 public function current_action() {
220 return empty( $_POST['submit'] ) ? parent::current_action() : false;
221 }
222
223 /**
224 * Displays the dropdown list to filter strings per group
225 *
226 * @since 1.1
227 *
228 * @param string $which only 'top' is supported
229 */
230 function extra_tablenav( $which ) {
231 if ( 'top' !== $which ) {
232 return;
233 }
234
235 echo '<div class="alignleft actions">';
236 printf(
237 '<label class="screen-reader-text" for="select-group" >%s</label>',
238 /* translators: accessibility text */
239 esc_html__( 'Filter by group', 'polylang' )
240 );
241 echo '<select id="select-group" name="group">' . "\n";
242 printf(
243 '<option value="-1"%s>%s</option>' . "\n",
244 -1 === $this->group_selected ? ' selected="selected"' : '',
245 esc_html__( 'View all groups', 'polylang' )
246 );
247
248 foreach ( $this->groups as $group ) {
249 printf(
250 '<option value="%s"%s>%s</option>' . "\n",
251 esc_attr( urlencode( $group ) ),
252 $this->selected_group === $group ? ' selected="selected"' : '',
253 esc_html( $group )
254 );
255 }
256 echo '</select>'."\n";
257
258 submit_button( __( 'Filter' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
259 echo '</div>';
260 }
261
262 /**
263 * Saves the strings translations in DB
264 * Optionaly clean the DB
265 *
266 * @since 1.9
267 */
268 public function save_translations() {
269 check_admin_referer( 'string-translation', '_wpnonce_string-translation' );
270
271 if ( ! empty( $_POST['submit'] ) ) {
272 foreach ( $this->languages as $language ) {
273 if ( empty( $_POST['translation'][ $language->slug ] ) ) { // In case the language filter is active ( thanks to John P. Bloch )
274 continue;
275 }
276
277 $mo = new PLL_MO();
278 $mo->import_from_db( $language );
279
280 foreach ( $_POST['translation'][ $language->slug ] as $key => $translation ) {
281 /**
282 * Filter the string translation before it is saved in DB
283 * Allows to sanitize strings registered with pll_register_string
284 *
285 * @since 1.6
286 *
287 * @param string $translation the string translation
288 * @param string $name the name as defined in pll_register_string
289 * @param string $context the context as defined in pll_register_string
290 */
291 $translation = apply_filters( 'pll_sanitize_string_translation', $translation, $this->strings[ $key ]['name'], $this->strings[ $key ]['context'] );
292 $mo->add_entry( $mo->make_entry( $this->strings[ $key ]['string'], $translation ) );
293 }
294
295 // Clean database ( removes all strings which were registered some day but are no more )
296 if ( ! empty( $_POST['clean'] ) ) {
297 $new_mo = new PLL_MO();
298
299 foreach ( $this->strings as $string ) {
300 $new_mo->add_entry( $mo->make_entry( $string['string'], $mo->translate( $string['string'] ) ) );
301 }
302 }
303
304 isset( $new_mo ) ? $new_mo->export_to_db( $language ) : $mo->export_to_db( $language );
305 }
306
307 add_settings_error( 'general', 'pll_strings_translations_updated', __( 'Translations updated.', 'polylang' ), 'updated' );
308
309 /**
310 * Fires after the strings translations are saved in DB
311 *
312 * @since 1.2
313 */
314 do_action( 'pll_save_strings_translations' );
315 }
316
317 // Unregisters strings registered through WPML API
318 if ( $this->current_action() === 'delete' && ! empty( $_POST['strings'] ) && function_exists( 'icl_unregister_string' ) ) {
319 foreach ( $_POST['strings'] as $key ) {
320 icl_unregister_string( $this->strings[ $key ]['context'], $this->strings[ $key ]['name'] );
321 }
322 }
323
324 // To refresh the page ( possible thanks to the $_GET['noheader']=true )
325 $args = array_intersect_key( $_REQUEST, array_flip( array( 's', 'paged', 'group' ) ) );
326 if ( ! empty( $_GET['paged'] ) && ! empty( $_POST['submit'] ) ) {
327 $args['paged'] = (int) $_GET['paged']; // Don't rely on $_REQUEST['paged'] or $_POST['paged']. See #14
328 }
329 if ( ! empty( $args['s'] ) ) {
330 $args['s'] = urlencode( $args['s'] ); // Searched string needs to be encoded as it comes from $_POST
331 }
332 PLL_Settings::redirect( $args );
333 }
334 }
335