PluginProbe
TablePress – Tables in WordPress made easy / 3.2
TablePress – Tables in WordPress made easy v3.2
3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 2.4.4 All 44 releases
← All changes | models/model-table.php +150 -85 2.2.33.2 View file →
@@ -24,27 +24,24 @@
24 24 /**
25 25 * Instance of the Post Type Model.
26 26 *
27 27 * @since 1.0.0
28 - * @var TablePress_Post_Model
29 28 */
30 - protected $model_post;
29 + protected \TablePress_Post_Model $model_post;
31 30
32 31 /**
33 32 * Name of the Post Meta Field for table options.
34 33 *
35 34 * @since 1.0.0
36 - * @var string
37 35 */
38 - protected $table_options_field_name = '_tablepress_table_options';
36 + protected string $table_options_field_name = '_tablepress_table_options';
39 37
40 38 /**
41 39 * Name of the Post Meta Field for table visibility.
42 40 *
43 41 * @since 1.0.0
44 - * @var string
45 42 */
46 - protected $table_visibility_field_name = '_tablepress_table_visibility';
43 + protected string $table_visibility_field_name = '_tablepress_table_visibility';
47 44
48 45 /**
49 46 * Default set of tables.
50 47 *
@@ -53,9 +50,9 @@
53 50 * @type int $last_id Last table ID that was given to a new table.
54 51 * @type array<string, int> $table_post Connections between table ID and post ID (key: table ID, value: post ID).
55 52 * }
56 53 */
57 - protected $default_tables = array(
54 + protected array $default_tables = array(
58 55 'last_id' => 0,
59 56 'table_post' => array(),
60 57 );
61 58
@@ -62,11 +59,10 @@
62 59 /**
63 60 * Instance of WP_Option class for the list of tables.
64 61 *
65 62 * @since 1.0.0
66 - * @var TablePress_WP_Option
67 63 */
68 - protected $tables;
64 + protected \TablePress_WP_Option $tables;
69 65
70 66 /**
71 67 * Init the Table model by instantiating a Post model and loading the list of tables option.
72 68 *
@@ -114,11 +110,8 @@
114 110 * @param int $post_id Post ID of an existing table, or -1 for a new table.
115 111 * @return array<string, mixed> Post.
116 112 */
117 113 protected function _table_to_post( array $table, int $post_id ): array {
118 - // Run filters on content in each cell and other fields.
119 - $table = $this->filter_content( $table );
120 -
121 114 // Sanitize each cell, table name, and table description, if the user is not allowed to work with unfiltered HTML.
122 115 if ( ! current_user_can( 'unfiltered_html' ) ) {
123 116 $table = $this->sanitize( $table );
124 117 }
@@ -188,9 +181,9 @@
188 181 * @param bool $load_data Whether the table data shall be loaded.
189 182 * @param bool $load_options_visibility Whether the table options and table visibility shall be loaded.
190 183 * @return array<string, mixed>|WP_Error Table as an array on success, WP_Error on error.
191 184 */
192 - public function load( string $table_id, bool $load_data = true, bool $load_options_visibility = true ) /* : array|WP_Post */ {
185 + public function load( string $table_id, bool $load_data = true, bool $load_options_visibility = true ) /* : array|WP_Error */ {
193 186 if ( empty( $table_id ) ) {
194 187 return new WP_Error( 'table_load_empty_table_id' );
195 188 }
196 189
@@ -232,11 +225,13 @@
232 225
233 226 // This loop now uses the WP cache.
234 227 $table_ids = array();
235 228 foreach ( $table_post as $table_id => $post_id ) {
236 - $table_id = (string) $table_id;
229 + $table_id = (string) $table_id; // Ensure that the table ID is a string, as it comes from an array key where numeric strings are converted to integers.
230 +
237 231 // Load table without data and options to save memory.
238 232 $table = $this->load( $table_id, false, false );
233 +
239 234 // Skip tables that could not be loaded properly.
240 235 if ( ! is_wp_error( $table ) ) {
241 236 $table_ids[] = $table_id;
242 237 }
@@ -281,47 +276,8 @@
281 276 return $table;
282 277 }
283 278
284 279 /**
285 - * Filter/modify the content of table cells and other fields, e.g. for security hardening.
286 - *
287 - * This is similar to the `sanitize()` method, but executed for all users.
288 - * In 1.10.0, adding `rel="noopener noreferrer"` to all HTML link elements like `<a target=` was added. See https://core.trac.wordpress.org/ticket/43187.
289 - * Since 1.13.0, and on WP 5.6, only `rel="noopener"` is added. See https://core.trac.wordpress.org/ticket/49558.
290 - *
291 - * @since 1.10.0
292 - *
293 - * @param array<string, mixed> $table Table.
294 - * @return array<string, mixed> Filtered/modified table.
295 - */
296 - public function filter_content( array $table ): array {
297 - /**
298 - * Filters whether the contents of table cells and fields should be filtered/modified.
299 - *
300 - * @since 1.10.0
301 - *
302 - * @param bool $filter Whether to filter the content of table cells and other fields. Default true.
303 - */
304 - if ( ! apply_filters( 'tablepress_filter_table_cell_content', true ) ) {
305 - return $table;
306 - }
307 -
308 - // Filter the table name and description.
309 - $fields = array( 'name', 'description' );
310 - foreach ( $fields as $field ) {
311 - $table[ $field ] = wp_targeted_link_rel( $table[ $field ] );
312 - }
313 -
314 - foreach ( $table['data'] as $row_idx => $row ) {
315 - foreach ( $row as $column_idx => $cell_content ) {
316 - $table['data'][ $row_idx ][ $column_idx ] = wp_targeted_link_rel( $cell_content );
317 - }
318 - }
319 -
320 - return $table;
321 - }
322 -
323 - /**
324 280 * Save a table.
325 281 *
326 282 * @since 1.0.0
327 283 *
@@ -332,8 +288,17 @@
332 288 if ( empty( $table['id'] ) ) {
333 289 return new WP_Error( 'table_save_empty_table_id' );
334 290 }
335 291
292 + /**
293 + * Fires before a table is saved.
294 + *
295 + * @since 3.1.0
296 + *
297 + * @param string $table_id ID of the table to be saved.
298 + */
299 + do_action( 'tablepress_event_pre_save_table', $table['id'] );
300 +
336 301 $post_id = $this->_get_post_id( $table['id'] );
337 302 if ( false === $post_id ) {
338 303 return new WP_Error( 'table_save_no_post_id_for_table_id', '', $table['id'] );
339 304 }
@@ -370,9 +335,9 @@
370 335 * Fires after a table has been saved.
371 336 *
372 337 * @since 1.5.0
373 338 *
374 - * @param string $table_id ID of the added table.
339 + * @param string $table_id ID of the saved table.
375 340 */
376 341 do_action( 'tablepress_event_saved_table', $table['id'] );
377 342
378 343 return $table['id'];
@@ -488,10 +453,21 @@
488 453 if ( ! $this->table_exists( $table_id ) ) {
489 454 return new WP_Error( 'table_delete_table_does_not_exist', '', $table_id );
490 455 }
491 456
457 + /**
458 + * Fires before a table is deleted.
459 + *
460 + * @since 3.1.0
461 + *
462 + * @param string $table_id ID of the table to be deleted.
463 + */
464 + do_action( 'tablepress_event_pre_delete_table', $table_id );
465 +
492 466 $post_id = $this->_get_post_id( $table_id ); // No ! false check necessary, as this is covered by table_exists() check above.
493 - $deleted = $this->model_post->delete( $post_id ); // Post Meta fields will be deleted automatically by that function. // @phpstan-ignore-line .
467 +
468 + // @phpstan-ignore argument.type
469 + $deleted = $this->model_post->delete( $post_id ); // Post Meta fields will be deleted automatically by that function.
494 470 if ( false === $deleted ) {
495 471 return new WP_Error( 'table_delete_post_could_not_be_deleted', '', $post_id );
496 472 }
497 473
@@ -526,11 +502,13 @@
526 502 return;
527 503 }
528 504
529 505 foreach ( $tables['table_post'] as $table_id => $post_id ) {
530 - $table_id = (string) $table_id;
506 + $table_id = (string) $table_id; // Ensure that the table ID is a string, as it comes from an array key where numeric strings are converted to integers.
507 +
531 508 $this->model_post->delete( $post_id ); // Post Meta fields will be deleted automatically by that function.
532 509 unset( $tables['table_post'][ $table_id ] );
510 +
533 511 // Invalidate table output caches that belong to this table.
534 512 $this->invalidate_table_output_cache( $table_id );
535 513 }
536 514
@@ -650,13 +628,13 @@
650 628 }
651 629
652 630 // Kinsta.
653 631 if ( isset( $GLOBALS['kinsta_cache'] ) && ! empty( $GLOBALS['kinsta_cache']->kinsta_cache_purge ) && is_callable( array( $GLOBALS['kinsta_cache']->kinsta_cache_purge, 'purge_complete_caches' ) ) ) {
654 - $GLOBALS['kinsta_cache']->kinsta_cache_purge->purge_complete_caches(); // @phpstan-ignore-line
632 + $GLOBALS['kinsta_cache']->kinsta_cache_purge->purge_complete_caches(); // @phpstan-ignore method.nonObject
655 633 }
656 634 // LiteSpeed Cache.
657 635 if ( is_callable( array( 'LiteSpeed_Cache_Tags', 'add_purge_tag' ) ) ) {
658 - LiteSpeed_Cache_Tags::add_purge_tag( '*' ); // @phpstan-ignore-line
636 + LiteSpeed_Cache_Tags::add_purge_tag( '*' ); // @phpstan-ignore class.notFound
659 637 }
660 638 // Pagely.
661 639 if ( class_exists( 'PagelyCachePurge' ) ) {
662 640 $_pagely = new PagelyCachePurge();
@@ -665,23 +643,23 @@
665 643 }
666 644 }
667 645 // Pressidum.
668 646 if ( is_callable( array( 'Ninukis_Plugin', 'get_instance' ) ) ) {
669 - $_pressidum = Ninukis_Plugin::get_instance(); // @phpstan-ignore-line
647 + $_pressidum = Ninukis_Plugin::get_instance(); // @phpstan-ignore class.notFound
670 648 if ( is_callable( array( $_pressidum, 'purgeAllCaches' ) ) ) {
671 - $_pressidum->purgeAllCaches(); // @phpstan-ignore-line
649 + $_pressidum->purgeAllCaches(); // @phpstan-ignore method.nonObject
672 650 }
673 651 }
674 652 // Savvii.
675 653 if ( defined( '\Savvii\CacheFlusherPlugin::NAME_DOMAINFLUSH_NOW' ) ) {
676 - $_savvii = new \Savvii\CacheFlusherPlugin(); // @phpstan-ignore-line
654 + $_savvii = new \Savvii\CacheFlusherPlugin(); // @phpstan-ignore class.notFound
677 655 if ( is_callable( array( $_savvii, 'domainflush' ) ) ) {
678 - $_savvii->domainflush(); // @phpstan-ignore-line
656 + $_savvii->domainflush(); // @phpstan-ignore class.notFound
679 657 }
680 658 }
681 659 // WP Fastest Cache.
682 660 if ( isset( $GLOBALS['wp_fastest_cache'] ) && is_callable( array( $GLOBALS['wp_fastest_cache'], 'deleteCache' ) ) ) {
683 - $GLOBALS['wp_fastest_cache']->deleteCache( true ); // @phpstan-ignore-line
661 + $GLOBALS['wp_fastest_cache']->deleteCache( true ); // @phpstan-ignore method.nonObject
684 662 }
685 663 // WP-Optimize.
686 664 if ( function_exists( 'WP_Optimize' ) ) {
687 665 WP_Optimize()->get_page_cache()->purge();
@@ -809,10 +787,10 @@
809 787 'last_modified' => wp_date( 'Y-m-d H:i:s' ),
810 788 'author' => get_current_user_id(),
811 789 'options' => array(
812 790 'last_editor' => get_current_user_id(),
813 - 'table_head' => true,
814 - 'table_foot' => false,
791 + 'table_head' => 1,
792 + 'table_foot' => 0,
815 793 'alternating_row_colors' => true,
816 794 'row_hover' => true,
817 795 'print_name' => false,
818 796 'print_name_position' => 'above',
@@ -830,9 +808,9 @@
830 808 'datatables_scrollx' => false,
831 809 'datatables_custom_commands' => '',
832 810 ),
833 811 'visibility' => array(
834 - 'rows' => array( 1 ), // One visbile row.
812 + 'rows' => array( 1 ), // One visible row.
835 813 'columns' => array( 1 ), // One visible column.
836 814 ),
837 815 );
838 816 /**
@@ -908,9 +886,9 @@
908 886 array_walk_recursive(
909 887 $table['data'],
910 888 static function ( /* string|int|float|bool|null */ &$cell_content, int $col_idx ): void {
911 889 $cell_content = (string) $cell_content;
912 - }
890 + },
913 891 );
914 892 // Table Options.
915 893 if ( isset( $new_table['options'] ) ) { // Options are for example not set for newly added tables.
916 894 // Specials check for certain options.
@@ -925,8 +903,17 @@
925 903 if ( $new_table['options']['datatables_paginate_entries'] < 1 ) {
926 904 $new_table['options']['datatables_paginate_entries'] = 10; // Default value.
927 905 }
928 906 }
907 +
908 + // Backward compatibility: Convert boolean or numeric string "table_head" and "table_foot" options to integer.
909 + if ( isset( $new_table['options']['table_head'] ) ) {
910 + $new_table['options']['table_head'] = absint( $new_table['options']['table_head'] );
911 + }
912 + if ( isset( $new_table['options']['table_foot'] ) ) {
913 + $new_table['options']['table_foot'] = absint( $new_table['options']['table_foot'] );
914 + }
915 +
929 916 // Merge new options.
930 917 $default_table = $this->get_table_template();
931 918 $table['options'] = array_intersect_key( $table['options'], $default_table['options'] );
932 919 $new_table['options'] = array_intersect_key( $new_table['options'], $default_table['options'] );
@@ -940,8 +927,18 @@
940 927 // $table['created'] = wp_date( 'Y-m-d H:i:s' ); // We don't want this, as it would override the original datetime.
941 928 $table['last_modified'] = wp_date( 'Y-m-d H:i:s' );
942 929 $table['options']['last_editor'] = get_current_user_id();
943 930
931 + // Prevent issues if the "Custom Commands" field is not set, e.g. when non-admins have previously edited the table.
932 + if ( ! isset( $table['options']['datatables_custom_commands'] ) ) {
933 + $table['options']['datatables_custom_commands'] = '';
934 + }
935 +
936 + // Convert CSS classes and some DataTables 1.x parameters to the DataTables 2 variants.
937 + if ( '' !== $table['options']['datatables_custom_commands'] ) {
938 + $table['options']['datatables_custom_commands'] = TablePress::convert_datatables_api_data( $table['options']['datatables_custom_commands'] );
939 + }
940 +
944 941 return $table;
945 942 }
946 943
947 944 /**
@@ -954,9 +951,9 @@
954 951 * @return bool True on success, false on error.
955 952 */
956 953 protected function _add_table_options( int $post_id, array $options ): bool {
957 954 $options = wp_json_encode( $options, TABLEPRESS_JSON_OPTIONS );
958 - return $this->model_post->add_meta_field( $post_id, $this->table_options_field_name, $options ); // @phpstan-ignore-line
955 + return $this->model_post->add_meta_field( $post_id, $this->table_options_field_name, $options ); // @phpstan-ignore argument.type
959 956 }
960 957
961 958 /**
962 959 * Update the table options of a table (in a post meta field in the table's post).
@@ -968,9 +965,9 @@
968 965 * @return bool True on success, false on error.
969 966 */
970 967 protected function _update_table_options( int $post_id, array $options ): bool {
971 968 $options = wp_json_encode( $options, TABLEPRESS_JSON_OPTIONS );
972 - return $this->model_post->update_meta_field( $post_id, $this->table_options_field_name, $options ); // @phpstan-ignore-line
969 + return $this->model_post->update_meta_field( $post_id, $this->table_options_field_name, $options ); // @phpstan-ignore argument.type
973 970 }
974 971
975 972 /**
976 973 * Get the table options of a table (from a post meta field of the table's post).
@@ -984,9 +981,15 @@
984 981 $options = $this->model_post->get_meta_field( $post_id, $this->table_options_field_name );
985 982 if ( empty( $options ) ) {
986 983 return array();
987 984 }
988 - return (array) json_decode( $options, true );
985 + $options = (array) json_decode( $options, true );
986 +
987 + // Backward compatibility: Convert boolean "table_head" and "table_foot" options to integer.
988 + $options['table_head'] = absint( $options['table_head'] );
989 + $options['table_foot'] = absint( $options['table_foot'] );
990 +
991 + return $options;
989 992 }
990 993
991 994 /**
992 995 * Save the table visibility of a table (in a post meta field of the table's post).
@@ -992,15 +995,15 @@
992 995 * Save the table visibility of a table (in a post meta field of the table's post).
993 996 *
994 997 * @since 1.0.0
995 998 *
996 - * @param int $post_id Post ID.
997 - * @param array<string, array{rows: int[], columns: int[]}> $visibility Table visibility.
999 + * @param int $post_id Post ID.
1000 + * @param array{rows: int[], columns: int[]} $visibility Table visibility.
998 1001 * @return bool True on success, false on error.
999 1002 */
1000 1003 protected function _add_table_visibility( int $post_id, array $visibility ): bool {
1001 1004 $visibility = wp_json_encode( $visibility, TABLEPRESS_JSON_OPTIONS );
1002 - return $this->model_post->add_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); // @phpstan-ignore-line
1005 + return $this->model_post->add_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); // @phpstan-ignore argument.type
1003 1006 }
1004 1007
1005 1008 /**
1006 1009 * Update the table visibility of a table (in a post meta field in the table's post).
@@ -1006,15 +1009,15 @@
1006 1009 * Update the table visibility of a table (in a post meta field in the table's post).
1007 1010 *
1008 1011 * @since 1.0.0
1009 1012 *
1010 - * @param int $post_id Post ID.
1011 - * @param array<string, array{rows: int[], columns: int[]}> $visibility Table visibility.
1013 + * @param int $post_id Post ID.
1014 + * @param array{rows: int[], columns: int[]} $visibility Table visibility.
1012 1015 * @return bool True on success, false on error.
1013 1016 */
1014 1017 protected function _update_table_visibility( int $post_id, array $visibility ): bool {
1015 1018 $visibility = wp_json_encode( $visibility, TABLEPRESS_JSON_OPTIONS );
1016 - return $this->model_post->update_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); // @phpstan-ignore-line
1019 + return $this->model_post->update_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); // @phpstan-ignore argument.type
1017 1020 }
1018 1021
1019 1022 /**
1020 1023 * Get the table visibility of a table (from a post meta field of the table's post).
@@ -1021,14 +1024,17 @@
1021 1024 *
1022 1025 * @since 1.0.0
1023 1026 *
1024 1027 * @param int $post_id Post ID.
1025 - * @return array<string, array{rows: int[], columns: int[]}> Table visibility on success, empty array on error.
1028 + * @return array{rows: int[], columns: int[]} Table visibility on success, empty array on error.
1026 1029 */
1027 1030 protected function _get_table_visibility( int $post_id ): array {
1028 1031 $visibility = $this->model_post->get_meta_field( $post_id, $this->table_visibility_field_name );
1029 1032 if ( empty( $visibility ) ) {
1030 - return array();
1033 + return array(
1034 + 'rows' => array(),
1035 + 'columns' => array(),
1036 + );
1031 1037 }
1032 1038 return json_decode( $visibility, true );
1033 1039 }
1034 1040
@@ -1054,10 +1060,23 @@
1054 1060 // Get default Table with default Table Options.
1055 1061 $default_table = $this->get_table_template();
1056 1062
1057 1063 // Go through all tables (this loop now uses the WP cache).
1058 - foreach ( $table_post as $table_id => $post_id ) {
1064 + foreach ( $table_post as $post_id ) {
1059 1065 $table_options = $this->_get_table_options( $post_id );
1066 +
1067 + /**
1068 + * Filters the Table Options before they are merged with the default Table Options.
1069 + *
1070 + * @since 3.0.0
1071 + *
1072 + * @param array<string, mixed> $table_options Table Options.
1073 + * @param array<string, mixed> $default_table_options Default Table Options.
1074 + * @param bool $remove_old_options Whether old table options should be removed from the database.
1075 + * @param int $post_id Post ID of the table.
1076 + */
1077 + $table_options = apply_filters( 'tablepress_table_options_before_merge', $table_options, $default_table['options'], $remove_old_options, $post_id );
1078 +
1060 1079 if ( $remove_old_options ) {
1061 1080 // Remove old (i.e. no longer existing) Table Options.
1062 1081 $table_options = array_intersect_key( $table_options, $default_table['options'] );
1063 1082 }
@@ -1067,8 +1086,48 @@
1067 1086 }
1068 1087 }
1069 1088
1070 1089 /**
1090 + * Updates all tables' "Custom Commands" to use DataTables 2 variants instead of old DataTables 1.x CSS classes and parameters
1091 + *
1092 + * @since 3.0.0
1093 + */
1094 + public function update_custom_commands_datatables_tp30(): void {
1095 + $table_post = $this->tables->get( 'table_post' );
1096 + if ( empty( $table_post ) ) {
1097 + return;
1098 + }
1099 +
1100 + // Prime the meta cache with the table options of all tables.
1101 + update_meta_cache( 'post', array_values( $table_post ) );
1102 +
1103 + foreach ( $table_post as $table_id => $post_id ) {
1104 + $table_options = $this->_get_table_options( $post_id );
1105 +
1106 + // Fix tables where the "Custom Commands" entry is missing entirely.
1107 + if ( ! isset( $table_options['datatables_custom_commands'] ) ) {
1108 + $table_options['datatables_custom_commands'] = '';
1109 + $this->_update_table_options( $post_id, $table_options );
1110 + continue;
1111 + }
1112 +
1113 + // Nothing to do if there are no "Custom Commands".
1114 + if ( '' === $table_options['datatables_custom_commands'] ) {
1115 + continue;
1116 + }
1117 + // Run search/replace.
1118 + $old_custom_commands = $table_options['datatables_custom_commands'];
1119 + $table_options['datatables_custom_commands'] = TablePress::convert_datatables_api_data( $table_options['datatables_custom_commands'] );
1120 + // No need to save (which runs a DB query) if nothing was replaced in the "Custom Commands".
1121 + if ( $old_custom_commands === $table_options['datatables_custom_commands'] ) {
1122 + continue;
1123 + }
1124 +
1125 + $this->_update_table_options( $post_id, $table_options );
1126 + }
1127 + }
1128 +
1129 + /**
1071 1130 * Invalidate all table output caches, e.g. after a plugin update.
1072 1131 *
1073 1132 * @since 1.0.0
1074 1133 */
@@ -1078,8 +1137,9 @@
1078 1137 return;
1079 1138 }
1080 1139
1081 1140 foreach ( $table_post as $table_id => $post_id ) {
1141 + $table_id = (string) $table_id; // Ensure that the table ID is a string, as it comes from an array key where numeric strings are converted to integers.
1082 1142 $this->invalidate_table_output_cache( $table_id );
1083 1143 }
1084 1144 }
1085 1145
@@ -1197,18 +1257,23 @@
1197 1257 }
1198 1258
1199 1259 // Pretend that there is a `_tablepress_export_table_id` post meta field with the list of table IDs.
1200 1260 $key = '_tablepress_export_table_id';
1201 - $value = wxr_cdata( implode( ',', $table_ids ) ); // @phpstan-ignore-line
1202 1261
1262 + /**
1263 + * Load WP export functions.
1264 + */
1265 + require_once ABSPATH . 'wp-admin/includes/export.php'; // @phpstan-ignore requireOnce.fileNotFound (This is a WordPress core file that always exists.)
1266 + $value = wxr_cdata( implode( ',', $table_ids ) );
1267 +
1203 1268 // Hijack the filter and print extra XML code for our faked post meta field.
1204 1269 // phpcs:disable WordPress.Security.EscapeOutput.HeredocOutputNotEscaped
1205 1270 echo <<<WXR
1206 - <wp:postmeta>
1207 - <wp:meta_key>{$key}</wp:meta_key>
1208 - <wp:meta_value>{$value}</wp:meta_value>
1209 - </wp:postmeta>\n
1210 -WXR;
1271 + <wp:postmeta>
1272 + <wp:meta_key>{$key}</wp:meta_key>
1273 + <wp:meta_value>{$value}</wp:meta_value>
1274 + </wp:postmeta>\n
1275 + WXR;
1211 1276 // phpcs:enable
1212 1277
1213 1278 return $skip;
1214 1279 }