Skip to content

Commit 28a1642

Browse files
committed
Add unit test and update function to typecast directly to string
1 parent ca33f76 commit 28a1642

File tree

2 files changed

+273
-4
lines changed

2 files changed

+273
-4
lines changed

src/wp-admin/includes/export.php

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,9 +243,7 @@ function export_wp( $args = array() ) {
243243
* @return string
244244
*/
245245
function wxr_cdata( $str ) {
246-
if ( ! is_string( $str ) ) {
247-
return '';
248-
}
246+
$str = (string) $str;
249247

250248
if ( ! wp_is_valid_utf8( $str ) ) {
251249
$str = utf8_encode( $str );
@@ -631,7 +629,7 @@ function wxr_filter_postmeta( $return_me, $meta_key ) {
631629
*
632630
* @param string $post_excerpt Excerpt for the current post.
633631
*/
634-
$excerpt = wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) );
632+
$excerpt = wxr_cdata( $post->post_excerpt );
635633

636634
$is_sticky = is_sticky( $post->ID ) ? 1 : 0;
637635
?>

tests/phpunit/tests/admin/exportWp.php

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,4 +290,275 @@ private function populate_args_post_authors( array &$args, $expected_ids ) {
290290
$post_ids_key = $expected_ids[0];
291291
$args['author'] = self::$post_ids[ $post_ids_key ]['post_author'];
292292
}
293+
294+
/**
295+
* Tests that export handles posts with NULL postmeta values without fatal errors.
296+
*
297+
* @since n.e.x.t
298+
*
299+
* @ticket 64347
300+
*/
301+
public function test_export_with_null_postmeta_values() {
302+
global $wpdb;
303+
304+
$post_id = self::factory()->post->create(
305+
array(
306+
'post_title' => 'Test Post with NULL Meta',
307+
'post_content' => 'Test content',
308+
'post_type' => 'post',
309+
)
310+
);
311+
312+
// Add multiple types of postmeta values.
313+
add_post_meta( $post_id, 'string_meta', 'normal string' );
314+
add_post_meta( $post_id, 'numeric_string_meta', 123 );
315+
add_post_meta( $post_id, 'empty_string_meta', '' );
316+
add_post_meta(
317+
$post_id,
318+
'array_meta',
319+
array(
320+
'key' => 'value'
321+
)
322+
);
323+
324+
// Directly insert NULL and non-string values into postmeta.
325+
$wpdb->insert(
326+
$wpdb->postmeta,
327+
array(
328+
'post_id' => $post_id,
329+
'meta_key' => 'null_meta',
330+
'meta_value' => null,
331+
),
332+
array( '%d', '%s', '%s' )
333+
);
334+
335+
$xml = $this->get_the_export(
336+
array(
337+
'content' => 'post',
338+
)
339+
);
340+
341+
$this->assertNotFalse( $xml, 'Export should not fail with NULL postmeta values' );
342+
$this->assertGreaterThan( 0, count( $xml->channel->item ), 'Export should contain items' );
343+
344+
// Post should be present in export.
345+
$found_post = false;
346+
foreach ( $xml->channel->item as $item ) {
347+
$wp_item = $item->children( 'wp', true );
348+
if ( (int) $wp_item->post_id === $post_id ) {
349+
$found_post = true;
350+
break;
351+
}
352+
}
353+
354+
$this->assertTrue( $found_post, 'Post with NULL metadata should be included in export' );
355+
}
356+
357+
/**
358+
* Tests that export handles comments with NULL values without fatal errors.
359+
*
360+
* @since n.e.x.t
361+
*
362+
* @ticket 64347
363+
*/
364+
public function test_export_with_null_comment_values() {
365+
global $wpdb;
366+
367+
$post_id = self::factory()->post->create(
368+
array(
369+
'post_title' => 'Test Post for Comments',
370+
'post_type' => 'post',
371+
)
372+
);
373+
374+
$comment_id = self::factory()->comment->create(
375+
array(
376+
'comment_post_ID' => $post_id,
377+
'comment_content' => 'Test comment',
378+
)
379+
);
380+
381+
// Insert NULL comment meta.
382+
$wpdb->insert(
383+
$wpdb->commentmeta,
384+
array(
385+
'comment_id' => $comment_id,
386+
'meta_key' => 'null_comment_meta',
387+
'meta_value' => null,
388+
),
389+
array( '%d', '%s', '%s' )
390+
);
391+
392+
$xml = $this->get_the_export(
393+
array(
394+
'content' => 'post',
395+
)
396+
);
397+
398+
$this->assertNotFalse( $xml, 'Export should not fail with NULL comment meta values' );
399+
$this->assertGreaterThan( 0, count( $xml->channel->item ), 'Export should contain items' );
400+
}
401+
402+
/**
403+
* Tests that export handles term meta with NULL values without fatal errors.
404+
*
405+
* @since n.e.x.t
406+
*
407+
* @ticket 64347
408+
*/
409+
public function test_export_with_null_term_meta_values() {
410+
global $wpdb;
411+
412+
// Create term.
413+
$term = self::factory()->term->create(
414+
array(
415+
'taxonomy' => 'category',
416+
'name' => 'Test Category',
417+
)
418+
);
419+
420+
$post_id = self::factory()->post->create(
421+
array(
422+
'post_title' => 'Test Post with Category',
423+
'post_type' => 'post',
424+
'post_status' => 'publish',
425+
)
426+
);
427+
428+
wp_set_object_terms( $post_id, $term, 'category' );
429+
430+
// Insert NULL term meta.
431+
$wpdb->insert(
432+
$wpdb->termmeta,
433+
array(
434+
'term_id' => $term,
435+
'meta_key' => 'null_term_meta',
436+
'meta_value' => null,
437+
),
438+
array( '%d', '%s', '%s' )
439+
);
440+
441+
$xml = $this->get_the_export(
442+
array(
443+
'content' => 'all',
444+
)
445+
);
446+
447+
$this->assertNotFalse( $xml, 'Export should not fail with NULL term meta values' );
448+
$this->assertGreaterThan( 0, count( $xml->channel->item ), 'Export should contain items' );
449+
}
450+
451+
/**
452+
* Tests that export handles posts with NULL title and content without fatal errors.
453+
*
454+
* @since n.e.x.t
455+
*
456+
* @ticket 64347
457+
*/
458+
public function test_export_with_null_post_fields() {
459+
global $wpdb;
460+
461+
// Create a post first.
462+
$post_id = self::factory()->post->create(
463+
array(
464+
'post_title' => 'Test Post',
465+
'post_content' => 'Test content',
466+
'post_type' => 'post',
467+
)
468+
);
469+
470+
// Update to set NULL values directly (bypassing WordPress API).
471+
$wpdb->update(
472+
$wpdb->posts,
473+
array(
474+
'post_excerpt' => null,
475+
),
476+
array( 'ID' => $post_id ),
477+
array( '%s' ),
478+
array( '%d' )
479+
);
480+
481+
$xml = $this->get_the_export(
482+
array(
483+
'content' => 'post',
484+
)
485+
);
486+
487+
$this->assertNotFalse( $xml, 'Export should not fail with NULL post fields' );
488+
$this->assertGreaterThan( 0, count( $xml->channel->item ), 'Export should contain items' );
489+
490+
// Verify the post is in the export.
491+
$found_post = false;
492+
foreach ( $xml->channel->item as $item ) {
493+
$wp_item = $item->children( 'wp', true );
494+
if ( (int) $wp_item->post_id === $post_id ) {
495+
$found_post = true;
496+
break;
497+
}
498+
}
499+
500+
$this->assertTrue( $found_post, 'Post with NULL excerpt should be included in export' );
501+
}
502+
503+
/**
504+
* Tests that export handles user fields with potential NULL values.
505+
*
506+
* @since n.e.x.t
507+
*
508+
* @ticket 64347
509+
*/
510+
public function test_export_with_users_having_empty_fields() {
511+
global $wpdb;
512+
513+
$user_id = self::factory()->user->create(
514+
array(
515+
'user_login' => 'testuser_export',
516+
'user_email' => '[email protected]',
517+
'first_name' => '',
518+
'last_name' => '',
519+
'display_name' => 'Test User',
520+
)
521+
);
522+
523+
$post_id = self::factory()->post->create(
524+
array(
525+
'post_title' => 'Post by User with Empty Fields',
526+
'post_author' => $user_id,
527+
'post_type' => 'post',
528+
)
529+
);
530+
531+
$wpdb->update(
532+
$wpdb->users,
533+
array(
534+
'display_name' => null,
535+
),
536+
array( 'ID' => $user_id ),
537+
array( '%s'),
538+
array( '%d' )
539+
);
540+
541+
clean_user_cache( $user_id );
542+
543+
$xml = $this->get_the_export(
544+
array(
545+
'content' => 'post',
546+
)
547+
);
548+
549+
$this->assertNotFalse( $xml, 'Export should not fail with users having empty name fields' );
550+
551+
// Check that the author is in the export.
552+
$authors = $xml->channel->children( 'wp', true );
553+
$found_author = false;
554+
555+
foreach ( $authors as $author ) {
556+
if ( isset( $author->author_id ) && (int) $author->author_id === $user_id ) {
557+
$found_author = true;
558+
break;
559+
}
560+
}
561+
562+
$this->assertTrue( $found_author, 'User with empty name fields should be included in export' );
563+
}
293564
}

0 commit comments

Comments
 (0)