PageRenderTime 42ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/polylang/settings/table-string.php

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