Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions features/export.feature
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,34 @@ Feature: Export content.
Error: Term is missing a parent
"""

Scenario: Export a site and skip the authors
Given a WP install

When I run `wp export --skip_authors`
Then save STDOUT 'Writing to file %s' as {EXPORT_FILE}
And the {EXPORT_FILE} file should not contain:
"""
<wp:author>
"""

Scenario: Export a site and skip the terms
Given a WP install

When I run `wp export --skip_terms`
Then save STDOUT 'Writing to file %s' as {EXPORT_FILE}
And the {EXPORT_FILE} file should not contain:
"""
<wp:term>
"""
And the {EXPORT_FILE} file should not contain:
"""
<wp:category>
"""
And the {EXPORT_FILE} file should not contain:
"""
<wp:tags>
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XML tag <wp:tags> appears to be incorrect. Based on WordPress WXR format standards, tags are typically represented as <wp:tag>, not <wp:tags> (note the singular form). This test assertion may not work as expected.

Suggested change
<wp:tags>
<wp:tag>

Copilot uses AI. Check for mistakes.
"""

@require-wp-5.2 @require-mysql
Scenario: Export posts with future status
Given a WP install
Expand Down
56 changes: 56 additions & 0 deletions src/Export_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
private $max_file_size;
private $include_once;
private $wxr_path;
private $exclude = [];

/**
* Exports WordPress content to a WXR file.
Expand All @@ -51,6 +52,12 @@
* [--skip_comments]
* : Don't include comments in the WXR export file.
*
* [--skip_authors]
* : Don't include authors in the WXR export file.
*
* [--skip_terms]
* : Don't include terms (categories, tags, custom taxonomy terms and nav menu terms) in the WXR export file.
*
* [--max_file_size=<MB>]
* : A single export file should have this many megabytes. -1 for unlimited.
* ---
Expand Down Expand Up @@ -145,6 +152,8 @@
'with_attachments' => true, // or FALSE if user requested some post__in
'start_id' => null,
'skip_comments' => null,
'skip_authors' => null,
'skip_terms' => null,
'max_file_size' => 15,
'filename_format' => '{site}.wordpress.{date}.{n}.xml',
'include_once' => null,
Expand All @@ -169,6 +178,26 @@
$defaults['with_attachments']
);

$this->export_args['skip_authors'] = Utils\get_flag_value(
$assoc_args,
'skip_authors',
$defaults['skip_authors']
);

$this->export_args['skip_terms'] = Utils\get_flag_value(
$assoc_args,
'skip_terms',
$defaults['skip_terms']
);

if ( $this->export_args['skip_authors'] ) {
$this->exclude[] = 'authors';
}

Comment on lines +193 to +196
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The --skip_terms flag excludes sections but does not update $this->export_args['skip_terms'] at the point of exclusion. The validation method check_skip_terms() (line 514-525) will set this value later during validation, but this creates a potential inconsistency if validation order changes. Additionally, the --stdout mode uses WP_Export_File_Writer which doesn't support the exclusion mechanism. When --stdout is used with --skip_authors or --skip_terms, the sections will still be included in the output since WP_Export_File_Writer calls before_posts() without parameters.

Suggested change
if ( $this->export_args['skip_authors'] ) {
$this->exclude[] = 'authors';
}
// Re-calculate exclusions after validation to ensure consistency.
$this->exclude = [];
if ( $this->export_args['skip_authors'] ) {
$this->exclude[] = 'authors';
}

Copilot uses AI. Check for mistakes.
if ( $this->export_args['skip_terms'] ) {
$this->exclude = array_merge( $this->exclude, array( 'categories', 'tags', 'nav_menu_terms', 'custom_taxonomies_terms' ) );
}

if ( ! function_exists( 'wp_export' ) ) {
self::load_export_api();
}
Expand Down Expand Up @@ -204,6 +233,7 @@
'destination_directory' => $this->wxr_path,
'filename_template' => self::get_filename_template( $assoc_args['filename_format'] ),
'include_once' => $this->include_once,
'exclude' => $this->exclude,
],
]
);
Expand Down Expand Up @@ -468,6 +498,32 @@
return true;
}

private function check_skip_authors( $skip ) {
if ( null === $skip ) {
return true;
}

if ( 0 !== (int) $skip && 1 !== (int) $skip ) {
WP_CLI::warning( 'skip_authors needs to be 0 (no) or 1 (yes).' );
return false;

Check warning on line 508 in src/Export_Command.php

View check run for this annotation

Codecov / codecov/patch

src/Export_Command.php#L507-L508

Added lines #L507 - L508 were not covered by tests
}
$this->export_args['skip_authors'] = $skip;
return true;
}

private function check_skip_terms( $skip ) {
if ( null === $skip ) {
return true;
}

if ( 0 !== (int) $skip && 1 !== (int) $skip ) {
WP_CLI::warning( 'skip_terms needs to be 0 (no) or 1 (yes).' );
return false;

Check warning on line 521 in src/Export_Command.php

View check run for this annotation

Codecov / codecov/patch

src/Export_Command.php#L520-L521

Added lines #L520 - L521 were not covered by tests
}
$this->export_args['skip_terms'] = $skip;
return true;
}

private function check_max_file_size( $size ) {
if ( ! is_numeric( $size ) ) {
WP_CLI::warning( 'max_file_size should be numeric.' );
Expand Down
11 changes: 10 additions & 1 deletion src/WP_Export_Split_Files_Writer.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,18 @@ public function __construct( $formatter, $writer_args = [] ) {
$this->subsequent_sections = array_diff( $this->available_sections, $writer_args['include_once'] );
}

if ( ! empty( $writer_args['exclude'] ) ) {
foreach ( $writer_args['exclude'] as $exclude ) {
$key = array_search( $exclude, $this->available_sections, true );
if ( false !== $key ) {
unset( $this->available_sections[ $key ] );
}
}
}
Comment on lines +48 to +55
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exclusion logic removes sections from $this->available_sections after it has already been used to calculate $this->subsequent_sections (line 45). This means excluded sections will still be present in subsequent files when using --include_once. The exclusion logic should be moved before line 44 to ensure excluded sections are properly removed from both $this->available_sections and $this->subsequent_sections.

Copilot uses AI. Check for mistakes.

$this->destination_directory = $writer_args['destination_directory'];
$this->filename_template = $writer_args['filename_template'];
$this->before_posts_xml = $this->formatter->before_posts();
$this->before_posts_xml = $this->formatter->before_posts( $this->available_sections );
$this->after_posts_xml = $this->formatter->after_posts();
}

Expand Down