$post_type, 'field' => $meta_key); } function wpbr_render_new_batch_page() { if (!current_user_can('manage_options')) return; // Creating a batch is wpbr_handle_new_batch_post(), on `load-{page}`. It must not live here: // by the time this function runs the admin header has been printed and a redirect is impossible. // The first-run screen offers to start a batch already pointed at a field it // found. Carried as hidden fields rather than kept in the session, so the // form still says everything it is about to do. // // THE ARGUMENTS ARE NAMESPACED BECAUSE `post_type` BELONGS TO CORE. wp-admin/admin.php reads it while it resolves an admin screen, and // when it names a registered post type core looks the plugin page up under `admin.php?post_type=...` instead of `admin.php`, finds no // page there and ends the request with "Cannot load wpbr-new-batch." before this function runs. The first-run screen's "Start a // batch" links carried exactly that and were a dead end on a real site for every post type that exists (reproduced on WordPress 7). // The old names are still read, for a link made before the change whose post type core does not know. $preset = wpbr_requested_preset(); $preset_type = $preset['post_type']; $preset_key = $preset['field']; if ($preset_type !== '' && !post_type_exists($preset_type)) { $preset_type = ''; $preset_key = ''; } echo "
"; wpbr_help_link_echo('core.batches.create', __('Starting a batch', 'wpbr-bulk-replace')); echo "
"; echo ""; echo "" . esc_html__('You will upload files and set up matching on the next screen.', 'wpbr-bulk-replace') . "
"; echo ""; wpbr_help_link_echo('core.batches.overview', __('What a batch is', 'wpbr-bulk-replace')); echo "
"; if (!$batches) { wpbr_render_first_run(); echo "" . esc_html__('Add New Batch', 'wpbr-bulk-replace') . "
"; echo "| " . esc_html__('ID', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Label', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Post type', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Meta field', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Files', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Progress', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Created', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('By', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Actions', 'wpbr-bulk-replace') . " | "; echo "
|---|---|---|---|---|---|---|---|---|
| ".esc_html(number_format_i18n($b->id))." | "; echo "".esc_html($b->label)." | "; echo "".esc_html($b->post_type ? wpbr_post_type_display($b->post_type) : $not_set)." | "; echo "".esc_html($b->meta_key_name ? $b->meta_key_name : $not_set)." | "; echo "".esc_html(number_format_i18n($b->item_count))." | "; $done = (int) $b->done; $todo = (int) $b->to_do; $review = (int) $b->needs_review; $total = $done + $todo; echo "";
if ($total > 0) {
$pct = (int) round(($done / $total) * 100);
// The bar is a picture of the sentence beneath it, so it is hidden
// rather than announced twice.
echo "";
echo "";
echo esc_html(sprintf(
/* translators: 1: number of files processed, 2: total number of files. */
__('%1$s of %2$s done', 'wpbr-bulk-replace'),
number_format_i18n($done), number_format_i18n($total)
));
if ($review) {
echo " · " . esc_html(sprintf(
/* translators: %s is a number of files. */
_n('%s needs review', '%s need review', $review, 'wpbr-bulk-replace'),
number_format_i18n($review)
));
}
$aside = array();
if ((int) $b->skipped) {
/* translators: %s is a number of files. */
$aside[] = sprintf(_n('%s skipped', '%s skipped', (int) $b->skipped, 'wpbr-bulk-replace'), number_format_i18n($b->skipped));
}
if ((int) $b->combined) {
/* translators: %s is a number of files merged into another file. */
$aside[] = sprintf(_n('%s merged', '%s merged', (int) $b->combined, 'wpbr-bulk-replace'), number_format_i18n($b->combined));
}
if ((int) $b->new_page) {
/* translators: %s is a number of files with no post to attach to yet. */
$aside[] = sprintf(_n('%s needs a page', '%s need a page', (int) $b->new_page, 'wpbr-bulk-replace'), number_format_i18n($b->new_page));
}
if ($aside) echo " ".esc_html(implode(', ', $aside)); echo ""; } elseif ($review) { echo "" . esc_html(sprintf( /* translators: %s is a number of files. */ _n('%s needs review', '%s need review', $review, 'wpbr-bulk-replace'), number_format_i18n($review) )) . ""; } else { echo "" . esc_html__('Not started', 'wpbr-bulk-replace') . ""; } if ((int) $b->needs_attention) { // A file that could not be put back after a failed replacement. Stated plainly and in words, not colour alone. echo " " . esc_html(sprintf( /* translators: %s is a number of files. */ _n('%s file needs attention', '%s files need attention', (int) $b->needs_attention, 'wpbr-bulk-replace'), number_format_i18n((int) $b->needs_attention) )) . ""; } echo " | ";
echo ""
. esc_html(mysql2date(get_option('date_format', 'M j, Y'), $b->created_at))
. " " . esc_html(mysql2date(get_option('time_format', 'g:i a'), $b->created_at)) . " | ";
echo ""; if (!empty($b->actor) && wpbr_actor_label($b->actor) !== '') { echo "created_by))."\">".esc_html(wpbr_actor_label($b->actor)).""; } elseif ($b->created_by) { echo "created_by))."\">".esc_html(wpbr_user_label($b->created_by)).""; } else { echo "—" . esc_html__('Unknown', 'wpbr-bulk-replace') . ""; } echo " | "; $del_url = wp_nonce_url( admin_url('admin.php?page=wpbr-batches&wpbr_delete='.$b->id), 'wpbr_delete_batch_'.$b->id, 'wpbr_del_nonce' ); echo ""; // Both controls name the batch: in a list of twelve, "Open" and // "Delete this batch" twelve times over identify nothing. echo "label )) . "\">" . esc_html__('Open', 'wpbr-bulk-replace') . " "; echo "label )) . "\">"; echo " | "; echo "
" . esc_html__('A batch is one set of files you want matched to existing content and swapped in. Start one, upload your files, and the wizard takes it from there.', 'wpbr-bulk-replace') . "
"; if (!empty($scan['fields'])) { wpbr_render_first_run_fields($scan); } elseif ($scan['posts'] > 0) { wpbr_render_first_run_nothing_found($scan); } else { wpbr_render_first_run_empty_site(); } echo "" . esc_html__('Add New Batch', 'wpbr-bulk-replace') . " "; echo "" . esc_html__('Read how it works first', 'wpbr-bulk-replace') . "
"; echo "" . esc_html(sprintf( /* translators: %s is a number of meta fields. */ _n( '%s field looks like it holds files. Start a batch from it, or add one yourself.', '%s fields look like they hold files. Start a batch from one, or add one yourself.', count($scan['fields']), 'wpbr-bulk-replace' ), number_format_i18n(count($scan['fields'])) )) . "
"; echo "| " . esc_html__('Content', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Field', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Has a file', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('For example', 'wpbr-bulk-replace') . " | "; echo "" . esc_html__('Start a batch', 'wpbr-bulk-replace') . " | "; echo "
|---|---|---|---|---|
| " . esc_html(wpbr_post_type_label_title($field['post_type'])) . " | "; echo "" . esc_html($field['meta_key']) . " | ";
echo "" . esc_html(sprintf( /* translators: %s is a number of posts. */ _n('%s post', '%s posts', $field['posts'], 'wpbr-bulk-replace'), number_format_i18n($field['posts']) )) . " | "; echo "" . ($field['sample'] !== ''
? "" . esc_html($field['sample']) . ""
: "—") . " | ";
echo "" . esc_html__('Start a batch', 'wpbr-bulk-replace') . " | "; echo "
" . esc_html__('This is a guess from what the values look like, not a promise. You can pick any field at the Match step, including one that is not listed here.', 'wpbr-bulk-replace') . "
"; wpbr_render_first_run_sample_note($scan); } /** * Say so when the counts are a sample rather than a survey. * * On a large site the scan looks at the most recent posts rather than all of * them, because the alternative is a screen that does not open. A count that is * quietly of something narrower than the reader assumes is worse than no count, * so the narrowing is stated wherever the numbers are shown. */ function wpbr_render_first_run_sample_note($scan) { if (empty($scan['sampled'])) return; echo "" . esc_html(sprintf( /* translators: 1: a number of posts looked at, 2: the total number of published posts. */ __('Counted across the %1$s most recently published posts, of %2$s on the site. Looking at all of them would mean reading every custom field on the site each time this screen opens.', 'wpbr-bulk-replace'), number_format_i18n($scan['limit']), number_format_i18n($scan['posts']) )) . "
"; } /** * The site has content, and none of it has a file in a meta field. * * The most useful thing this screen can do is say so, because the alternative is * the reader finding out at the Match step after uploading their files. */ function wpbr_render_first_run_nothing_found($scan) { echo "" . esc_html__('Nothing on this site looks like a file field yet.', 'wpbr-bulk-replace') . " "; $looked_at = empty($scan['sampled']) ? (int) $scan['posts'] : (int) $scan['limit']; echo esc_html(sprintf( /* translators: %s is a number of published posts. */ _n( 'That is after looking at %s published post.', 'That is after looking at %s published posts.', $looked_at, 'wpbr-bulk-replace' ), number_format_i18n($looked_at) )) . " "; echo esc_html(sprintf( /* translators: %s is a number of post types. */ _n( 'Your site has %s post type.', 'Your site has %s post types.', $scan['types'], 'wpbr-bulk-replace' ), number_format_i18n($scan['types']) )) . "
"; echo "" . esc_html__('This plugin replaces files that your posts point at through a custom field holding a URL or a path. If your files are attached through the Media Library alone, or stored as an attachment ID rather than a URL, there is nothing here for it to match against.', 'wpbr-bulk-replace') . "
"; echo "" . esc_html__('You can still start a batch and choose any field by hand at the Match step — this is a guess, not a verdict.', 'wpbr-bulk-replace') . "
"; wpbr_render_first_run_sample_note($scan); echo "" . esc_html__('There is no published content to match files against yet. Publish the posts or pages the files belong to first, then come back — matching works by comparing filenames to the titles of published content.', 'wpbr-bulk-replace') . "
"; echo "" . esc_html(sprintf( /* translators: %s is a number of files. */ _n('Picked up %s new file from the staging folder. Files already registered to a batch were skipped.', 'Picked up %s new files from the staging folder. Files already registered to a batch were skipped.', $added, 'wpbr-bulk-replace'), number_format_i18n($added) )) . "
" . esc_html__('That batch no longer exists.', 'wpbr-bulk-replace') . "
" . wp_kses_post(sprintf( /* translators: %s is a number of file records. */ _n('This removes the batch and its %s file record from the tool. It does not undo anything already done to your site — replaced files stay replaced and created attachments stay in place.', 'This removes the batch and its %s file records from the tool. It does not undo anything already done to your site — replaced files stay replaced and created attachments stay in place.', (int) $counts->total, 'wpbr-bulk-replace'), number_format_i18n($counts->total) )) . "
"; if ((int) $counts->processed > 0) { echo "" . wp_kses_post(sprintf( /* translators: %s is a number of files. */ _n('%s file in this batch has already been processed. Once the batch is gone you lose the ability to roll it back from here, even if its backup remains on disk. If you might want to undo it, do that first.', '%s files in this batch have already been processed. Once the batch is gone you lose the ability to roll them back from here, even if their backups remain on disk. If you might want to undo any of them, do that first.', (int) $counts->processed, 'wpbr-bulk-replace'), number_format_i18n($counts->processed) )) . "
"; echo "".esc_html(implode(' ', $parts))."