v1.2.0
This commit is contained in:
parent
6708bbb67f
commit
650e69349f
21 changed files with 2919 additions and 268 deletions
|
|
@ -218,6 +218,99 @@
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Tools & Status page
|
||||||
|
----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/* Status table */
|
||||||
|
.mra-status-table td.mra-status-dot-col {
|
||||||
|
width: 24px;
|
||||||
|
padding-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-status-table th {
|
||||||
|
white-space: nowrap;
|
||||||
|
width: 180px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-status-table td.mra-status-hint {
|
||||||
|
color: #50575e;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status indicator dots */
|
||||||
|
.mra-dot {
|
||||||
|
display: inline-block;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border-radius: 50%;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-dot-ok { background: #00a32a; }
|
||||||
|
.mra-dot-warn { background: #dba617; }
|
||||||
|
.mra-dot-error { background: #d63638; }
|
||||||
|
|
||||||
|
/* Job status labels in the scheduled-jobs row */
|
||||||
|
.mra-job-label {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WP-CLI hint below status table */
|
||||||
|
.mra-cli-hint {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-cli-hint code {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Operations section */
|
||||||
|
.mra-ops-heading {
|
||||||
|
margin-top: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-destructive-heading {
|
||||||
|
margin-top: 1.5em;
|
||||||
|
color: #b32d2e;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-ops-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16px;
|
||||||
|
margin: 12px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-op-card {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #dcdcde;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
width: 280px;
|
||||||
|
max-width: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-op-card-title {
|
||||||
|
margin: 0 0 8px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1d2327;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-op-card-desc {
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
/* Pricing reference table (settings page) */
|
/* Pricing reference table (settings page) */
|
||||||
.mra-pricing-table {
|
.mra-pricing-table {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
|
|
@ -238,6 +331,44 @@
|
||||||
border-bottom: 1px solid #dcdcde;
|
border-bottom: 1px solid #dcdcde;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -----------------------------------------------------------------------
|
||||||
|
Direct scan runner
|
||||||
|
----------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
.mra-runner-progress {
|
||||||
|
margin: 8px 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-runner-bar {
|
||||||
|
height: 8px;
|
||||||
|
background: #dcdcde;
|
||||||
|
border-radius: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-runner-bar-fill {
|
||||||
|
height: 100%;
|
||||||
|
width: 0;
|
||||||
|
background: #2271b1;
|
||||||
|
border-radius: 4px;
|
||||||
|
transition: width 0.25s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-runner-label {
|
||||||
|
display: block;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #50575e;
|
||||||
|
min-height: 1.4em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mra-runner-actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
/* Consensus block */
|
/* Consensus block */
|
||||||
.mra-consensus {
|
.mra-consensus {
|
||||||
background: #f0f8e8;
|
background: #f0f8e8;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,86 @@
|
||||||
/* global mraAdmin */
|
/* global mraAdmin, mraTools */
|
||||||
( function ( $ ) {
|
( function ( $ ) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Batch runner — Tools page
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function initRunner( type ) {
|
||||||
|
var running = false;
|
||||||
|
var stopReq = false;
|
||||||
|
|
||||||
|
var $card = $( '#mra-runner-' + type );
|
||||||
|
var $start = $card.find( '.mra-runner-start' );
|
||||||
|
var $stop = $card.find( '.mra-runner-stop' );
|
||||||
|
var $prog = $card.find( '.mra-runner-progress' );
|
||||||
|
var $fill = $card.find( '.mra-runner-bar-fill' );
|
||||||
|
var $label = $card.find( '.mra-runner-label' );
|
||||||
|
|
||||||
|
$start.on( 'click', function () {
|
||||||
|
if ( running ) { return; }
|
||||||
|
running = true;
|
||||||
|
stopReq = false;
|
||||||
|
$start.prop( 'disabled', true );
|
||||||
|
$stop.prop( 'hidden', false );
|
||||||
|
$prog.prop( 'hidden', false );
|
||||||
|
$fill.css( 'width', '0%' );
|
||||||
|
$label.text( '' );
|
||||||
|
runBatch();
|
||||||
|
} );
|
||||||
|
|
||||||
|
$stop.on( 'click', function () {
|
||||||
|
stopReq = true;
|
||||||
|
$( this ).prop( 'disabled', true );
|
||||||
|
} );
|
||||||
|
|
||||||
|
function runBatch() {
|
||||||
|
if ( stopReq ) {
|
||||||
|
finish( mraTools.i18n.stopped );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax( {
|
||||||
|
url: mraTools.ajaxUrl,
|
||||||
|
type: 'POST',
|
||||||
|
data: {
|
||||||
|
action: 'mra_run_batch',
|
||||||
|
type: type,
|
||||||
|
nonce: mraTools.nonce
|
||||||
|
},
|
||||||
|
success: function ( res ) {
|
||||||
|
if ( ! res.success ) {
|
||||||
|
finish( mraTools.i18n.error );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var d = res.data;
|
||||||
|
var pct = d.total > 0 ? Math.round( ( d.done / d.total ) * 100 ) : 100;
|
||||||
|
$fill.css( 'width', pct + '%' );
|
||||||
|
$label.text( d.done + ' / ' + d.total );
|
||||||
|
if ( d.remaining > 0 ) {
|
||||||
|
setTimeout( runBatch, 300 );
|
||||||
|
} else {
|
||||||
|
$fill.css( 'width', '100%' );
|
||||||
|
finish( mraTools.i18n.done );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error: function () {
|
||||||
|
finish( mraTools.i18n.error );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
function finish( msg ) {
|
||||||
|
running = false;
|
||||||
|
$start.prop( 'disabled', false );
|
||||||
|
$stop.prop( 'hidden', true ).prop( 'disabled', false );
|
||||||
|
$label.text( msg );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Modal — Audit page
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
var $overlay, $modalTitle, $modalBody;
|
var $overlay, $modalTitle, $modalBody;
|
||||||
|
|
||||||
function openModal( attachmentId ) {
|
function openModal( attachmentId ) {
|
||||||
|
|
@ -37,6 +116,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
$( function () {
|
$( function () {
|
||||||
|
// Initialize batch runners if mraTools is available (Tools page only).
|
||||||
|
if ( typeof mraTools !== 'undefined' ) {
|
||||||
|
[ 'index', 'usage', 'external' ].forEach( initRunner );
|
||||||
|
}
|
||||||
|
|
||||||
$overlay = $( '#mra-modal-overlay' );
|
$overlay = $( '#mra-modal-overlay' );
|
||||||
$modalTitle = $overlay.find( '.mra-modal-title' );
|
$modalTitle = $overlay.find( '.mra-modal-title' );
|
||||||
$modalBody = $overlay.find( '.mra-modal-body' );
|
$modalBody = $overlay.find( '.mra-modal-body' );
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,50 @@
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 1.2.0 =
|
||||||
|
|
||||||
|
_Release date: 2026-05-02_
|
||||||
|
|
||||||
|
**Added**
|
||||||
|
|
||||||
|
* Browser-based AJAX scan runner in the Tools page: run index, usage, and external scan batches directly from the browser with a live progress bar. Useful when WP-Cron is disabled or Action Scheduler is not running.
|
||||||
|
* "Requeue scan errors" operation: re-queues only attachments that failed the last external scan run (status `error`), without touching already-scanned items.
|
||||||
|
* "Last Scanned" column in the audit list, showing a human-readable relative time with a precise date tooltip. Sortable with NULLs always listed last.
|
||||||
|
* Bulk action "Export External Results CSV": downloads a CSV with attachment metadata and all external scan results, including top matching domains per provider.
|
||||||
|
|
||||||
|
**Compatibility**
|
||||||
|
|
||||||
|
* WordPress: 6.8 - 7.0
|
||||||
|
* PHP: 8.2 - 8.4
|
||||||
|
* WP-CLI: 2.x
|
||||||
|
|
||||||
|
**Tests**
|
||||||
|
|
||||||
|
* PHP Coding Standards: WPCS 3.x / PHPCS 3.x
|
||||||
|
* PHPStan: level 9
|
||||||
|
* PHPCompatibility: PHP 8.2 - 8.4
|
||||||
|
|
||||||
|
= 1.1.0 =
|
||||||
|
|
||||||
|
_Release date: 2026-05-02_
|
||||||
|
|
||||||
|
**Changed**
|
||||||
|
|
||||||
|
* Plugin URI updated to `https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit`.
|
||||||
|
* Author changed to `ROBOTSTXT` with URI `https://www.robotstxt.es/`.
|
||||||
|
* Contributors updated to `javiercasares, robotstxt`.
|
||||||
|
|
||||||
|
**Compatibility**
|
||||||
|
|
||||||
|
* WordPress: 6.8 - 7.0
|
||||||
|
* PHP: 8.2 - 8.4
|
||||||
|
* WP-CLI: 2.x
|
||||||
|
|
||||||
|
**Tests**
|
||||||
|
|
||||||
|
* PHP Coding Standards: WPCS 3.x / PHPCS 3.x
|
||||||
|
* PHPStan: level 9
|
||||||
|
* PHPCompatibility: PHP 8.2 - 8.4
|
||||||
|
|
||||||
= 1.0.0 =
|
= 1.0.0 =
|
||||||
|
|
||||||
_Release date: 2026-05-01_
|
_Release date: 2026-05-01_
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,8 @@ class AuditPage {
|
||||||
|
|
||||||
if ( 'export_csv' === $action ) {
|
if ( 'export_csv' === $action ) {
|
||||||
$this->handle_export_csv();
|
$this->handle_export_csv();
|
||||||
|
} elseif ( 'export_external_csv' === $action ) {
|
||||||
|
$this->handle_export_external_csv();
|
||||||
} elseif ( 'run_external_scan' === $action ) {
|
} elseif ( 'run_external_scan' === $action ) {
|
||||||
$this->handle_run_external_scan();
|
$this->handle_run_external_scan();
|
||||||
} elseif ( 'purge_external_data' === $action ) {
|
} elseif ( 'purge_external_data' === $action ) {
|
||||||
|
|
@ -498,6 +500,142 @@ class AuditPage {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outputs an external-results CSV for selected attachment IDs and terminates.
|
||||||
|
*
|
||||||
|
* One row per attachment × provider pair. Attachments with no results still
|
||||||
|
* appear with empty provider columns.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function handle_export_external_csv(): void {
|
||||||
|
check_admin_referer( 'bulk-mra-attachments' );
|
||||||
|
|
||||||
|
if ( ! current_user_can( 'edit_posts' ) ) {
|
||||||
|
wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$ids = $this->collect_attachment_ids();
|
||||||
|
$rows = $this->build_external_csv_rows( $ids );
|
||||||
|
|
||||||
|
$filename = 'media-audit-external-' . gmdate( 'Y-m-d' ) . '.csv';
|
||||||
|
|
||||||
|
header( 'Content-Type: text/csv; charset=utf-8' );
|
||||||
|
header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
|
||||||
|
header( 'Pragma: no-cache' );
|
||||||
|
|
||||||
|
$out = fopen( 'php://output', 'w' );
|
||||||
|
if ( false === $out ) {
|
||||||
|
wp_die( esc_html__( 'Could not open output stream.', 'robotstxt-mediaaudit' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
fwrite( $out, "\xEF\xBB\xBF" ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fwrite
|
||||||
|
|
||||||
|
fputcsv(
|
||||||
|
$out,
|
||||||
|
array(
|
||||||
|
__( 'Attachment ID', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'Filename', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'File URL', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'External Status', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'Last Scanned', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'Provider', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'Match Count', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'Top Domains', 'robotstxt-mediaaudit' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ( $rows as $row ) {
|
||||||
|
fputcsv( $out, $row );
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose( $out ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds external-results CSV rows for the given attachment IDs.
|
||||||
|
*
|
||||||
|
* Each row represents one attachment × provider combination. Attachments with
|
||||||
|
* no provider results are included with empty provider columns. If $ids is
|
||||||
|
* empty, all indexed attachments are exported.
|
||||||
|
*
|
||||||
|
* @param array<int, int> $ids Attachment IDs to export (empty = all).
|
||||||
|
*
|
||||||
|
* @return array<int, array<int, string>>
|
||||||
|
*/
|
||||||
|
private function build_external_csv_rows( array $ids ): array {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
|
||||||
|
|
||||||
|
if ( empty( $ids ) ) {
|
||||||
|
$rows = $wpdb->get_results(
|
||||||
|
"SELECT i.attachment_id, i.file_name, i.file_url, i.external_status,
|
||||||
|
i.external_scanned_at, er.provider, er.match_count, er.top_domains
|
||||||
|
FROM {$wpdb->prefix}mra_media_index i
|
||||||
|
LEFT JOIN {$wpdb->prefix}mra_external_results er ON er.attachment_id = i.attachment_id
|
||||||
|
ORDER BY i.attachment_id ASC, er.provider ASC",
|
||||||
|
ARRAY_A
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$placeholders = implode( ',', array_fill( 0, count( $ids ), '%d' ) );
|
||||||
|
$rows = $wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT i.attachment_id, i.file_name, i.file_url, i.external_status,
|
||||||
|
i.external_scanned_at, er.provider, er.match_count, er.top_domains
|
||||||
|
FROM {$wpdb->prefix}mra_media_index i
|
||||||
|
LEFT JOIN {$wpdb->prefix}mra_external_results er ON er.attachment_id = i.attachment_id
|
||||||
|
WHERE i.attachment_id IN ({$placeholders})
|
||||||
|
ORDER BY i.attachment_id ASC, er.provider ASC",
|
||||||
|
...$ids
|
||||||
|
),
|
||||||
|
ARRAY_A
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
|
||||||
|
|
||||||
|
if ( ! $rows ) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$output = array();
|
||||||
|
|
||||||
|
foreach ( $rows as $r ) {
|
||||||
|
$aid_raw = $r['attachment_id'] ?? '';
|
||||||
|
$scanned_raw = $r['external_scanned_at'] ?? '';
|
||||||
|
$domains_raw = $r['top_domains'] ?? '';
|
||||||
|
$mc_raw = $r['match_count'] ?? '';
|
||||||
|
|
||||||
|
$domains_decoded = is_string( $domains_raw ) && '' !== $domains_raw
|
||||||
|
? json_decode( $domains_raw, true )
|
||||||
|
: array();
|
||||||
|
$domain_parts = array();
|
||||||
|
if ( is_array( $domains_decoded ) ) {
|
||||||
|
foreach ( $domains_decoded as $d ) {
|
||||||
|
if ( is_string( $d ) ) {
|
||||||
|
$domain_parts[] = $d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$domains_str = implode( '; ', $domain_parts );
|
||||||
|
|
||||||
|
$output[] = array(
|
||||||
|
is_numeric( $aid_raw ) ? (string) (int) $aid_raw : '',
|
||||||
|
is_string( $r['file_name'] ?? null ) ? (string) $r['file_name'] : '',
|
||||||
|
is_string( $r['file_url'] ?? null ) ? (string) $r['file_url'] : '',
|
||||||
|
is_string( $r['external_status'] ?? null ) ? (string) $r['external_status'] : '',
|
||||||
|
is_string( $scanned_raw ) ? $scanned_raw : '',
|
||||||
|
is_string( $r['provider'] ?? null ) ? (string) $r['provider'] : '',
|
||||||
|
is_numeric( $mc_raw ) ? (string) (int) $mc_raw : '',
|
||||||
|
$domains_str,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queues selected attachments for external scanning and redirects.
|
* Queues selected attachments for external scanning and redirects.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ class MediaListTable extends \WP_List_Table {
|
||||||
'usage_count' => __( 'Usage Count', 'robotstxt-mediaaudit' ),
|
'usage_count' => __( 'Usage Count', 'robotstxt-mediaaudit' ),
|
||||||
'usages' => __( 'Usages', 'robotstxt-mediaaudit' ),
|
'usages' => __( 'Usages', 'robotstxt-mediaaudit' ),
|
||||||
'external_status' => __( 'External Status', 'robotstxt-mediaaudit' ),
|
'external_status' => __( 'External Status', 'robotstxt-mediaaudit' ),
|
||||||
|
'external_scanned_at' => __( 'Last Scanned', 'robotstxt-mediaaudit' ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,6 +67,7 @@ class MediaListTable extends \WP_List_Table {
|
||||||
return array(
|
return array(
|
||||||
'attachment_id' => array( 'attachment_id', true ),
|
'attachment_id' => array( 'attachment_id', true ),
|
||||||
'usage_count' => array( 'usage_count', false ),
|
'usage_count' => array( 'usage_count', false ),
|
||||||
|
'external_scanned_at' => array( 'external_scanned_at', false ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,6 +81,7 @@ class MediaListTable extends \WP_List_Table {
|
||||||
'run_external_scan' => __( 'Run External Scan', 'robotstxt-mediaaudit' ),
|
'run_external_scan' => __( 'Run External Scan', 'robotstxt-mediaaudit' ),
|
||||||
'purge_external_data' => __( 'Purge External Data', 'robotstxt-mediaaudit' ),
|
'purge_external_data' => __( 'Purge External Data', 'robotstxt-mediaaudit' ),
|
||||||
'export_csv' => __( 'Export CSV', 'robotstxt-mediaaudit' ),
|
'export_csv' => __( 'Export CSV', 'robotstxt-mediaaudit' ),
|
||||||
|
'export_external_csv' => __( 'Export External Results CSV', 'robotstxt-mediaaudit' ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -309,6 +312,47 @@ class MediaListTable extends \WP_List_Table {
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the external scan date column.
|
||||||
|
*
|
||||||
|
* Shows a human-readable time difference (e.g. "3 days ago") with the full
|
||||||
|
* date/time as a tooltip. Displays "—" when the attachment has never been scanned.
|
||||||
|
*
|
||||||
|
* @param array<string, mixed> $item Row data.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function column_external_scanned_at( $item ) {
|
||||||
|
$raw = $item['external_scanned_at'];
|
||||||
|
|
||||||
|
if ( ! is_string( $raw ) || '' === $raw ) {
|
||||||
|
return '—';
|
||||||
|
}
|
||||||
|
|
||||||
|
$ts = strtotime( $raw );
|
||||||
|
if ( false === $ts ) {
|
||||||
|
return '—';
|
||||||
|
}
|
||||||
|
|
||||||
|
$date_fmt = get_option( 'date_format' );
|
||||||
|
$time_fmt = get_option( 'time_format' );
|
||||||
|
$format = ( is_string( $date_fmt ) ? $date_fmt : 'Y-m-d' )
|
||||||
|
. ' '
|
||||||
|
. ( is_string( $time_fmt ) ? $time_fmt : 'H:i' );
|
||||||
|
$full_val = wp_date( $format, $ts );
|
||||||
|
$full = is_string( $full_val ) ? $full_val : $raw;
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
'<abbr title="%s">%s</abbr>',
|
||||||
|
esc_attr( $full ),
|
||||||
|
sprintf(
|
||||||
|
/* translators: %s: human-readable time difference, e.g. "3 days" */
|
||||||
|
esc_html__( '%s ago', 'robotstxt-mediaaudit' ),
|
||||||
|
esc_html( human_time_diff( $ts ) )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders filter controls above the table.
|
* Renders filter controls above the table.
|
||||||
*
|
*
|
||||||
|
|
@ -391,7 +435,7 @@ class MediaListTable extends \WP_List_Table {
|
||||||
$offset = ( $paged - 1 ) * $per_page;
|
$offset = ( $paged - 1 ) * $per_page;
|
||||||
|
|
||||||
// Sorting.
|
// Sorting.
|
||||||
$allowed_orderby = array( 'attachment_id', 'usage_count' );
|
$allowed_orderby = array( 'attachment_id', 'usage_count', 'external_scanned_at' );
|
||||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||||
$orderby_raw = isset( $_REQUEST['orderby'] ) && is_string( $_REQUEST['orderby'] ) ? sanitize_key( wp_unslash( $_REQUEST['orderby'] ) ) : '';
|
$orderby_raw = isset( $_REQUEST['orderby'] ) && is_string( $_REQUEST['orderby'] ) ? sanitize_key( wp_unslash( $_REQUEST['orderby'] ) ) : '';
|
||||||
$orderby = in_array( $orderby_raw, $allowed_orderby, true ) ? $orderby_raw : 'attachment_id';
|
$orderby = in_array( $orderby_raw, $allowed_orderby, true ) ? $orderby_raw : 'attachment_id';
|
||||||
|
|
@ -438,6 +482,9 @@ class MediaListTable extends \WP_List_Table {
|
||||||
|
|
||||||
if ( 'usage_count' === $orderby ) {
|
if ( 'usage_count' === $orderby ) {
|
||||||
$order_sql = "(SELECT COUNT(*) FROM {$wpdb->prefix}mra_media_usage mu WHERE mu.attachment_id = i.attachment_id) {$order}";
|
$order_sql = "(SELECT COUNT(*) FROM {$wpdb->prefix}mra_media_usage mu WHERE mu.attachment_id = i.attachment_id) {$order}";
|
||||||
|
} elseif ( 'external_scanned_at' === $orderby ) {
|
||||||
|
// NULLs always last, regardless of sort direction.
|
||||||
|
$order_sql = "i.external_scanned_at IS NULL ASC, i.external_scanned_at {$order}";
|
||||||
} else {
|
} else {
|
||||||
$order_sql = "i.attachment_id {$order}";
|
$order_sql = "i.attachment_id {$order}";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
776
includes/Admin/ToolsPage.php
Normal file
776
includes/Admin/ToolsPage.php
Normal file
|
|
@ -0,0 +1,776 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Tools & Status admin page.
|
||||||
|
*
|
||||||
|
* @package MediaRightsAudit\Admin
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace MediaRightsAudit\Admin;
|
||||||
|
|
||||||
|
use MediaRightsAudit\Core\Database;
|
||||||
|
use MediaRightsAudit\Core\Queue\Scheduler;
|
||||||
|
use MediaRightsAudit\External\ExternalScanner;
|
||||||
|
use MediaRightsAudit\Internal\AttachmentIndexer;
|
||||||
|
use MediaRightsAudit\Internal\UsageScanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the Tools & Status admin page.
|
||||||
|
*
|
||||||
|
* Provides a live system-health overview and one-click bulk operations for
|
||||||
|
* managing internal and external scan data. All state-changing operations
|
||||||
|
* use POST + redirect (PRG) to prevent double-submission.
|
||||||
|
*/
|
||||||
|
class ToolsPage {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonce action for all tool operations.
|
||||||
|
*/
|
||||||
|
const NONCE_ACTION = 'mra_tools_op';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonce field name.
|
||||||
|
*/
|
||||||
|
const NONCE_FIELD = 'mra_tools_nonce';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Nonce action for the AJAX batch runner.
|
||||||
|
*/
|
||||||
|
const NONCE_BATCH = 'mra_run_batch';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin page hook suffix, used to scope asset enqueuing.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private string $hook_suffix = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores the hook suffix and registers the load-* hook for pre-output processing.
|
||||||
|
*
|
||||||
|
* @param string $suffix Hook suffix returned by add_submenu_page().
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function set_hook_suffix( string $suffix ): void {
|
||||||
|
$this->hook_suffix = $suffix;
|
||||||
|
add_action( 'load-' . $suffix, array( $this, 'handle_load' ) );
|
||||||
|
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues CSS and JS assets for the Tools page.
|
||||||
|
*
|
||||||
|
* @param string $hook Current admin page hook suffix.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function enqueue_assets( string $hook ): void {
|
||||||
|
if ( $hook !== $this->hook_suffix ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$base = ROBOTSTXT_MEDIAAUDIT_PLUGIN_URL . 'assets/';
|
||||||
|
$ver = ROBOTSTXT_MEDIAAUDIT_VERSION;
|
||||||
|
|
||||||
|
wp_enqueue_style( 'mra-admin', $base . 'css/media-audit-admin.css', array(), $ver );
|
||||||
|
wp_enqueue_script( 'mra-admin', $base . 'js/media-audit-admin.js', array( 'jquery' ), $ver, true );
|
||||||
|
|
||||||
|
wp_localize_script(
|
||||||
|
'mra-admin',
|
||||||
|
'mraTools',
|
||||||
|
array(
|
||||||
|
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
|
||||||
|
'nonce' => wp_create_nonce( self::NONCE_BATCH ),
|
||||||
|
'i18n' => array(
|
||||||
|
'done' => __( 'Done.', 'robotstxt-mediaaudit' ),
|
||||||
|
'stopped' => __( 'Stopped.', 'robotstxt-mediaaudit' ),
|
||||||
|
'error' => __( 'An error occurred.', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AJAX handler for the batch runner. Processes one batch and returns progress data.
|
||||||
|
*
|
||||||
|
* Expected POST fields: type (index|usage|external), nonce.
|
||||||
|
* Returns JSON: {done: int, total: int, remaining: int}.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function ajax_run_batch(): void {
|
||||||
|
check_ajax_referer( self::NONCE_BATCH, 'nonce' );
|
||||||
|
|
||||||
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
|
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) ), 403 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$type = sanitize_key( wp_unslash( isset( $_POST['type'] ) && is_string( $_POST['type'] ) ? $_POST['type'] : '' ) );
|
||||||
|
|
||||||
|
$remaining = 0;
|
||||||
|
$done = 0;
|
||||||
|
$total = 0;
|
||||||
|
|
||||||
|
switch ( $type ) {
|
||||||
|
case 'index':
|
||||||
|
AttachmentIndexer::index_batch();
|
||||||
|
$remaining = AttachmentIndexer::get_pending_count();
|
||||||
|
$done = AttachmentIndexer::get_indexed_count();
|
||||||
|
$total = $done + $remaining;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'usage':
|
||||||
|
UsageScanner::scan_batch();
|
||||||
|
$remaining = UsageScanner::get_pending_count();
|
||||||
|
$total = AttachmentIndexer::get_indexed_count();
|
||||||
|
$done = max( 0, $total - $remaining );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'external':
|
||||||
|
ExternalScanner::queue_all_pending();
|
||||||
|
ExternalScanner::scan_batch();
|
||||||
|
$counts = ExternalScanner::get_status_counts();
|
||||||
|
$remaining = $counts['queued'] ?? 0;
|
||||||
|
$done = ( $counts['scanned'] ?? 0 ) + ( $counts['matches'] ?? 0 ) + ( $counts['error'] ?? 0 );
|
||||||
|
$total = $done + $remaining;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wp_send_json_error( array( 'message' => __( 'Invalid batch type.', 'robotstxt-mediaaudit' ) ), 400 );
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json_success(
|
||||||
|
array(
|
||||||
|
'done' => $done,
|
||||||
|
'total' => $total,
|
||||||
|
'remaining' => $remaining,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fires before page HTML is output; processes POST operations and redirects.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function handle_load(): void {
|
||||||
|
if ( ! isset( $_POST['mra_tools_op'] ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
|
wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
|
||||||
|
}
|
||||||
|
check_admin_referer( self::NONCE_ACTION, self::NONCE_FIELD );
|
||||||
|
|
||||||
|
$op = sanitize_key( wp_unslash( is_string( $_POST['mra_tools_op'] ) ? $_POST['mra_tools_op'] : '' ) );
|
||||||
|
$result = $this->dispatch_op( $op );
|
||||||
|
|
||||||
|
wp_safe_redirect(
|
||||||
|
add_query_arg(
|
||||||
|
array(
|
||||||
|
'page' => 'robotstxt-mediaaudit-tools',
|
||||||
|
'mra_notice' => $result['notice'],
|
||||||
|
'mra_count' => $result['count'],
|
||||||
|
'mra_op' => $op,
|
||||||
|
),
|
||||||
|
admin_url( 'admin.php' )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Routes an operation key to the appropriate handler and returns a result array.
|
||||||
|
*
|
||||||
|
* @param string $op Operation key from the POST body.
|
||||||
|
*
|
||||||
|
* @return array{notice: string, count: int}
|
||||||
|
*/
|
||||||
|
private function dispatch_op( string $op ): array {
|
||||||
|
$count = 0;
|
||||||
|
|
||||||
|
switch ( $op ) {
|
||||||
|
case 'schedule_internal':
|
||||||
|
AttachmentIndexer::schedule();
|
||||||
|
UsageScanner::schedule();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'schedule_external':
|
||||||
|
ExternalScanner::schedule();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'requeue_errors':
|
||||||
|
$count = ExternalScanner::requeue_errors();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'rescan_usage':
|
||||||
|
$count = UsageScanner::reset_all();
|
||||||
|
UsageScanner::schedule();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'reindex_all':
|
||||||
|
$count = AttachmentIndexer::reset_all();
|
||||||
|
AttachmentIndexer::schedule();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'purge_external':
|
||||||
|
$count = ExternalScanner::purge_all();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'full_reset':
|
||||||
|
Database::truncate_all();
|
||||||
|
AttachmentIndexer::schedule();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return array(
|
||||||
|
'notice' => 'error',
|
||||||
|
'count' => 0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'notice' => 'success',
|
||||||
|
'count' => $count,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the Tools & Status page.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function render(): void {
|
||||||
|
if ( ! current_user_can( 'manage_options' ) ) {
|
||||||
|
wp_die( esc_html__( 'You do not have permission to access this page.', 'robotstxt-mediaaudit' ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = $this->get_system_status();
|
||||||
|
$notice = $this->get_notice_data();
|
||||||
|
?>
|
||||||
|
<div class="wrap">
|
||||||
|
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
|
||||||
|
|
||||||
|
<?php $this->render_notice( $notice ); ?>
|
||||||
|
|
||||||
|
<h2><?php esc_html_e( 'System Status', 'robotstxt-mediaaudit' ); ?></h2>
|
||||||
|
<?php $this->render_status( $status ); ?>
|
||||||
|
|
||||||
|
<h2 class="mra-ops-heading"><?php esc_html_e( 'Operations', 'robotstxt-mediaaudit' ); ?></h2>
|
||||||
|
<?php $this->render_operations(); ?>
|
||||||
|
|
||||||
|
<h2 class="mra-ops-heading"><?php esc_html_e( 'Direct scan runner', 'robotstxt-mediaaudit' ); ?></h2>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e( 'Run scan batches directly from your browser without relying on background jobs. Useful when WP-Cron is disabled or Action Scheduler is not running. Keep this tab open while processing.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
</p>
|
||||||
|
<?php $this->render_runner(); ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Status data
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects all status data for the status table.
|
||||||
|
*
|
||||||
|
* @return array{db_version_ok: bool, stored_version: string, as_available: bool, cron_disabled: bool, total_images: int, indexed: int, pending_index: int, pending_usage: int, external: array<string, int>, jobs: array{index: bool, usage: bool, external: bool}}
|
||||||
|
*/
|
||||||
|
private function get_system_status(): array {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$raw_ver = get_option( 'robotstxt_mediaaudit_db_version', '' );
|
||||||
|
$stored_ver = is_string( $raw_ver ) ? $raw_ver : '';
|
||||||
|
$as_ok = Scheduler::is_available();
|
||||||
|
|
||||||
|
// phpcs:ignore WordPress.DB.DirectDatabaseQuery
|
||||||
|
$total_images = (int) $wpdb->get_var(
|
||||||
|
"SELECT COUNT(ID) FROM {$wpdb->posts}
|
||||||
|
WHERE post_type = 'attachment'
|
||||||
|
AND post_mime_type LIKE 'image/%'
|
||||||
|
AND post_status != 'trash'"
|
||||||
|
);
|
||||||
|
|
||||||
|
$indexed = AttachmentIndexer::get_indexed_count();
|
||||||
|
$pending_idx = AttachmentIndexer::get_pending_count();
|
||||||
|
$pending_use = UsageScanner::get_pending_count();
|
||||||
|
$ext_counts = ExternalScanner::get_status_counts();
|
||||||
|
|
||||||
|
$fallback_ver = '' !== $stored_ver ? $stored_ver : __( 'not installed', 'robotstxt-mediaaudit' );
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'db_version_ok' => ROBOTSTXT_MEDIAAUDIT_DB_VERSION === $stored_ver,
|
||||||
|
'stored_version' => $fallback_ver,
|
||||||
|
'as_available' => $as_ok,
|
||||||
|
'cron_disabled' => defined( 'DISABLE_WP_CRON' ) && DISABLE_WP_CRON,
|
||||||
|
'total_images' => $total_images,
|
||||||
|
'indexed' => $indexed,
|
||||||
|
'pending_index' => $pending_idx,
|
||||||
|
'pending_usage' => $pending_use,
|
||||||
|
'external' => $ext_counts,
|
||||||
|
'jobs' => array(
|
||||||
|
'index' => $as_ok && Scheduler::has_pending( AttachmentIndexer::AS_HOOK ),
|
||||||
|
'usage' => $as_ok && Scheduler::has_pending( UsageScanner::AS_HOOK ),
|
||||||
|
'external' => $as_ok && Scheduler::has_pending( ExternalScanner::AS_HOOK ),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads PRG redirect query parameters and returns structured notice data.
|
||||||
|
*
|
||||||
|
* @return array{type: string, op: string, count: int}|null
|
||||||
|
*/
|
||||||
|
private function get_notice_data(): ?array {
|
||||||
|
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||||
|
if ( ! isset( $_GET['mra_notice'] ) ) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$type = sanitize_key( wp_unslash( is_string( $_GET['mra_notice'] ) ? $_GET['mra_notice'] : '' ) );
|
||||||
|
$op2 = sanitize_key( wp_unslash( isset( $_GET['mra_op'] ) && is_string( $_GET['mra_op'] ) ? $_GET['mra_op'] : '' ) );
|
||||||
|
$count = isset( $_GET['mra_count'] ) && is_numeric( $_GET['mra_count'] ) ? (int) $_GET['mra_count'] : 0;
|
||||||
|
return array(
|
||||||
|
'type' => $type,
|
||||||
|
'op' => $op2,
|
||||||
|
'count' => abs( $count ),
|
||||||
|
);
|
||||||
|
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
// Rendering helpers
|
||||||
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a WP admin notice for a completed operation.
|
||||||
|
*
|
||||||
|
* @param array{type: string, op: string, count: int}|null $notice Notice data.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function render_notice( ?array $notice ): void {
|
||||||
|
if ( null === $notice || 'success' !== $notice['type'] ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$messages = array(
|
||||||
|
'schedule_internal' => __( 'Internal scan scheduled.', 'robotstxt-mediaaudit' ),
|
||||||
|
'schedule_external' => __( 'External scan scheduled.', 'robotstxt-mediaaudit' ),
|
||||||
|
'requeue_errors' => __( 'Failed scans re-queued. Background scan scheduled.', 'robotstxt-mediaaudit' ),
|
||||||
|
'rescan_usage' => __( 'Usage data cleared. Background scan scheduled.', 'robotstxt-mediaaudit' ),
|
||||||
|
'reindex_all' => __( 'Index cleared. Fresh indexing scheduled.', 'robotstxt-mediaaudit' ),
|
||||||
|
'purge_external' => __( 'External scan data purged.', 'robotstxt-mediaaudit' ),
|
||||||
|
'full_reset' => __( 'All data reset. Fresh indexing scheduled.', 'robotstxt-mediaaudit' ),
|
||||||
|
);
|
||||||
|
|
||||||
|
$msg = $messages[ $notice['op'] ] ?? __( 'Operation completed.', 'robotstxt-mediaaudit' );
|
||||||
|
?>
|
||||||
|
<div class="notice notice-success is-dismissible">
|
||||||
|
<p><?php echo esc_html( $msg ); ?></p>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the system status table.
|
||||||
|
*
|
||||||
|
* @param array{db_version_ok: bool, stored_version: string, as_available: bool, cron_disabled: bool, total_images: int, indexed: int, pending_index: int, pending_usage: int, external: array<string, int>, jobs: array{index: bool, usage: bool, external: bool}} $status Status data.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function render_status( array $status ): void {
|
||||||
|
$db_ok = $status['db_version_ok'];
|
||||||
|
$as_ok = $status['as_available'];
|
||||||
|
$cron = $status['cron_disabled'];
|
||||||
|
$tot = $status['total_images'];
|
||||||
|
$idx = $status['indexed'];
|
||||||
|
$pi = $status['pending_index'];
|
||||||
|
$pu = $status['pending_usage'];
|
||||||
|
|
||||||
|
$ext = $status['external'];
|
||||||
|
$ep = $ext['pending'] ?? 0;
|
||||||
|
$eq = $ext['queued'] ?? 0;
|
||||||
|
$es = $ext['scanned'] ?? 0;
|
||||||
|
$em = $ext['matches'] ?? 0;
|
||||||
|
$ee = $ext['error'] ?? 0;
|
||||||
|
|
||||||
|
$jobs = $status['jobs'];
|
||||||
|
$ji = $jobs['index'];
|
||||||
|
$ju = $jobs['usage'];
|
||||||
|
$je = $jobs['external'];
|
||||||
|
|
||||||
|
$needs_work = $pi > 0 || $pu > 0 || $ep > 0 || $eq > 0;
|
||||||
|
$any_job = $ji || $ju || $je;
|
||||||
|
?>
|
||||||
|
<table class="widefat striped mra-status-table">
|
||||||
|
<tbody>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="mra-status-dot-col"><?php echo $this->dot( $db_ok ? 'ok' : 'error' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></td>
|
||||||
|
<th scope="row"><?php esc_html_e( 'Database schema', 'robotstxt-mediaaudit' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
if ( $db_ok ) {
|
||||||
|
printf(
|
||||||
|
/* translators: %s: version number */
|
||||||
|
esc_html__( 'v%s – up to date', 'robotstxt-mediaaudit' ),
|
||||||
|
esc_html( ROBOTSTXT_MEDIAAUDIT_DB_VERSION )
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
printf(
|
||||||
|
/* translators: 1: stored version, 2: expected version */
|
||||||
|
esc_html__( 'Installed: %1$s — Required: %2$s', 'robotstxt-mediaaudit' ),
|
||||||
|
esc_html( $status['stored_version'] ),
|
||||||
|
esc_html( ROBOTSTXT_MEDIAAUDIT_DB_VERSION )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td class="mra-status-hint">
|
||||||
|
<?php if ( ! $db_ok ) : ?>
|
||||||
|
<?php esc_html_e( 'Deactivate and reactivate the plugin to apply pending migrations.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="mra-status-dot-col"><?php echo $this->dot( $as_ok ? 'ok' : 'error' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></td>
|
||||||
|
<th scope="row"><?php esc_html_e( 'Action Scheduler', 'robotstxt-mediaaudit' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php if ( $as_ok ) : ?>
|
||||||
|
<?php esc_html_e( 'Available', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php esc_html_e( 'Not available', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="mra-status-hint">
|
||||||
|
<?php if ( ! $as_ok ) : ?>
|
||||||
|
<?php esc_html_e( 'Install and activate the Action Scheduler plugin. Background scanning will not work without it.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="mra-status-dot-col"><?php echo $this->dot( $cron ? 'warn' : 'ok' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></td>
|
||||||
|
<th scope="row"><?php esc_html_e( 'WP-Cron', 'robotstxt-mediaaudit' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php if ( $cron ) : ?>
|
||||||
|
<?php esc_html_e( 'Disabled (DISABLE_WP_CRON)', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php else : ?>
|
||||||
|
<?php esc_html_e( 'Enabled', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="mra-status-hint">
|
||||||
|
<?php if ( $cron ) : ?>
|
||||||
|
<?php esc_html_e( 'Background jobs will not fire automatically. Trigger the cron externally or use WP-CLI:', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<code>wp cron event run --due-now</code>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="mra-status-dot-col"><?php echo $this->dot( $pi > 0 ? 'warn' : 'ok' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></td>
|
||||||
|
<th scope="row"><?php esc_html_e( 'Internal index', 'robotstxt-mediaaudit' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: 1: indexed count, 2: total images */
|
||||||
|
esc_html__( '%1$s / %2$s images indexed', 'robotstxt-mediaaudit' ),
|
||||||
|
esc_html( number_format_i18n( $idx ) ),
|
||||||
|
esc_html( number_format_i18n( $tot ) )
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td class="mra-status-hint">
|
||||||
|
<?php if ( $pi > 0 ) : ?>
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: %s: formatted count */
|
||||||
|
esc_html( _n( '%s image not yet indexed.', '%s images not yet indexed.', $pi, 'robotstxt-mediaaudit' ) ),
|
||||||
|
esc_html( number_format_i18n( $pi ) )
|
||||||
|
);
|
||||||
|
echo ' ';
|
||||||
|
esc_html_e( 'Schedule an internal scan below.', 'robotstxt-mediaaudit' );
|
||||||
|
?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="mra-status-dot-col"><?php echo $this->dot( $pu > 0 ? 'warn' : 'ok' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></td>
|
||||||
|
<th scope="row"><?php esc_html_e( 'Usage scan', 'robotstxt-mediaaudit' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: 1: scanned count, 2: total indexed */
|
||||||
|
esc_html__( '%1$s / %2$s scanned for usage', 'robotstxt-mediaaudit' ),
|
||||||
|
esc_html( number_format_i18n( max( 0, $idx - $pu ) ) ),
|
||||||
|
esc_html( number_format_i18n( $idx ) )
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td class="mra-status-hint">
|
||||||
|
<?php if ( $pu > 0 ) : ?>
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: %s: formatted count */
|
||||||
|
esc_html( _n( '%s pending.', '%s pending.', $pu, 'robotstxt-mediaaudit' ) ),
|
||||||
|
esc_html( number_format_i18n( $pu ) )
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="mra-status-dot-col">
|
||||||
|
<?php
|
||||||
|
if ( $ee > 0 ) {
|
||||||
|
$ext_dot = 'error';
|
||||||
|
} elseif ( $ep > 0 || $eq > 0 ) {
|
||||||
|
$ext_dot = 'warn';
|
||||||
|
} else {
|
||||||
|
$ext_dot = 'ok';
|
||||||
|
}
|
||||||
|
echo $this->dot( $ext_dot ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<th scope="row"><?php esc_html_e( 'External scan', 'robotstxt-mediaaudit' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php
|
||||||
|
printf(
|
||||||
|
/* translators: 1: scanned 2: matches 3: queued 4: pending 5: errors */
|
||||||
|
esc_html__( '%1$s scanned · %2$s matches · %3$s queued · %4$s pending · %5$s errors', 'robotstxt-mediaaudit' ),
|
||||||
|
esc_html( number_format_i18n( $es ) ),
|
||||||
|
esc_html( number_format_i18n( $em ) ),
|
||||||
|
esc_html( number_format_i18n( $eq ) ),
|
||||||
|
esc_html( number_format_i18n( $ep ) ),
|
||||||
|
esc_html( number_format_i18n( $ee ) )
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<td class="mra-status-hint">
|
||||||
|
<?php if ( $ee > 0 ) : ?>
|
||||||
|
<?php esc_html_e( 'Some scans failed. Check that API keys are configured correctly in Settings.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php elseif ( $ep > 0 ) : ?>
|
||||||
|
<?php esc_html_e( 'Schedule an external scan below to process pending items.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td class="mra-status-dot-col">
|
||||||
|
<?php
|
||||||
|
if ( $as_ok && $needs_work && ! $any_job ) {
|
||||||
|
$jobs_dot = 'warn';
|
||||||
|
} elseif ( $any_job ) {
|
||||||
|
$jobs_dot = 'ok';
|
||||||
|
} else {
|
||||||
|
$jobs_dot = 'ok';
|
||||||
|
}
|
||||||
|
echo $this->dot( $jobs_dot ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
?>
|
||||||
|
</td>
|
||||||
|
<th scope="row"><?php esc_html_e( 'Scheduled jobs', 'robotstxt-mediaaudit' ); ?></th>
|
||||||
|
<td>
|
||||||
|
<?php if ( ! $as_ok ) : ?>
|
||||||
|
<em><?php esc_html_e( 'Action Scheduler not available.', 'robotstxt-mediaaudit' ); ?></em>
|
||||||
|
<?php else : ?>
|
||||||
|
<span class="mra-job-label"><?php esc_html_e( 'Index:', 'robotstxt-mediaaudit' ); ?> <strong><?php echo $ji ? esc_html__( 'Pending', 'robotstxt-mediaaudit' ) : '—'; ?></strong></span>
|
||||||
|
<span class="mra-job-label"><?php esc_html_e( 'Usage:', 'robotstxt-mediaaudit' ); ?> <strong><?php echo $ju ? esc_html__( 'Pending', 'robotstxt-mediaaudit' ) : '—'; ?></strong></span>
|
||||||
|
<span class="mra-job-label"><?php esc_html_e( 'External:', 'robotstxt-mediaaudit' ); ?> <strong><?php echo $je ? esc_html__( 'Pending', 'robotstxt-mediaaudit' ) : '—'; ?></strong></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="mra-status-hint">
|
||||||
|
<?php if ( $as_ok && $needs_work && ! $any_job ) : ?>
|
||||||
|
<?php esc_html_e( 'There is work to do but no background job is scheduled. Use the operations below.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php elseif ( $cron && $any_job ) : ?>
|
||||||
|
<?php esc_html_e( 'WP-Cron is disabled. Jobs will not fire automatically.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<?php if ( $cron ) : ?>
|
||||||
|
<p class="description mra-cli-hint">
|
||||||
|
<?php esc_html_e( 'WP-CLI commands to process scans manually:', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
<code>wp mra scan-internal</code>
|
||||||
|
<code>wp mra scan-external</code>
|
||||||
|
</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the operations grid (normal + destructive).
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function render_operations(): void {
|
||||||
|
$ops = array(
|
||||||
|
array(
|
||||||
|
'op' => 'schedule_internal',
|
||||||
|
'label' => __( 'Schedule internal scan', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Queue a background job to index all unindexed media files and scan their usage across posts, pages, and custom fields. Safe to run at any time — will not re-process completed work.', 'robotstxt-mediaaudit' ),
|
||||||
|
'class' => 'button button-primary',
|
||||||
|
'confirm' => '',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'op' => 'schedule_external',
|
||||||
|
'label' => __( 'Schedule external scan', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Mark all pending attachments as queued and launch a background reverse-image-search via the configured providers. Requires API keys in Settings.', 'robotstxt-mediaaudit' ),
|
||||||
|
'class' => 'button button-primary',
|
||||||
|
'confirm' => '',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'op' => 'requeue_errors',
|
||||||
|
'label' => __( 'Requeue scan errors', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Re-queues only the attachments that failed with an error on the last external scan run. Does not affect already-scanned items. Useful to retry after fixing API key issues.', 'robotstxt-mediaaudit' ),
|
||||||
|
'class' => 'button',
|
||||||
|
'confirm' => '',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$destructive = array(
|
||||||
|
array(
|
||||||
|
'op' => 'rescan_usage',
|
||||||
|
'label' => __( 'Reset usage data', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Clears all usage rows and resets the usage-scan flag for every indexed attachment. File metadata in the index is preserved. A background usage scan is scheduled immediately after.', 'robotstxt-mediaaudit' ),
|
||||||
|
'class' => 'button',
|
||||||
|
'confirm' => __( 'This will delete all usage data. Continue?', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'op' => 'reindex_all',
|
||||||
|
'label' => __( 'Re-index media library', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Deletes all index and usage entries, then schedules a full fresh re-index. External scan results are not affected. Useful if many media files have been added or removed.', 'robotstxt-mediaaudit' ),
|
||||||
|
'class' => 'button',
|
||||||
|
'confirm' => __( 'This will delete all index and usage data. Continue?', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'op' => 'purge_external',
|
||||||
|
'label' => __( 'Purge external data', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Deletes all external scan results and resets every attachment\'s external status to pending. Use this before switching API providers or to force a complete re-scan.', 'robotstxt-mediaaudit' ),
|
||||||
|
'class' => 'button',
|
||||||
|
'confirm' => __( 'This will delete all external scan results. Continue?', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'op' => 'full_reset',
|
||||||
|
'label' => __( 'Reset all data', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Truncates all three plugin tables (index, usage, external results) and schedules a fresh indexing run. Use this to start completely from scratch.', 'robotstxt-mediaaudit' ),
|
||||||
|
'class' => 'button button-link-delete',
|
||||||
|
'confirm' => __( 'This will permanently delete ALL plugin data and cannot be undone. Are you absolutely sure?', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
<div class="mra-ops-grid">
|
||||||
|
<?php foreach ( $ops as $op ) : ?>
|
||||||
|
<?php $this->render_op_card( $op ); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3 class="mra-destructive-heading">
|
||||||
|
<?php esc_html_e( 'Destructive operations', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
</h3>
|
||||||
|
<p class="description">
|
||||||
|
<?php esc_html_e( 'These operations permanently delete plugin data. Intended for forced rescans, troubleshooting, or starting fresh. A confirmation prompt will appear before any action is taken.', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
</p>
|
||||||
|
<div class="mra-ops-grid">
|
||||||
|
<?php foreach ( $destructive as $op ) : ?>
|
||||||
|
<?php $this->render_op_card( $op ); ?>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a single operation card with a self-contained POST form.
|
||||||
|
*
|
||||||
|
* @param array{op: string, label: string, desc: string, class: string, confirm: string} $op Operation definition.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function render_op_card( array $op ): void {
|
||||||
|
?>
|
||||||
|
<div class="mra-op-card">
|
||||||
|
<h4 class="mra-op-card-title"><?php echo esc_html( $op['label'] ); ?></h4>
|
||||||
|
<p class="mra-op-card-desc description"><?php echo esc_html( $op['desc'] ); ?></p>
|
||||||
|
<form method="post">
|
||||||
|
<?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_FIELD ); ?>
|
||||||
|
<input type="hidden" name="mra_tools_op" value="<?php echo esc_attr( $op['op'] ); ?>" />
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="<?php echo esc_attr( $op['class'] ); ?>"
|
||||||
|
<?php if ( ! empty( $op['confirm'] ) ) : ?>
|
||||||
|
onclick="return confirm('<?php echo esc_js( $op['confirm'] ); ?>');"
|
||||||
|
<?php endif; ?>
|
||||||
|
>
|
||||||
|
<?php echo esc_html( $op['label'] ); ?>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders the direct scan runner cards.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
private function render_runner(): void {
|
||||||
|
$runners = array(
|
||||||
|
array(
|
||||||
|
'type' => 'index',
|
||||||
|
'label' => __( 'Index media files', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Discovers unindexed images and registers them in the plugin index. Run this first.', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'type' => 'usage',
|
||||||
|
'label' => __( 'Scan usage', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Checks every indexed image for usage across posts, pages, and custom fields.', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'type' => 'external',
|
||||||
|
'label' => __( 'External scan', 'robotstxt-mediaaudit' ),
|
||||||
|
'desc' => __( 'Sends images to external providers for reverse-image search. Requires API keys in Settings.', 'robotstxt-mediaaudit' ),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
<div class="mra-ops-grid">
|
||||||
|
<?php foreach ( $runners as $runner ) : ?>
|
||||||
|
<div class="mra-op-card" id="mra-runner-<?php echo esc_attr( $runner['type'] ); ?>">
|
||||||
|
<h4 class="mra-op-card-title"><?php echo esc_html( $runner['label'] ); ?></h4>
|
||||||
|
<p class="mra-op-card-desc description"><?php echo esc_html( $runner['desc'] ); ?></p>
|
||||||
|
<div class="mra-runner-progress" hidden>
|
||||||
|
<div class="mra-runner-bar">
|
||||||
|
<div class="mra-runner-bar-fill"></div>
|
||||||
|
</div>
|
||||||
|
<span class="mra-runner-label"></span>
|
||||||
|
</div>
|
||||||
|
<div class="mra-runner-actions">
|
||||||
|
<button type="button" class="button button-primary mra-runner-start">
|
||||||
|
<?php esc_html_e( 'Run now', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="button mra-runner-stop" hidden>
|
||||||
|
<?php esc_html_e( 'Stop', 'robotstxt-mediaaudit' ); ?>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</div>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an escaped HTML status indicator dot span.
|
||||||
|
*
|
||||||
|
* @param string $color One of 'ok', 'warn', 'error'.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function dot( string $color ): string {
|
||||||
|
return '<span class="mra-dot mra-dot-' . esc_attr( $color ) . '" aria-hidden="true"></span>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -57,6 +57,23 @@ class Database {
|
||||||
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_media_index`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
|
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_media_index`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Truncates all plugin tables, removing all data while preserving the table structure.
|
||||||
|
*
|
||||||
|
* Used by the Tools page "Reset all data" operation.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public static function truncate_all(): void {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.DirectDatabaseQuery
|
||||||
|
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_external_results`" );
|
||||||
|
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_media_usage`" );
|
||||||
|
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_media_index`" );
|
||||||
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Migrations
|
// Migrations
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ namespace MediaRightsAudit\Core;
|
||||||
|
|
||||||
use MediaRightsAudit\Admin\AuditPage;
|
use MediaRightsAudit\Admin\AuditPage;
|
||||||
use MediaRightsAudit\Admin\Settings;
|
use MediaRightsAudit\Admin\Settings;
|
||||||
|
use MediaRightsAudit\Admin\ToolsPage;
|
||||||
use MediaRightsAudit\CLI\Command;
|
use MediaRightsAudit\CLI\Command;
|
||||||
use MediaRightsAudit\External\AbstractProvider;
|
use MediaRightsAudit\External\AbstractProvider;
|
||||||
use MediaRightsAudit\External\ExternalScanner;
|
use MediaRightsAudit\External\ExternalScanner;
|
||||||
|
|
@ -38,12 +39,20 @@ class Plugin {
|
||||||
*/
|
*/
|
||||||
private AuditPage $audit_page;
|
private AuditPage $audit_page;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tools & Status page controller.
|
||||||
|
*
|
||||||
|
* @var ToolsPage
|
||||||
|
*/
|
||||||
|
private ToolsPage $tools_page;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialises dependencies.
|
* Initialises dependencies.
|
||||||
*/
|
*/
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->settings = new Settings();
|
$this->settings = new Settings();
|
||||||
$this->audit_page = new AuditPage();
|
$this->audit_page = new AuditPage();
|
||||||
|
$this->tools_page = new ToolsPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -59,6 +68,7 @@ class Plugin {
|
||||||
add_action( AttachmentIndexer::AS_HOOK, array( AttachmentIndexer::class, 'process_scheduled_batch' ) );
|
add_action( AttachmentIndexer::AS_HOOK, array( AttachmentIndexer::class, 'process_scheduled_batch' ) );
|
||||||
add_action( UsageScanner::AS_HOOK, array( UsageScanner::class, 'process_scheduled_batch' ) );
|
add_action( UsageScanner::AS_HOOK, array( UsageScanner::class, 'process_scheduled_batch' ) );
|
||||||
add_action( ExternalScanner::AS_HOOK, array( ExternalScanner::class, 'process_scheduled_batch' ) );
|
add_action( ExternalScanner::AS_HOOK, array( ExternalScanner::class, 'process_scheduled_batch' ) );
|
||||||
|
add_action( 'wp_ajax_mra_run_batch', array( $this->tools_page, 'ajax_run_batch' ) );
|
||||||
add_filter( 'mra/external/providers', array( $this, 'register_providers' ) );
|
add_filter( 'mra/external/providers', array( $this, 'register_providers' ) );
|
||||||
add_filter( 'wp_privacy_personal_data_exporters', array( DataExporter::class, 'register' ) );
|
add_filter( 'wp_privacy_personal_data_exporters', array( DataExporter::class, 'register' ) );
|
||||||
add_filter( 'wp_privacy_personal_data_erasers', array( DataEraser::class, 'register' ) );
|
add_filter( 'wp_privacy_personal_data_erasers', array( DataEraser::class, 'register' ) );
|
||||||
|
|
@ -107,6 +117,19 @@ class Plugin {
|
||||||
array( $this->audit_page, 'render' )
|
array( $this->audit_page, 'render' )
|
||||||
);
|
);
|
||||||
|
|
||||||
|
$tools_suffix = add_submenu_page(
|
||||||
|
'robotstxt-mediaaudit',
|
||||||
|
__( 'Tools', 'robotstxt-mediaaudit' ),
|
||||||
|
__( 'Tools', 'robotstxt-mediaaudit' ),
|
||||||
|
'manage_options',
|
||||||
|
'robotstxt-mediaaudit-tools',
|
||||||
|
array( $this->tools_page, 'render' )
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( is_string( $tools_suffix ) ) {
|
||||||
|
$this->tools_page->set_hook_suffix( $tools_suffix );
|
||||||
|
}
|
||||||
|
|
||||||
add_submenu_page(
|
add_submenu_page(
|
||||||
'robotstxt-mediaaudit',
|
'robotstxt-mediaaudit',
|
||||||
__( 'Settings', 'robotstxt-mediaaudit' ),
|
__( 'Settings', 'robotstxt-mediaaudit' ),
|
||||||
|
|
|
||||||
89
includes/External/ExternalScanner.php
vendored
89
includes/External/ExternalScanner.php
vendored
|
|
@ -184,6 +184,39 @@ class ExternalScanner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Re-queues all attachments that previously failed with external_status = 'error'.
|
||||||
|
*
|
||||||
|
* Does not touch pending, queued, scanned, or matched attachments.
|
||||||
|
* Schedules a background scan batch if any items were re-queued and
|
||||||
|
* no batch is already pending.
|
||||||
|
*
|
||||||
|
* @return int Number of attachments re-queued.
|
||||||
|
*/
|
||||||
|
public static function requeue_errors(): int {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.DirectDatabaseQuery
|
||||||
|
$count = (int) $wpdb->get_var(
|
||||||
|
"SELECT COUNT(*) FROM {$wpdb->prefix}mra_media_index WHERE external_status = 'error'"
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $count > 0 ) {
|
||||||
|
$wpdb->query(
|
||||||
|
"UPDATE {$wpdb->prefix}mra_media_index
|
||||||
|
SET external_status = 'queued', external_scanned_at = NULL
|
||||||
|
WHERE external_status = 'error'"
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! Scheduler::has_pending( self::AS_HOOK ) ) {
|
||||||
|
Scheduler::schedule_single( self::AS_HOOK );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes external scan results and resets status to pending for given IDs.
|
* Deletes external scan results and resets status to pending for given IDs.
|
||||||
*
|
*
|
||||||
|
|
@ -221,6 +254,62 @@ class ExternalScanner {
|
||||||
// phpcs:enable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all external scan results and resets every attachment's external_status to pending.
|
||||||
|
*
|
||||||
|
* @return int Number of result rows deleted.
|
||||||
|
*/
|
||||||
|
public static function purge_all(): int {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.DirectDatabaseQuery
|
||||||
|
$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}mra_external_results" );
|
||||||
|
$wpdb->query( "DELETE FROM {$wpdb->prefix}mra_external_results" );
|
||||||
|
$wpdb->query(
|
||||||
|
"UPDATE {$wpdb->prefix}mra_media_index
|
||||||
|
SET external_status = 'pending', external_scanned_at = NULL"
|
||||||
|
);
|
||||||
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a count of attachments grouped by external_status.
|
||||||
|
*
|
||||||
|
* @return array<string, int>
|
||||||
|
*/
|
||||||
|
public static function get_status_counts(): array {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$rows = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
|
||||||
|
"SELECT external_status, COUNT(*) AS cnt
|
||||||
|
FROM {$wpdb->prefix}mra_media_index
|
||||||
|
GROUP BY external_status",
|
||||||
|
ARRAY_A
|
||||||
|
);
|
||||||
|
|
||||||
|
$counts = array(
|
||||||
|
'pending' => 0,
|
||||||
|
'queued' => 0,
|
||||||
|
'scanned' => 0,
|
||||||
|
'matches' => 0,
|
||||||
|
'error' => 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( is_array( $rows ) ) {
|
||||||
|
foreach ( $rows as $row ) {
|
||||||
|
$s = is_array( $row ) && is_string( $row['external_status'] ) ? $row['external_status'] : '';
|
||||||
|
if ( isset( $counts[ $s ] ) ) {
|
||||||
|
$cnt = isset( $row['cnt'] ) && is_numeric( $row['cnt'] ) ? (int) $row['cnt'] : 0;
|
||||||
|
$counts[ $s ] = $cnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $counts;
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
// Private helpers
|
// Private helpers
|
||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -172,4 +172,21 @@ class AttachmentIndexer {
|
||||||
Scheduler::schedule_single( self::AS_HOOK );
|
Scheduler::schedule_single( self::AS_HOOK );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes all rows from mra_media_index and mra_media_usage, forcing a full re-index on the next run.
|
||||||
|
*
|
||||||
|
* @return int Number of index rows removed.
|
||||||
|
*/
|
||||||
|
public static function reset_all(): int {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.DirectDatabaseQuery
|
||||||
|
$count = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->prefix}mra_media_index" );
|
||||||
|
$wpdb->query( "DELETE FROM {$wpdb->prefix}mra_media_usage" );
|
||||||
|
$wpdb->query( "DELETE FROM {$wpdb->prefix}mra_media_index" );
|
||||||
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -461,4 +461,26 @@ class UsageScanner {
|
||||||
Scheduler::schedule_single( self::AS_HOOK );
|
Scheduler::schedule_single( self::AS_HOOK );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets usage scan state for all indexed attachments.
|
||||||
|
*
|
||||||
|
* Clears internal_scanned_at so every attachment is re-queued for scanning, and
|
||||||
|
* deletes all mra_media_usage rows. File metadata in mra_media_index is preserved.
|
||||||
|
*
|
||||||
|
* @return int Number of attachments reset.
|
||||||
|
*/
|
||||||
|
public static function reset_all(): int {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.DB.DirectDatabaseQuery
|
||||||
|
$count = (int) $wpdb->get_var(
|
||||||
|
"SELECT COUNT(*) FROM {$wpdb->prefix}mra_media_index WHERE internal_scanned_at IS NOT NULL"
|
||||||
|
);
|
||||||
|
$wpdb->query( "UPDATE {$wpdb->prefix}mra_media_index SET internal_scanned_at = NULL" );
|
||||||
|
$wpdb->query( "DELETE FROM {$wpdb->prefix}mra_media_usage" );
|
||||||
|
// phpcs:enable WordPress.DB.DirectDatabaseQuery
|
||||||
|
|
||||||
|
return $count;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2,10 +2,10 @@
|
||||||
# This file is distributed under the GPL-3.0-or-later.
|
# This file is distributed under the GPL-3.0-or-later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.0.0\n"
|
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.2.0\n"
|
||||||
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-"
|
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-"
|
||||||
"mediaaudit\n"
|
"mediaaudit\n"
|
||||||
"POT-Creation-Date: 2026-05-02T06:06:40+00:00\n"
|
"POT-Creation-Date: 2026-05-02T07:36:54+00:00\n"
|
||||||
"PO-Revision-Date: 2026-05-01 07:41+0000\n"
|
"PO-Revision-Date: 2026-05-01 07:41+0000\n"
|
||||||
"Last-Translator: Javier Casares <javier@casares.org>\n"
|
"Last-Translator: Javier Casares <javier@casares.org>\n"
|
||||||
"Language-Team: Catalan <ca@li.org>\n"
|
"Language-Team: Catalan <ca@li.org>\n"
|
||||||
|
|
@ -23,8 +23,8 @@ msgstr "Auditoria de mitjans (by ROBOTSTXT)"
|
||||||
|
|
||||||
#. Plugin URI of the plugin
|
#. Plugin URI of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "https://robotstxt.es/plugins/media-audit/"
|
msgid "https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit"
|
||||||
msgstr "https://robotstxt.es/plugins/media-audit/"
|
msgstr ""
|
||||||
|
|
||||||
#. Description of the plugin
|
#. Description of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
|
|
@ -37,279 +37,311 @@ msgstr ""
|
||||||
|
|
||||||
#. Author of the plugin
|
#. Author of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "Javier Casares"
|
msgid "ROBOTSTXT"
|
||||||
msgstr "Javier Casares"
|
msgstr ""
|
||||||
|
|
||||||
#. Author URI of the plugin
|
#. Author URI of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "https://javiercasares.com"
|
msgid "https://www.robotstxt.es/"
|
||||||
msgstr "https://javiercasares.com"
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:112
|
#: includes/Admin/AuditPage.php:114
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "S'està carregant…"
|
msgstr "S'està carregant…"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:113
|
#: includes/Admin/AuditPage.php:115
|
||||||
msgid "Error loading details."
|
msgid "Error loading details."
|
||||||
msgstr "S'ha produït un error en carregar els detalls."
|
msgstr "S'ha produït un error en carregar els detalls."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:114 includes/Admin/AuditPage.php:190
|
#: includes/Admin/AuditPage.php:116 includes/Admin/AuditPage.php:192
|
||||||
msgid "This image is not used in any post."
|
msgid "This image is not used in any post."
|
||||||
msgstr "Aquesta imatge no s'utilitza en cap entrada."
|
msgstr "Aquesta imatge no s'utilitza en cap entrada."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:115 includes/Admin/AuditPage.php:152
|
#: includes/Admin/AuditPage.php:117 includes/Admin/AuditPage.php:154
|
||||||
msgid "Usage Details"
|
msgid "Usage Details"
|
||||||
msgstr "Detalls d'ús"
|
msgstr "Detalls d'ús"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:131 includes/Admin/Settings.php:325
|
#: includes/Admin/AuditPage.php:133 includes/Admin/Settings.php:325
|
||||||
|
#: includes/Admin/ToolsPage.php:245
|
||||||
msgid "You do not have permission to access this page."
|
msgid "You do not have permission to access this page."
|
||||||
msgstr "No teniu permís per accedir a aquesta pàgina."
|
msgstr "No teniu permís per accedir a aquesta pàgina."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:138 includes/Core/Plugin.php:89
|
#: includes/Admin/AuditPage.php:140 includes/Core/Plugin.php:99
|
||||||
#: includes/Core/Plugin.php:90 includes/Core/Plugin.php:103
|
#: includes/Core/Plugin.php:100 includes/Core/Plugin.php:113
|
||||||
#: includes/Core/Plugin.php:104 includes/Privacy/DataEraser.php:33
|
#: includes/Core/Plugin.php:114 includes/Privacy/DataEraser.php:33
|
||||||
#: includes/Privacy/DataExporter.php:45
|
#: includes/Privacy/DataExporter.php:45
|
||||||
msgid "Media Audit"
|
msgid "Media Audit"
|
||||||
msgstr "Auditoria de mitjans"
|
msgstr "Auditoria de mitjans"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:144
|
#: includes/Admin/AuditPage.php:146
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Cerca"
|
msgstr "Cerca"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:153
|
#: includes/Admin/AuditPage.php:155
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Tanca"
|
msgstr "Tanca"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:171 includes/Admin/AuditPage.php:459
|
#: includes/Admin/AuditPage.php:173 includes/Admin/AuditPage.php:461
|
||||||
#: includes/Admin/AuditPage.php:510 includes/Admin/AuditPage.php:542
|
#: includes/Admin/AuditPage.php:515 includes/Admin/AuditPage.php:648
|
||||||
|
#: includes/Admin/AuditPage.php:680 includes/Admin/ToolsPage.php:105
|
||||||
|
#: includes/Admin/ToolsPage.php:161
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr "Permisos insuficients."
|
msgstr "Permisos insuficients."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:176
|
#: includes/Admin/AuditPage.php:178
|
||||||
msgid "Invalid attachment ID."
|
msgid "Invalid attachment ID."
|
||||||
msgstr "Identificador de fitxer adjunt no vàlid."
|
msgstr "Identificador de fitxer adjunt no vàlid."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:184
|
#: includes/Admin/AuditPage.php:186
|
||||||
msgid "Featured Image"
|
msgid "Featured Image"
|
||||||
msgstr "Imatge destacada"
|
msgstr "Imatge destacada"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:185
|
#: includes/Admin/AuditPage.php:187
|
||||||
msgid "Post Content"
|
msgid "Post Content"
|
||||||
msgstr "Contingut de l'entrada"
|
msgstr "Contingut de l'entrada"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:186
|
#: includes/Admin/AuditPage.php:188
|
||||||
msgid "Custom Field"
|
msgid "Custom Field"
|
||||||
msgstr "Camp personalitzat"
|
msgstr "Camp personalitzat"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:194
|
#: includes/Admin/AuditPage.php:196
|
||||||
msgid "Post"
|
msgid "Post"
|
||||||
msgstr "Entrada"
|
msgstr "Entrada"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:195
|
#: includes/Admin/AuditPage.php:197
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr "Tipus"
|
msgstr "Tipus"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:196
|
#: includes/Admin/AuditPage.php:198
|
||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr "Context"
|
msgstr "Context"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:197
|
#: includes/Admin/AuditPage.php:199
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Estat"
|
msgstr "Estat"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:240
|
#: includes/Admin/AuditPage.php:242
|
||||||
msgid "Internal Usage"
|
msgid "Internal Usage"
|
||||||
msgstr "Ús intern"
|
msgstr "Ús intern"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:288
|
#: includes/Admin/AuditPage.php:290
|
||||||
msgid "External Scan Results"
|
msgid "External Scan Results"
|
||||||
msgstr "Resultats de l'exploració externa"
|
msgstr "Resultats de l'exploració externa"
|
||||||
|
|
||||||
#. translators: %d: number of external matches
|
#. translators: %d: number of external matches
|
||||||
#: includes/Admin/AuditPage.php:312
|
#: includes/Admin/AuditPage.php:314
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d match"
|
msgid "%d match"
|
||||||
msgid_plural "%d matches"
|
msgid_plural "%d matches"
|
||||||
msgstr[0] "%d coincidència"
|
msgstr[0] "%d coincidència"
|
||||||
msgstr[1] "%d coincidències"
|
msgstr[1] "%d coincidències"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:317
|
#: includes/Admin/AuditPage.php:319
|
||||||
msgid "No matches"
|
msgid "No matches"
|
||||||
msgstr "Sense coincidències"
|
msgstr "Sense coincidències"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:328
|
#: includes/Admin/AuditPage.php:330
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Domini"
|
msgstr "Domini"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:329
|
#: includes/Admin/AuditPage.php:331
|
||||||
msgid "Occurrences"
|
msgid "Occurrences"
|
||||||
msgstr "Aparicions"
|
msgstr "Aparicions"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:350
|
#: includes/Admin/AuditPage.php:352
|
||||||
msgid "Consensus Domains"
|
msgid "Consensus Domains"
|
||||||
msgstr "Dominis de consens"
|
msgstr "Dominis de consens"
|
||||||
|
|
||||||
#. translators: %d: number of providers that agree
|
#. translators: %d: number of providers that agree
|
||||||
#: includes/Admin/AuditPage.php:356
|
#: includes/Admin/AuditPage.php:358
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d provider"
|
msgid "%d provider"
|
||||||
msgid_plural "%d providers"
|
msgid_plural "%d providers"
|
||||||
msgstr[0] "%d proveïdor"
|
msgstr[0] "%d proveïdor"
|
||||||
msgstr[1] "%d proveïdors"
|
msgstr[1] "%d proveïdors"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:388
|
#: includes/Admin/AuditPage.php:390
|
||||||
msgid "In Index"
|
msgid "In Index"
|
||||||
msgstr "A l'índex"
|
msgstr "A l'índex"
|
||||||
|
|
||||||
#. translators: %d: count of images not yet indexed
|
#. translators: %d: count of images not yet indexed
|
||||||
#: includes/Admin/AuditPage.php:392
|
#: includes/Admin/AuditPage.php:394
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d not yet indexed"
|
msgid "%d not yet indexed"
|
||||||
msgstr "%d encara no indexades"
|
msgstr "%d encara no indexades"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:395
|
#: includes/Admin/AuditPage.php:397
|
||||||
msgid "All indexed"
|
msgid "All indexed"
|
||||||
msgstr "Totes indexades"
|
msgstr "Totes indexades"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:400 includes/Admin/MediaListTable.php:275
|
#: includes/Admin/AuditPage.php:402 includes/Admin/MediaListTable.php:278
|
||||||
msgid "Scanned"
|
msgid "Scanned"
|
||||||
msgstr "Explorades"
|
msgstr "Explorades"
|
||||||
|
|
||||||
#. translators: %d: percentage
|
#. translators: %d: percentage
|
||||||
#: includes/Admin/AuditPage.php:403
|
#: includes/Admin/AuditPage.php:405
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d%% of index"
|
msgid "%d%% of index"
|
||||||
msgstr "%d%% de l'índex"
|
msgstr "%d%% de l'índex"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:410
|
#: includes/Admin/AuditPage.php:412
|
||||||
msgid "Used"
|
msgid "Used"
|
||||||
msgstr "Usades"
|
msgstr "Usades"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:416 includes/Admin/MediaListTable.php:200
|
#: includes/Admin/AuditPage.php:418 includes/Admin/MediaListTable.php:203
|
||||||
msgid "Unused"
|
msgid "Unused"
|
||||||
msgstr "No usades"
|
msgstr "No usades"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:423
|
#: includes/Admin/AuditPage.php:425
|
||||||
msgid "External Matches"
|
msgid "External Matches"
|
||||||
msgstr "Coincidències externes"
|
msgstr "Coincidències externes"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:473
|
#: includes/Admin/AuditPage.php:475 includes/Admin/AuditPage.php:529
|
||||||
msgid "Could not open output stream."
|
msgid "Could not open output stream."
|
||||||
msgstr "No s'ha pogut obrir el flux de sortida."
|
msgstr "No s'ha pogut obrir el flux de sortida."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:482 includes/Privacy/DataExporter.php:257
|
#: includes/Admin/AuditPage.php:484 includes/Admin/AuditPage.php:537
|
||||||
#: includes/Privacy/DataExporter.php:299
|
#: includes/Privacy/DataExporter.php:257 includes/Privacy/DataExporter.php:299
|
||||||
msgid "Attachment ID"
|
msgid "Attachment ID"
|
||||||
msgstr "ID del fitxer adjunt"
|
msgstr "ID del fitxer adjunt"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:483 includes/Admin/MediaListTable.php:52
|
#: includes/Admin/AuditPage.php:485 includes/Admin/AuditPage.php:538
|
||||||
#: includes/Privacy/DataExporter.php:261
|
#: includes/Admin/MediaListTable.php:52 includes/Privacy/DataExporter.php:261
|
||||||
msgid "Filename"
|
msgid "Filename"
|
||||||
msgstr "Nom de fitxer"
|
msgstr "Nom de fitxer"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:484 includes/Privacy/DataExporter.php:265
|
#: includes/Admin/AuditPage.php:486 includes/Admin/AuditPage.php:539
|
||||||
|
#: includes/Privacy/DataExporter.php:265
|
||||||
msgid "File URL"
|
msgid "File URL"
|
||||||
msgstr "URL del fitxer"
|
msgstr "URL del fitxer"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:485
|
#: includes/Admin/AuditPage.php:487
|
||||||
msgid "MIME Type"
|
msgid "MIME Type"
|
||||||
msgstr "Tipus MIME"
|
msgstr "Tipus MIME"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:486
|
#: includes/Admin/AuditPage.php:488
|
||||||
msgid "File Size (bytes)"
|
msgid "File Size (bytes)"
|
||||||
msgstr "Mida del fitxer (bytes)"
|
msgstr "Mida del fitxer (bytes)"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:487 includes/Admin/MediaListTable.php:56
|
#: includes/Admin/AuditPage.php:489 includes/Admin/AuditPage.php:540
|
||||||
|
#: includes/Admin/MediaListTable.php:56
|
||||||
msgid "External Status"
|
msgid "External Status"
|
||||||
msgstr "Estat extern"
|
msgstr "Estat extern"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:488 includes/Admin/MediaListTable.php:54
|
#: includes/Admin/AuditPage.php:490 includes/Admin/MediaListTable.php:54
|
||||||
msgid "Usage Count"
|
msgid "Usage Count"
|
||||||
msgstr "Nombre d'usos"
|
msgstr "Nombre d'usos"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:489
|
#: includes/Admin/AuditPage.php:491
|
||||||
msgid "Used In (post titles)"
|
msgid "Used In (post titles)"
|
||||||
msgstr "Usat a (títols d'entrades)"
|
msgstr "Usat a (títols d'entrades)"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:541 includes/Admin/MediaListTable.php:57
|
||||||
|
msgid "Last Scanned"
|
||||||
|
msgstr "Darrera exploració"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:542 includes/Privacy/DataExporter.php:303
|
||||||
|
msgid "Provider"
|
||||||
|
msgstr "Proveïdor"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:543 includes/Privacy/DataExporter.php:307
|
||||||
|
msgid "Match Count"
|
||||||
|
msgstr "Nombre de coincidències"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:544
|
||||||
|
msgid "Top Domains"
|
||||||
|
msgstr "Dominis principals"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:51
|
#: includes/Admin/MediaListTable.php:51
|
||||||
msgid "Thumbnail"
|
msgid "Thumbnail"
|
||||||
msgstr "Miniatura"
|
msgstr "Miniatura"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:53
|
#: includes/Admin/MediaListTable.php:53
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr ""
|
msgstr "ID"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:55
|
#: includes/Admin/MediaListTable.php:55
|
||||||
msgid "Usages"
|
msgid "Usages"
|
||||||
msgstr "Usos"
|
msgstr "Usos"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:79
|
#: includes/Admin/MediaListTable.php:81
|
||||||
msgid "Run External Scan"
|
msgid "Run External Scan"
|
||||||
msgstr "Executar exploració externa"
|
msgstr "Executar exploració externa"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:80
|
#: includes/Admin/MediaListTable.php:82
|
||||||
msgid "Purge External Data"
|
msgid "Purge External Data"
|
||||||
msgstr "Eliminar dades externes"
|
msgstr "Eliminar dades externes"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:81
|
#: includes/Admin/MediaListTable.php:83
|
||||||
msgid "Export CSV"
|
msgid "Export CSV"
|
||||||
msgstr "Exportar CSV"
|
msgstr "Exportar CSV"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:165
|
#: includes/Admin/MediaListTable.php:84
|
||||||
|
msgid "Export External Results CSV"
|
||||||
|
msgstr "Exportar CSV de resultats externs"
|
||||||
|
|
||||||
|
#: includes/Admin/MediaListTable.php:168
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Edita"
|
msgstr "Edita"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:170
|
#: includes/Admin/MediaListTable.php:173
|
||||||
msgid "View Details"
|
msgid "View Details"
|
||||||
msgstr "Visualitza els detalls"
|
msgstr "Visualitza els detalls"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:236
|
#: includes/Admin/MediaListTable.php:239
|
||||||
msgid "(no title)"
|
msgid "(no title)"
|
||||||
msgstr "(sense títol)"
|
msgstr "(sense títol)"
|
||||||
|
|
||||||
#. translators: %d: number of additional usages
|
#. translators: %d: number of additional usages
|
||||||
#: includes/Admin/MediaListTable.php:251
|
#: includes/Admin/MediaListTable.php:254
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "+ %d more…"
|
msgid "+ %d more…"
|
||||||
msgstr "+ %d més…"
|
msgstr "+ %d més…"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:273
|
#: includes/Admin/MediaListTable.php:276 includes/Admin/ToolsPage.php:580
|
||||||
|
#: includes/Admin/ToolsPage.php:581 includes/Admin/ToolsPage.php:582
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "Pendent"
|
msgstr "Pendent"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:274
|
#: includes/Admin/MediaListTable.php:277
|
||||||
msgid "Queued"
|
msgid "Queued"
|
||||||
msgstr "En cua"
|
msgstr "En cua"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:276
|
#: includes/Admin/MediaListTable.php:279
|
||||||
msgid "Matches Found"
|
msgid "Matches Found"
|
||||||
msgstr "Coincidències trobades"
|
msgstr "Coincidències trobades"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:277
|
#: includes/Admin/MediaListTable.php:280
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Error"
|
msgstr "Error"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:305
|
#: includes/Admin/MediaListTable.php:308
|
||||||
msgid "View Results"
|
msgid "View Results"
|
||||||
msgstr "Visualitza els resultats"
|
msgstr "Visualitza els resultats"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:336
|
#. translators: %s: human-readable time difference, e.g. "3 days"
|
||||||
|
#: includes/Admin/MediaListTable.php:350
|
||||||
|
#, php-format
|
||||||
|
msgid "%s ago"
|
||||||
|
msgstr "fa %s"
|
||||||
|
|
||||||
|
#: includes/Admin/MediaListTable.php:380
|
||||||
msgid "All statuses"
|
msgid "All statuses"
|
||||||
msgstr "Tots els estats"
|
msgstr "Tots els estats"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:350
|
#: includes/Admin/MediaListTable.php:394
|
||||||
msgid "All post types"
|
msgid "All post types"
|
||||||
msgstr "Tots els tipus d'entrada"
|
msgstr "Tots els tipus d'entrada"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:365
|
#: includes/Admin/MediaListTable.php:409
|
||||||
msgid "Unused only"
|
msgid "Unused only"
|
||||||
msgstr "Només no usades"
|
msgstr "Només no usades"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:368
|
#: includes/Admin/MediaListTable.php:412
|
||||||
msgid "Filter"
|
msgid "Filter"
|
||||||
msgstr "Filtra"
|
msgstr "Filtra"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:378
|
#: includes/Admin/MediaListTable.php:422
|
||||||
msgid ""
|
msgid ""
|
||||||
"No indexed attachments found. Run wp mra scan-internal to populate the index."
|
"No indexed attachments found. Run wp mra scan-internal to populate the index."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -434,6 +466,417 @@ msgstr ""
|
||||||
"Nombre màxim de sol·licituds d'API per minut per proveïdor (1–60). Per "
|
"Nombre màxim de sol·licituds d'API per minut per proveïdor (1–60). Per "
|
||||||
"defecte: 10."
|
"defecte: 10."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:85
|
||||||
|
msgid "Done."
|
||||||
|
msgstr "Fet."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:86
|
||||||
|
msgid "Stopped."
|
||||||
|
msgstr "Aturat."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:87
|
||||||
|
msgid "An error occurred."
|
||||||
|
msgstr "S'ha produït un error."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:139
|
||||||
|
msgid "Invalid batch type."
|
||||||
|
msgstr "Tipus de lot no vàlid."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:256
|
||||||
|
msgid "System Status"
|
||||||
|
msgstr "Estat del sistema"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:259
|
||||||
|
msgid "Operations"
|
||||||
|
msgstr "Operacions"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:262
|
||||||
|
msgid "Direct scan runner"
|
||||||
|
msgstr "Executor d'exploració directa"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:264
|
||||||
|
msgid ""
|
||||||
|
"Run scan batches directly from your browser without relying on background "
|
||||||
|
"jobs. Useful when WP-Cron is disabled or Action Scheduler is not running. "
|
||||||
|
"Keep this tab open while processing."
|
||||||
|
msgstr ""
|
||||||
|
"Executeu lots d'exploració directament des del navegador sense dependre de "
|
||||||
|
"treballs en segon pla. Útil quan WP-Cron està desactivat o Action Scheduler "
|
||||||
|
"no s'està executant. Manteniu aquesta pestanya oberta mentre es processa."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:300
|
||||||
|
msgid "not installed"
|
||||||
|
msgstr "no instal·lat"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:358
|
||||||
|
msgid "Internal scan scheduled."
|
||||||
|
msgstr "Exploració interna programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:359
|
||||||
|
msgid "External scan scheduled."
|
||||||
|
msgstr "Exploració externa programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:360
|
||||||
|
msgid "Failed scans re-queued. Background scan scheduled."
|
||||||
|
msgstr ""
|
||||||
|
"Exploracions fallides reencolades. Exploració en segon pla "
|
||||||
|
"programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:361
|
||||||
|
msgid "Usage data cleared. Background scan scheduled."
|
||||||
|
msgstr "Dades d'ús eliminades. Exploració en segon pla programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:362
|
||||||
|
msgid "Index cleared. Fresh indexing scheduled."
|
||||||
|
msgstr "Índex eliminat. Nova indexació programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:363
|
||||||
|
msgid "External scan data purged."
|
||||||
|
msgstr "Dades d'exploració externa eliminades."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:364
|
||||||
|
msgid "All data reset. Fresh indexing scheduled."
|
||||||
|
msgstr "Totes les dades restablertes. Nova indexació programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:367
|
||||||
|
msgid "Operation completed."
|
||||||
|
msgstr "Operació completada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:411
|
||||||
|
msgid "Database schema"
|
||||||
|
msgstr "Esquema de base de dades"
|
||||||
|
|
||||||
|
#. translators: %s: version number
|
||||||
|
#: includes/Admin/ToolsPage.php:417
|
||||||
|
#, php-format
|
||||||
|
msgid "v%s – up to date"
|
||||||
|
msgstr "v%s – actualitzat"
|
||||||
|
|
||||||
|
#. translators: 1: stored version, 2: expected version
|
||||||
|
#: includes/Admin/ToolsPage.php:423
|
||||||
|
#, php-format
|
||||||
|
msgid "Installed: %1$s — Required: %2$s"
|
||||||
|
msgstr "Instal·lat: %1$s — Requerit: %2$s"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:432
|
||||||
|
msgid "Deactivate and reactivate the plugin to apply pending migrations."
|
||||||
|
msgstr ""
|
||||||
|
"Desactiveu i reactiveu el connector per aplicar les migracions "
|
||||||
|
"pendents."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:439
|
||||||
|
msgid "Action Scheduler"
|
||||||
|
msgstr "Action Scheduler"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:442
|
||||||
|
msgid "Available"
|
||||||
|
msgstr "Disponible"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:444
|
||||||
|
msgid "Not available"
|
||||||
|
msgstr "No disponible"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:449
|
||||||
|
msgid ""
|
||||||
|
"Install and activate the Action Scheduler plugin. Background scanning will "
|
||||||
|
"not work without it."
|
||||||
|
msgstr ""
|
||||||
|
"Instal·leu i activeu el connector Action Scheduler. L'exploració en segon "
|
||||||
|
"pla no funcionarà sense ell."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:456
|
||||||
|
msgid "WP-Cron"
|
||||||
|
msgstr "WP-Cron"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:459
|
||||||
|
msgid "Disabled (DISABLE_WP_CRON)"
|
||||||
|
msgstr "Desactivat (DISABLE_WP_CRON)"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:461
|
||||||
|
msgid "Enabled"
|
||||||
|
msgstr "Activat"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:466
|
||||||
|
msgid ""
|
||||||
|
"Background jobs will not fire automatically. Trigger the cron externally or "
|
||||||
|
"use WP-CLI:"
|
||||||
|
msgstr ""
|
||||||
|
"Els treballs en segon pla no s'executaran automàticament. Activeu el cron "
|
||||||
|
"externament o useu WP-CLI:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:474
|
||||||
|
msgid "Internal index"
|
||||||
|
msgstr "Índex intern"
|
||||||
|
|
||||||
|
#. translators: 1: indexed count, 2: total images
|
||||||
|
#: includes/Admin/ToolsPage.php:479
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s / %2$s images indexed"
|
||||||
|
msgstr "%1$s / %2$s imatges indexades"
|
||||||
|
|
||||||
|
#. translators: %s: formatted count
|
||||||
|
#: includes/Admin/ToolsPage.php:490
|
||||||
|
#, php-format
|
||||||
|
msgid "%s image not yet indexed."
|
||||||
|
msgid_plural "%s images not yet indexed."
|
||||||
|
msgstr[0] "%s imatge encara no indexada."
|
||||||
|
msgstr[1] "%s imatges encara no indexades."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:494
|
||||||
|
msgid "Schedule an internal scan below."
|
||||||
|
msgstr "Programeu una exploració interna a continuació."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:502
|
||||||
|
msgid "Usage scan"
|
||||||
|
msgstr "Exploració d'ús"
|
||||||
|
|
||||||
|
#. translators: 1: scanned count, 2: total indexed
|
||||||
|
#: includes/Admin/ToolsPage.php:507
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s / %2$s scanned for usage"
|
||||||
|
msgstr "%1$s / %2$s explorades per a ús"
|
||||||
|
|
||||||
|
#. translators: %s: formatted count
|
||||||
|
#: includes/Admin/ToolsPage.php:518
|
||||||
|
#, php-format
|
||||||
|
msgid "%s pending."
|
||||||
|
msgid_plural "%s pending."
|
||||||
|
msgstr[0] "%s pendent."
|
||||||
|
msgstr[1] "%s pendents."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:539 includes/Admin/ToolsPage.php:736
|
||||||
|
msgid "External scan"
|
||||||
|
msgstr "Exploració externa"
|
||||||
|
|
||||||
|
#. translators: 1: scanned 2: matches 3: queued 4: pending 5: errors
|
||||||
|
#: includes/Admin/ToolsPage.php:544
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s scanned · %2$s matches · %3$s queued · %4$s pending · %5$s errors"
|
||||||
|
msgstr ""
|
||||||
|
"%1$s explorades · %2$s coincidències · %3$s en cua · %4$s pendents · "
|
||||||
|
"%5$s errors"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:555
|
||||||
|
msgid ""
|
||||||
|
"Some scans failed. Check that API keys are configured correctly in Settings."
|
||||||
|
msgstr ""
|
||||||
|
"Algunes exploracions han fallat. Comproveu que les claus d'API estan "
|
||||||
|
"configurades correctament a la Configuració."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:557
|
||||||
|
msgid "Schedule an external scan below to process pending items."
|
||||||
|
msgstr ""
|
||||||
|
"Programeu una exploració externa a continuació per processar els elements "
|
||||||
|
"pendents."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:575
|
||||||
|
msgid "Scheduled jobs"
|
||||||
|
msgstr "Treballs programats"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:578
|
||||||
|
msgid "Action Scheduler not available."
|
||||||
|
msgstr "Action Scheduler no disponible."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:580
|
||||||
|
msgid "Index:"
|
||||||
|
msgstr "Índex:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:581
|
||||||
|
msgid "Usage:"
|
||||||
|
msgstr "Ús:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:582
|
||||||
|
msgid "External:"
|
||||||
|
msgstr "Extern:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:587
|
||||||
|
msgid ""
|
||||||
|
"There is work to do but no background job is scheduled. Use the operations "
|
||||||
|
"below."
|
||||||
|
msgstr ""
|
||||||
|
"Hi ha feina pendent però no hi ha cap treball en segon pla programat. "
|
||||||
|
"Useu les operacions de sota."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:589
|
||||||
|
msgid "WP-Cron is disabled. Jobs will not fire automatically."
|
||||||
|
msgstr ""
|
||||||
|
"WP-Cron està desactivat. Els treballs no s'executaran "
|
||||||
|
"automàticament."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:599
|
||||||
|
msgid "WP-CLI commands to process scans manually:"
|
||||||
|
msgstr "Comandes WP-CLI per processar exploracions manualment:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:616
|
||||||
|
msgid "Schedule internal scan"
|
||||||
|
msgstr "Programar exploració interna"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:617
|
||||||
|
msgid ""
|
||||||
|
"Queue a background job to index all unindexed media files and scan their "
|
||||||
|
"usage across posts, pages, and custom fields. Safe to run at any time — will "
|
||||||
|
"not re-process completed work."
|
||||||
|
msgstr ""
|
||||||
|
"Posa en cua un treball en segon pla per indexar tots els fitxers multimèdia "
|
||||||
|
"no indexats i explorar el seu ús en entrades, pàgines i camps personalitzats. "
|
||||||
|
"Es pot executar en qualsevol moment: no reprocessarà el treball ja completat."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:623
|
||||||
|
msgid "Schedule external scan"
|
||||||
|
msgstr "Programar exploració externa"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:624
|
||||||
|
msgid ""
|
||||||
|
"Mark all pending attachments as queued and launch a background reverse-image-"
|
||||||
|
"search via the configured providers. Requires API keys in Settings."
|
||||||
|
msgstr ""
|
||||||
|
"Marca tots els fitxers adjunts pendents com en cua i llança una cerca inversa "
|
||||||
|
"d'imatges en segon pla a través dels proveïdors configurats. Requereix claus "
|
||||||
|
"d'API a la Configuració."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:630
|
||||||
|
msgid "Requeue scan errors"
|
||||||
|
msgstr "Reencolar errors d'exploració"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:631
|
||||||
|
msgid ""
|
||||||
|
"Re-queues only the attachments that failed with an error on the last "
|
||||||
|
"external scan run. Does not affect already-scanned items. Useful to retry "
|
||||||
|
"after fixing API key issues."
|
||||||
|
msgstr ""
|
||||||
|
"Reencola només els fitxers adjunts que van fallar amb un error en l'última "
|
||||||
|
"execució de l'exploració externa. No afecta els elements ja explorats. "
|
||||||
|
"Útil per reintentar després de corregir problemes amb les claus d'API."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:640
|
||||||
|
msgid "Reset usage data"
|
||||||
|
msgstr "Restablir dades d'ús"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:641
|
||||||
|
msgid ""
|
||||||
|
"Clears all usage rows and resets the usage-scan flag for every indexed "
|
||||||
|
"attachment. File metadata in the index is preserved. A background usage scan "
|
||||||
|
"is scheduled immediately after."
|
||||||
|
msgstr ""
|
||||||
|
"Elimina totes les files d'ús i restableix l'indicador d'exploració d'ús per "
|
||||||
|
"a cada fitxer adjunt indexat. Els metadades del fitxer a l'índex es "
|
||||||
|
"conserven. Es programa una exploració en segon pla immediatament després."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:643
|
||||||
|
msgid "This will delete all usage data. Continue?"
|
||||||
|
msgstr "Això eliminarà totes les dades d'ús. Voleu continuar?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:647
|
||||||
|
msgid "Re-index media library"
|
||||||
|
msgstr "Re-indexar la biblioteca de mitjans"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:648
|
||||||
|
msgid ""
|
||||||
|
"Deletes all index and usage entries, then schedules a full fresh re-index. "
|
||||||
|
"External scan results are not affected. Useful if many media files have been "
|
||||||
|
"added or removed."
|
||||||
|
msgstr ""
|
||||||
|
"Elimina totes les entrades de l'índex i d'ús, i després programa una "
|
||||||
|
"re-indexació completa. Els resultats de l'exploració externa no es veuen "
|
||||||
|
"afectats. Útil si s'han afegit o eliminat molts fitxers multimèdia."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:650
|
||||||
|
msgid "This will delete all index and usage data. Continue?"
|
||||||
|
msgstr "Això eliminarà totes les dades de l'índex i d'ús. Voleu continuar?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:654
|
||||||
|
msgid "Purge external data"
|
||||||
|
msgstr "Purgar dades externes"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:655
|
||||||
|
msgid ""
|
||||||
|
"Deletes all external scan results and resets every attachment's external "
|
||||||
|
"status to pending. Use this before switching API providers or to force a "
|
||||||
|
"complete re-scan."
|
||||||
|
msgstr ""
|
||||||
|
"Elimina tots els resultats de l'exploració externa i restableix l'estat "
|
||||||
|
"extern de cada fitxer adjunt a pendent. Useu-ho abans de canviar de "
|
||||||
|
"proveïdors d'API o per forçar una exploració completa."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:657
|
||||||
|
msgid "This will delete all external scan results. Continue?"
|
||||||
|
msgstr ""
|
||||||
|
"Això eliminarà tots els resultats de l'exploració externa. Voleu "
|
||||||
|
"continuar?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:661
|
||||||
|
msgid "Reset all data"
|
||||||
|
msgstr "Restablir totes les dades"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:662
|
||||||
|
msgid ""
|
||||||
|
"Truncates all three plugin tables (index, usage, external results) and "
|
||||||
|
"schedules a fresh indexing run. Use this to start completely from scratch."
|
||||||
|
msgstr ""
|
||||||
|
"Buida les tres taules del connector (índex, ús, resultats externs) i "
|
||||||
|
"programa una nova indexació. Useu-ho per començar completament des de zero."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:664
|
||||||
|
msgid ""
|
||||||
|
"This will permanently delete ALL plugin data and cannot be undone. Are you "
|
||||||
|
"absolutely sure?"
|
||||||
|
msgstr ""
|
||||||
|
"Això eliminarà TOTES les dades del connector de forma permanent i no es pot "
|
||||||
|
"desfer. Esteu absolutament segurs?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:675
|
||||||
|
msgid "Destructive operations"
|
||||||
|
msgstr "Operacions destructives"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:678
|
||||||
|
msgid ""
|
||||||
|
"These operations permanently delete plugin data. Intended for forced "
|
||||||
|
"rescans, troubleshooting, or starting fresh. A confirmation prompt will "
|
||||||
|
"appear before any action is taken."
|
||||||
|
msgstr ""
|
||||||
|
"Aquestes operacions eliminen les dades del connector de forma permanent. "
|
||||||
|
"Pensades per forçar re-exploracions, solucionar problemes o començar des de "
|
||||||
|
"zero. Apareixerà una confirmació abans d'executar qualsevol acció."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:726
|
||||||
|
msgid "Index media files"
|
||||||
|
msgstr "Indexar fitxers multimèdia"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:727
|
||||||
|
msgid ""
|
||||||
|
"Discovers unindexed images and registers them in the plugin index. Run this "
|
||||||
|
"first."
|
||||||
|
msgstr ""
|
||||||
|
"Descobreix imatges no indexades i les registra a l'índex del connector. "
|
||||||
|
"Executeu-ho primer."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:731
|
||||||
|
msgid "Scan usage"
|
||||||
|
msgstr "Explorar l'ús"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:732
|
||||||
|
msgid ""
|
||||||
|
"Checks every indexed image for usage across posts, pages, and custom fields."
|
||||||
|
msgstr ""
|
||||||
|
"Comprova l'ús de cada imatge indexada en entrades, pàgines i camps "
|
||||||
|
"personalitzats."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:737
|
||||||
|
msgid ""
|
||||||
|
"Sends images to external providers for reverse-image search. Requires API "
|
||||||
|
"keys in Settings."
|
||||||
|
msgstr ""
|
||||||
|
"Envia imatges a proveïdors externs per a la cerca inversa d'imatges. "
|
||||||
|
"Requereix claus d'API a la Configuració."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:754
|
||||||
|
msgid "Run now"
|
||||||
|
msgstr "Executa ara"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:757
|
||||||
|
msgid "Stop"
|
||||||
|
msgstr "Atura"
|
||||||
|
|
||||||
#. translators: %s: DB version number
|
#. translators: %s: DB version number
|
||||||
#: includes/CLI/Command.php:49
|
#: includes/CLI/Command.php:49
|
||||||
#, php-format
|
#, php-format
|
||||||
|
|
@ -494,7 +937,11 @@ msgstr "S'estan executant les exploracions externes…"
|
||||||
msgid "External scan complete. %d attachments processed."
|
msgid "External scan complete. %d attachments processed."
|
||||||
msgstr "Exploració externa completada. %d fitxers adjunts processats."
|
msgstr "Exploració externa completada. %d fitxers adjunts processats."
|
||||||
|
|
||||||
#: includes/Core/Plugin.php:112 includes/Core/Plugin.php:113
|
#: includes/Core/Plugin.php:122 includes/Core/Plugin.php:123
|
||||||
|
msgid "Tools"
|
||||||
|
msgstr "Eines"
|
||||||
|
|
||||||
|
#: includes/Core/Plugin.php:135 includes/Core/Plugin.php:136
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Configuració"
|
msgstr "Configuració"
|
||||||
|
|
||||||
|
|
@ -522,14 +969,15 @@ msgstr "Última exploració (interna)"
|
||||||
msgid "Last Scanned (external)"
|
msgid "Last Scanned (external)"
|
||||||
msgstr "Última exploració (externa)"
|
msgstr "Última exploració (externa)"
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:303
|
|
||||||
msgid "Provider"
|
|
||||||
msgstr "Proveïdor"
|
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:307
|
|
||||||
msgid "Match Count"
|
|
||||||
msgstr "Nombre de coincidències"
|
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:311
|
#: includes/Privacy/DataExporter.php:311
|
||||||
msgid "Scanned At"
|
msgid "Scanned At"
|
||||||
msgstr "Explorat el"
|
msgstr "Explorat el"
|
||||||
|
|
||||||
|
#~ msgid "https://robotstxt.es/plugins/media-audit/"
|
||||||
|
#~ msgstr "https://robotstxt.es/plugins/media-audit/"
|
||||||
|
|
||||||
|
#~ msgid "Javier Casares"
|
||||||
|
#~ msgstr "Javier Casares"
|
||||||
|
|
||||||
|
#~ msgid "https://javiercasares.com"
|
||||||
|
#~ msgstr "https://javiercasares.com"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2,10 +2,10 @@
|
||||||
# This file is distributed under the GPL-3.0-or-later.
|
# This file is distributed under the GPL-3.0-or-later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.0.0\n"
|
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.2.0\n"
|
||||||
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-"
|
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-"
|
||||||
"mediaaudit\n"
|
"mediaaudit\n"
|
||||||
"POT-Creation-Date: 2026-05-02T06:06:40+00:00\n"
|
"POT-Creation-Date: 2026-05-02T07:36:54+00:00\n"
|
||||||
"PO-Revision-Date: 2026-05-01 07:41+0000\n"
|
"PO-Revision-Date: 2026-05-01 07:41+0000\n"
|
||||||
"Last-Translator: Javier Casares <javier@casares.org>\n"
|
"Last-Translator: Javier Casares <javier@casares.org>\n"
|
||||||
"Language-Team: Spanish (Spain) <es@li.org>\n"
|
"Language-Team: Spanish (Spain) <es@li.org>\n"
|
||||||
|
|
@ -23,8 +23,8 @@ msgstr "Auditoría de medios (by ROBOTSTXT)"
|
||||||
|
|
||||||
#. Plugin URI of the plugin
|
#. Plugin URI of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "https://robotstxt.es/plugins/media-audit/"
|
msgid "https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit"
|
||||||
msgstr "https://robotstxt.es/plugins/media-audit/"
|
msgstr ""
|
||||||
|
|
||||||
#. Description of the plugin
|
#. Description of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
|
|
@ -37,279 +37,311 @@ msgstr ""
|
||||||
|
|
||||||
#. Author of the plugin
|
#. Author of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "Javier Casares"
|
msgid "ROBOTSTXT"
|
||||||
msgstr "Javier Casares"
|
msgstr ""
|
||||||
|
|
||||||
#. Author URI of the plugin
|
#. Author URI of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "https://javiercasares.com"
|
msgid "https://www.robotstxt.es/"
|
||||||
msgstr "https://javiercasares.com"
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:112
|
#: includes/Admin/AuditPage.php:114
|
||||||
msgid "Loading…"
|
msgid "Loading…"
|
||||||
msgstr "Cargando…"
|
msgstr "Cargando…"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:113
|
#: includes/Admin/AuditPage.php:115
|
||||||
msgid "Error loading details."
|
msgid "Error loading details."
|
||||||
msgstr "Error al cargar los detalles."
|
msgstr "Error al cargar los detalles."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:114 includes/Admin/AuditPage.php:190
|
#: includes/Admin/AuditPage.php:116 includes/Admin/AuditPage.php:192
|
||||||
msgid "This image is not used in any post."
|
msgid "This image is not used in any post."
|
||||||
msgstr "Esta imagen no se usa en ninguna entrada."
|
msgstr "Esta imagen no se usa en ninguna entrada."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:115 includes/Admin/AuditPage.php:152
|
#: includes/Admin/AuditPage.php:117 includes/Admin/AuditPage.php:154
|
||||||
msgid "Usage Details"
|
msgid "Usage Details"
|
||||||
msgstr "Detalles de uso"
|
msgstr "Detalles de uso"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:131 includes/Admin/Settings.php:325
|
#: includes/Admin/AuditPage.php:133 includes/Admin/Settings.php:325
|
||||||
|
#: includes/Admin/ToolsPage.php:245
|
||||||
msgid "You do not have permission to access this page."
|
msgid "You do not have permission to access this page."
|
||||||
msgstr "No tienes permiso para acceder a esta página."
|
msgstr "No tienes permiso para acceder a esta página."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:138 includes/Core/Plugin.php:89
|
#: includes/Admin/AuditPage.php:140 includes/Core/Plugin.php:99
|
||||||
#: includes/Core/Plugin.php:90 includes/Core/Plugin.php:103
|
#: includes/Core/Plugin.php:100 includes/Core/Plugin.php:113
|
||||||
#: includes/Core/Plugin.php:104 includes/Privacy/DataEraser.php:33
|
#: includes/Core/Plugin.php:114 includes/Privacy/DataEraser.php:33
|
||||||
#: includes/Privacy/DataExporter.php:45
|
#: includes/Privacy/DataExporter.php:45
|
||||||
msgid "Media Audit"
|
msgid "Media Audit"
|
||||||
msgstr "Auditoría de medios"
|
msgstr "Auditoría de medios"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:144
|
#: includes/Admin/AuditPage.php:146
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr "Buscar"
|
msgstr "Buscar"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:153
|
#: includes/Admin/AuditPage.php:155
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Cerrar"
|
msgstr "Cerrar"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:171 includes/Admin/AuditPage.php:459
|
#: includes/Admin/AuditPage.php:173 includes/Admin/AuditPage.php:461
|
||||||
#: includes/Admin/AuditPage.php:510 includes/Admin/AuditPage.php:542
|
#: includes/Admin/AuditPage.php:515 includes/Admin/AuditPage.php:648
|
||||||
|
#: includes/Admin/AuditPage.php:680 includes/Admin/ToolsPage.php:105
|
||||||
|
#: includes/Admin/ToolsPage.php:161
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr "Permisos insuficientes."
|
msgstr "Permisos insuficientes."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:176
|
#: includes/Admin/AuditPage.php:178
|
||||||
msgid "Invalid attachment ID."
|
msgid "Invalid attachment ID."
|
||||||
msgstr "ID de adjunto no válido."
|
msgstr "ID de adjunto no válido."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:184
|
#: includes/Admin/AuditPage.php:186
|
||||||
msgid "Featured Image"
|
msgid "Featured Image"
|
||||||
msgstr "Imagen destacada"
|
msgstr "Imagen destacada"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:185
|
#: includes/Admin/AuditPage.php:187
|
||||||
msgid "Post Content"
|
msgid "Post Content"
|
||||||
msgstr "Contenido de la entrada"
|
msgstr "Contenido de la entrada"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:186
|
#: includes/Admin/AuditPage.php:188
|
||||||
msgid "Custom Field"
|
msgid "Custom Field"
|
||||||
msgstr "Campo personalizado"
|
msgstr "Campo personalizado"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:194
|
#: includes/Admin/AuditPage.php:196
|
||||||
msgid "Post"
|
msgid "Post"
|
||||||
msgstr "Entrada"
|
msgstr "Entrada"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:195
|
#: includes/Admin/AuditPage.php:197
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr "Tipo"
|
msgstr "Tipo"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:196
|
#: includes/Admin/AuditPage.php:198
|
||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr "Contexto"
|
msgstr "Contexto"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:197
|
#: includes/Admin/AuditPage.php:199
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr "Estado"
|
msgstr "Estado"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:240
|
#: includes/Admin/AuditPage.php:242
|
||||||
msgid "Internal Usage"
|
msgid "Internal Usage"
|
||||||
msgstr "Uso interno"
|
msgstr "Uso interno"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:288
|
#: includes/Admin/AuditPage.php:290
|
||||||
msgid "External Scan Results"
|
msgid "External Scan Results"
|
||||||
msgstr "Resultados del escaneo externo"
|
msgstr "Resultados del escaneo externo"
|
||||||
|
|
||||||
#. translators: %d: number of external matches
|
#. translators: %d: number of external matches
|
||||||
#: includes/Admin/AuditPage.php:312
|
#: includes/Admin/AuditPage.php:314
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d match"
|
msgid "%d match"
|
||||||
msgid_plural "%d matches"
|
msgid_plural "%d matches"
|
||||||
msgstr[0] "%d coincidencia"
|
msgstr[0] "%d coincidencia"
|
||||||
msgstr[1] "%d coincidencias"
|
msgstr[1] "%d coincidencias"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:317
|
#: includes/Admin/AuditPage.php:319
|
||||||
msgid "No matches"
|
msgid "No matches"
|
||||||
msgstr "Sin coincidencias"
|
msgstr "Sin coincidencias"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:328
|
#: includes/Admin/AuditPage.php:330
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr "Dominio"
|
msgstr "Dominio"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:329
|
#: includes/Admin/AuditPage.php:331
|
||||||
msgid "Occurrences"
|
msgid "Occurrences"
|
||||||
msgstr "Apariciones"
|
msgstr "Apariciones"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:350
|
#: includes/Admin/AuditPage.php:352
|
||||||
msgid "Consensus Domains"
|
msgid "Consensus Domains"
|
||||||
msgstr "Dominios de consenso"
|
msgstr "Dominios de consenso"
|
||||||
|
|
||||||
#. translators: %d: number of providers that agree
|
#. translators: %d: number of providers that agree
|
||||||
#: includes/Admin/AuditPage.php:356
|
#: includes/Admin/AuditPage.php:358
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d provider"
|
msgid "%d provider"
|
||||||
msgid_plural "%d providers"
|
msgid_plural "%d providers"
|
||||||
msgstr[0] "%d proveedor"
|
msgstr[0] "%d proveedor"
|
||||||
msgstr[1] "%d proveedores"
|
msgstr[1] "%d proveedores"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:388
|
#: includes/Admin/AuditPage.php:390
|
||||||
msgid "In Index"
|
msgid "In Index"
|
||||||
msgstr "En el índice"
|
msgstr "En el índice"
|
||||||
|
|
||||||
#. translators: %d: count of images not yet indexed
|
#. translators: %d: count of images not yet indexed
|
||||||
#: includes/Admin/AuditPage.php:392
|
#: includes/Admin/AuditPage.php:394
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d not yet indexed"
|
msgid "%d not yet indexed"
|
||||||
msgstr "%d aún no indexadas"
|
msgstr "%d aún no indexadas"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:395
|
#: includes/Admin/AuditPage.php:397
|
||||||
msgid "All indexed"
|
msgid "All indexed"
|
||||||
msgstr "Todas indexadas"
|
msgstr "Todas indexadas"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:400 includes/Admin/MediaListTable.php:275
|
#: includes/Admin/AuditPage.php:402 includes/Admin/MediaListTable.php:278
|
||||||
msgid "Scanned"
|
msgid "Scanned"
|
||||||
msgstr "Escaneadas"
|
msgstr "Escaneadas"
|
||||||
|
|
||||||
#. translators: %d: percentage
|
#. translators: %d: percentage
|
||||||
#: includes/Admin/AuditPage.php:403
|
#: includes/Admin/AuditPage.php:405
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d%% of index"
|
msgid "%d%% of index"
|
||||||
msgstr "%d%% del índice"
|
msgstr "%d%% del índice"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:410
|
#: includes/Admin/AuditPage.php:412
|
||||||
msgid "Used"
|
msgid "Used"
|
||||||
msgstr "Usadas"
|
msgstr "Usadas"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:416 includes/Admin/MediaListTable.php:200
|
#: includes/Admin/AuditPage.php:418 includes/Admin/MediaListTable.php:203
|
||||||
msgid "Unused"
|
msgid "Unused"
|
||||||
msgstr "Sin usar"
|
msgstr "Sin usar"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:423
|
#: includes/Admin/AuditPage.php:425
|
||||||
msgid "External Matches"
|
msgid "External Matches"
|
||||||
msgstr "Coincidencias externas"
|
msgstr "Coincidencias externas"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:473
|
#: includes/Admin/AuditPage.php:475 includes/Admin/AuditPage.php:529
|
||||||
msgid "Could not open output stream."
|
msgid "Could not open output stream."
|
||||||
msgstr "No se pudo abrir el flujo de salida."
|
msgstr "No se pudo abrir el flujo de salida."
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:482 includes/Privacy/DataExporter.php:257
|
#: includes/Admin/AuditPage.php:484 includes/Admin/AuditPage.php:537
|
||||||
#: includes/Privacy/DataExporter.php:299
|
#: includes/Privacy/DataExporter.php:257 includes/Privacy/DataExporter.php:299
|
||||||
msgid "Attachment ID"
|
msgid "Attachment ID"
|
||||||
msgstr "ID del adjunto"
|
msgstr "ID del adjunto"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:483 includes/Admin/MediaListTable.php:52
|
#: includes/Admin/AuditPage.php:485 includes/Admin/AuditPage.php:538
|
||||||
#: includes/Privacy/DataExporter.php:261
|
#: includes/Admin/MediaListTable.php:52 includes/Privacy/DataExporter.php:261
|
||||||
msgid "Filename"
|
msgid "Filename"
|
||||||
msgstr "Nombre de archivo"
|
msgstr "Nombre de archivo"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:484 includes/Privacy/DataExporter.php:265
|
#: includes/Admin/AuditPage.php:486 includes/Admin/AuditPage.php:539
|
||||||
|
#: includes/Privacy/DataExporter.php:265
|
||||||
msgid "File URL"
|
msgid "File URL"
|
||||||
msgstr "URL del archivo"
|
msgstr "URL del archivo"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:485
|
#: includes/Admin/AuditPage.php:487
|
||||||
msgid "MIME Type"
|
msgid "MIME Type"
|
||||||
msgstr "Tipo MIME"
|
msgstr "Tipo MIME"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:486
|
#: includes/Admin/AuditPage.php:488
|
||||||
msgid "File Size (bytes)"
|
msgid "File Size (bytes)"
|
||||||
msgstr "Tamaño del archivo (bytes)"
|
msgstr "Tamaño del archivo (bytes)"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:487 includes/Admin/MediaListTable.php:56
|
#: includes/Admin/AuditPage.php:489 includes/Admin/AuditPage.php:540
|
||||||
|
#: includes/Admin/MediaListTable.php:56
|
||||||
msgid "External Status"
|
msgid "External Status"
|
||||||
msgstr "Estado externo"
|
msgstr "Estado externo"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:488 includes/Admin/MediaListTable.php:54
|
#: includes/Admin/AuditPage.php:490 includes/Admin/MediaListTable.php:54
|
||||||
msgid "Usage Count"
|
msgid "Usage Count"
|
||||||
msgstr "Número de usos"
|
msgstr "Número de usos"
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:489
|
#: includes/Admin/AuditPage.php:491
|
||||||
msgid "Used In (post titles)"
|
msgid "Used In (post titles)"
|
||||||
msgstr "Usado en (títulos de entradas)"
|
msgstr "Usado en (títulos de entradas)"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:541 includes/Admin/MediaListTable.php:57
|
||||||
|
msgid "Last Scanned"
|
||||||
|
msgstr "Último escaneo"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:542 includes/Privacy/DataExporter.php:303
|
||||||
|
msgid "Provider"
|
||||||
|
msgstr "Proveedor"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:543 includes/Privacy/DataExporter.php:307
|
||||||
|
msgid "Match Count"
|
||||||
|
msgstr "Número de coincidencias"
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:544
|
||||||
|
msgid "Top Domains"
|
||||||
|
msgstr "Dominios principales"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:51
|
#: includes/Admin/MediaListTable.php:51
|
||||||
msgid "Thumbnail"
|
msgid "Thumbnail"
|
||||||
msgstr "Miniatura"
|
msgstr "Miniatura"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:53
|
#: includes/Admin/MediaListTable.php:53
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr ""
|
msgstr "ID"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:55
|
#: includes/Admin/MediaListTable.php:55
|
||||||
msgid "Usages"
|
msgid "Usages"
|
||||||
msgstr "Usos"
|
msgstr "Usos"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:79
|
#: includes/Admin/MediaListTable.php:81
|
||||||
msgid "Run External Scan"
|
msgid "Run External Scan"
|
||||||
msgstr "Ejecutar escaneo externo"
|
msgstr "Ejecutar escaneo externo"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:80
|
#: includes/Admin/MediaListTable.php:82
|
||||||
msgid "Purge External Data"
|
msgid "Purge External Data"
|
||||||
msgstr "Purgar datos externos"
|
msgstr "Purgar datos externos"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:81
|
#: includes/Admin/MediaListTable.php:83
|
||||||
msgid "Export CSV"
|
msgid "Export CSV"
|
||||||
msgstr "Exportar CSV"
|
msgstr "Exportar CSV"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:165
|
#: includes/Admin/MediaListTable.php:84
|
||||||
|
msgid "Export External Results CSV"
|
||||||
|
msgstr "Exportar CSV de resultados externos"
|
||||||
|
|
||||||
|
#: includes/Admin/MediaListTable.php:168
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr "Editar"
|
msgstr "Editar"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:170
|
#: includes/Admin/MediaListTable.php:173
|
||||||
msgid "View Details"
|
msgid "View Details"
|
||||||
msgstr "Ver detalles"
|
msgstr "Ver detalles"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:236
|
#: includes/Admin/MediaListTable.php:239
|
||||||
msgid "(no title)"
|
msgid "(no title)"
|
||||||
msgstr "(sin título)"
|
msgstr "(sin título)"
|
||||||
|
|
||||||
#. translators: %d: number of additional usages
|
#. translators: %d: number of additional usages
|
||||||
#: includes/Admin/MediaListTable.php:251
|
#: includes/Admin/MediaListTable.php:254
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "+ %d more…"
|
msgid "+ %d more…"
|
||||||
msgstr "+ %d más…"
|
msgstr "+ %d más…"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:273
|
#: includes/Admin/MediaListTable.php:276 includes/Admin/ToolsPage.php:580
|
||||||
|
#: includes/Admin/ToolsPage.php:581 includes/Admin/ToolsPage.php:582
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr "Pendiente"
|
msgstr "Pendiente"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:274
|
#: includes/Admin/MediaListTable.php:277
|
||||||
msgid "Queued"
|
msgid "Queued"
|
||||||
msgstr "En cola"
|
msgstr "En cola"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:276
|
#: includes/Admin/MediaListTable.php:279
|
||||||
msgid "Matches Found"
|
msgid "Matches Found"
|
||||||
msgstr "Coincidencias encontradas"
|
msgstr "Coincidencias encontradas"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:277
|
#: includes/Admin/MediaListTable.php:280
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr "Error"
|
msgstr "Error"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:305
|
#: includes/Admin/MediaListTable.php:308
|
||||||
msgid "View Results"
|
msgid "View Results"
|
||||||
msgstr "Ver resultados"
|
msgstr "Ver resultados"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:336
|
#. translators: %s: human-readable time difference, e.g. "3 days"
|
||||||
|
#: includes/Admin/MediaListTable.php:350
|
||||||
|
#, php-format
|
||||||
|
msgid "%s ago"
|
||||||
|
msgstr "hace %s"
|
||||||
|
|
||||||
|
#: includes/Admin/MediaListTable.php:380
|
||||||
msgid "All statuses"
|
msgid "All statuses"
|
||||||
msgstr "Todos los estados"
|
msgstr "Todos los estados"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:350
|
#: includes/Admin/MediaListTable.php:394
|
||||||
msgid "All post types"
|
msgid "All post types"
|
||||||
msgstr "Todos los tipos de entrada"
|
msgstr "Todos los tipos de entrada"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:365
|
#: includes/Admin/MediaListTable.php:409
|
||||||
msgid "Unused only"
|
msgid "Unused only"
|
||||||
msgstr "Solo sin usar"
|
msgstr "Solo sin usar"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:368
|
#: includes/Admin/MediaListTable.php:412
|
||||||
msgid "Filter"
|
msgid "Filter"
|
||||||
msgstr "Filtrar"
|
msgstr "Filtrar"
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:378
|
#: includes/Admin/MediaListTable.php:422
|
||||||
msgid ""
|
msgid ""
|
||||||
"No indexed attachments found. Run wp mra scan-internal to populate the index."
|
"No indexed attachments found. Run wp mra scan-internal to populate the index."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -435,6 +467,412 @@ msgstr ""
|
||||||
"Máximo de solicitudes de API por minuto por proveedor (1–60). "
|
"Máximo de solicitudes de API por minuto por proveedor (1–60). "
|
||||||
"Predeterminado: 10."
|
"Predeterminado: 10."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:85
|
||||||
|
msgid "Done."
|
||||||
|
msgstr "Listo."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:86
|
||||||
|
msgid "Stopped."
|
||||||
|
msgstr "Detenido."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:87
|
||||||
|
msgid "An error occurred."
|
||||||
|
msgstr "Se ha producido un error."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:139
|
||||||
|
msgid "Invalid batch type."
|
||||||
|
msgstr "Tipo de lote no válido."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:256
|
||||||
|
msgid "System Status"
|
||||||
|
msgstr "Estado del sistema"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:259
|
||||||
|
msgid "Operations"
|
||||||
|
msgstr "Operaciones"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:262
|
||||||
|
msgid "Direct scan runner"
|
||||||
|
msgstr "Ejecutor de escaneo directo"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:264
|
||||||
|
msgid ""
|
||||||
|
"Run scan batches directly from your browser without relying on background "
|
||||||
|
"jobs. Useful when WP-Cron is disabled or Action Scheduler is not running. "
|
||||||
|
"Keep this tab open while processing."
|
||||||
|
msgstr ""
|
||||||
|
"Ejecuta lotes de escaneo directamente desde tu navegador sin depender de "
|
||||||
|
"trabajos en segundo plano. Útil cuando WP-Cron está desactivado o Action "
|
||||||
|
"Scheduler no está en ejecución. Mantén esta pestaña abierta mientras se "
|
||||||
|
"procesa."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:300
|
||||||
|
msgid "not installed"
|
||||||
|
msgstr "no instalado"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:358
|
||||||
|
msgid "Internal scan scheduled."
|
||||||
|
msgstr "Escaneo interno programado."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:359
|
||||||
|
msgid "External scan scheduled."
|
||||||
|
msgstr "Escaneo externo programado."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:360
|
||||||
|
msgid "Failed scans re-queued. Background scan scheduled."
|
||||||
|
msgstr "Escaneos fallidos reencolados. Escaneo en segundo plano programado."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:361
|
||||||
|
msgid "Usage data cleared. Background scan scheduled."
|
||||||
|
msgstr "Datos de uso eliminados. Escaneo en segundo plano programado."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:362
|
||||||
|
msgid "Index cleared. Fresh indexing scheduled."
|
||||||
|
msgstr "Índice eliminado. Re-indexación programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:363
|
||||||
|
msgid "External scan data purged."
|
||||||
|
msgstr "Datos de escaneo externo eliminados."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:364
|
||||||
|
msgid "All data reset. Fresh indexing scheduled."
|
||||||
|
msgstr "Todos los datos restablecidos. Re-indexación programada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:367
|
||||||
|
msgid "Operation completed."
|
||||||
|
msgstr "Operación completada."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:411
|
||||||
|
msgid "Database schema"
|
||||||
|
msgstr "Esquema de base de datos"
|
||||||
|
|
||||||
|
#. translators: %s: version number
|
||||||
|
#: includes/Admin/ToolsPage.php:417
|
||||||
|
#, php-format
|
||||||
|
msgid "v%s – up to date"
|
||||||
|
msgstr "v%s – actualizado"
|
||||||
|
|
||||||
|
#. translators: 1: stored version, 2: expected version
|
||||||
|
#: includes/Admin/ToolsPage.php:423
|
||||||
|
#, php-format
|
||||||
|
msgid "Installed: %1$s — Required: %2$s"
|
||||||
|
msgstr "Instalado: %1$s — Requerido: %2$s"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:432
|
||||||
|
msgid "Deactivate and reactivate the plugin to apply pending migrations."
|
||||||
|
msgstr ""
|
||||||
|
"Desactiva y reactiva el plugin para aplicar las migraciones pendientes."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:439
|
||||||
|
msgid "Action Scheduler"
|
||||||
|
msgstr "Action Scheduler"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:442
|
||||||
|
msgid "Available"
|
||||||
|
msgstr "Disponible"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:444
|
||||||
|
msgid "Not available"
|
||||||
|
msgstr "No disponible"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:449
|
||||||
|
msgid ""
|
||||||
|
"Install and activate the Action Scheduler plugin. Background scanning will "
|
||||||
|
"not work without it."
|
||||||
|
msgstr ""
|
||||||
|
"Instala y activa el plugin Action Scheduler. El escaneo en segundo plano no "
|
||||||
|
"funcionará sin él."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:456
|
||||||
|
msgid "WP-Cron"
|
||||||
|
msgstr "WP-Cron"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:459
|
||||||
|
msgid "Disabled (DISABLE_WP_CRON)"
|
||||||
|
msgstr "Desactivado (DISABLE_WP_CRON)"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:461
|
||||||
|
msgid "Enabled"
|
||||||
|
msgstr "Activado"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:466
|
||||||
|
msgid ""
|
||||||
|
"Background jobs will not fire automatically. Trigger the cron externally or "
|
||||||
|
"use WP-CLI:"
|
||||||
|
msgstr ""
|
||||||
|
"Los trabajos en segundo plano no se ejecutarán automáticamente. Activa el "
|
||||||
|
"cron externamente o usa WP-CLI:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:474
|
||||||
|
msgid "Internal index"
|
||||||
|
msgstr "Índice interno"
|
||||||
|
|
||||||
|
#. translators: 1: indexed count, 2: total images
|
||||||
|
#: includes/Admin/ToolsPage.php:479
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s / %2$s images indexed"
|
||||||
|
msgstr "%1$s / %2$s imágenes indexadas"
|
||||||
|
|
||||||
|
#. translators: %s: formatted count
|
||||||
|
#: includes/Admin/ToolsPage.php:490
|
||||||
|
#, php-format
|
||||||
|
msgid "%s image not yet indexed."
|
||||||
|
msgid_plural "%s images not yet indexed."
|
||||||
|
msgstr[0] "%s imagen aún no indexada."
|
||||||
|
msgstr[1] "%s imágenes aún no indexadas."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:494
|
||||||
|
msgid "Schedule an internal scan below."
|
||||||
|
msgstr "Programa un escaneo interno más abajo."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:502
|
||||||
|
msgid "Usage scan"
|
||||||
|
msgstr "Escaneo de uso"
|
||||||
|
|
||||||
|
#. translators: 1: scanned count, 2: total indexed
|
||||||
|
#: includes/Admin/ToolsPage.php:507
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s / %2$s scanned for usage"
|
||||||
|
msgstr "%1$s / %2$s escaneadas de uso"
|
||||||
|
|
||||||
|
#. translators: %s: formatted count
|
||||||
|
#: includes/Admin/ToolsPage.php:518
|
||||||
|
#, php-format
|
||||||
|
msgid "%s pending."
|
||||||
|
msgid_plural "%s pending."
|
||||||
|
msgstr[0] "%s pendiente."
|
||||||
|
msgstr[1] "%s pendientes."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:539 includes/Admin/ToolsPage.php:736
|
||||||
|
msgid "External scan"
|
||||||
|
msgstr "Escaneo externo"
|
||||||
|
|
||||||
|
#. translators: 1: scanned 2: matches 3: queued 4: pending 5: errors
|
||||||
|
#: includes/Admin/ToolsPage.php:544
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s scanned · %2$s matches · %3$s queued · %4$s pending · %5$s errors"
|
||||||
|
msgstr ""
|
||||||
|
"%1$s escaneadas · %2$s coincidencias · %3$s en cola · %4$s pendientes · %5$s "
|
||||||
|
"errores"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:555
|
||||||
|
msgid ""
|
||||||
|
"Some scans failed. Check that API keys are configured correctly in Settings."
|
||||||
|
msgstr ""
|
||||||
|
"Algunos escaneos fallaron. Verifica que las claves de API están configuradas "
|
||||||
|
"correctamente en Ajustes."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:557
|
||||||
|
msgid "Schedule an external scan below to process pending items."
|
||||||
|
msgstr ""
|
||||||
|
"Programa un escaneo externo más abajo para procesar los elementos pendientes."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:575
|
||||||
|
msgid "Scheduled jobs"
|
||||||
|
msgstr "Trabajos programados"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:578
|
||||||
|
msgid "Action Scheduler not available."
|
||||||
|
msgstr "Action Scheduler no disponible."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:580
|
||||||
|
msgid "Index:"
|
||||||
|
msgstr "Índice:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:581
|
||||||
|
msgid "Usage:"
|
||||||
|
msgstr "Uso:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:582
|
||||||
|
msgid "External:"
|
||||||
|
msgstr "Externo:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:587
|
||||||
|
msgid ""
|
||||||
|
"There is work to do but no background job is scheduled. Use the operations "
|
||||||
|
"below."
|
||||||
|
msgstr ""
|
||||||
|
"Hay trabajo pendiente pero no hay ningún trabajo en segundo plano "
|
||||||
|
"programado. Usa las operaciones de abajo."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:589
|
||||||
|
msgid "WP-Cron is disabled. Jobs will not fire automatically."
|
||||||
|
msgstr ""
|
||||||
|
"WP-Cron está desactivado. Los trabajos no se ejecutarán automáticamente."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:599
|
||||||
|
msgid "WP-CLI commands to process scans manually:"
|
||||||
|
msgstr "Comandos WP-CLI para procesar escaneos manualmente:"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:616
|
||||||
|
msgid "Schedule internal scan"
|
||||||
|
msgstr "Programar escaneo interno"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:617
|
||||||
|
msgid ""
|
||||||
|
"Queue a background job to index all unindexed media files and scan their "
|
||||||
|
"usage across posts, pages, and custom fields. Safe to run at any time — will "
|
||||||
|
"not re-process completed work."
|
||||||
|
msgstr ""
|
||||||
|
"Cola un trabajo en segundo plano para indexar todos los archivos multimedia "
|
||||||
|
"no indexados y escanear su uso en entradas, páginas y campos personalizados. "
|
||||||
|
"Es seguro ejecutarlo en cualquier momento: no reprocesará el trabajo ya "
|
||||||
|
"completado."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:623
|
||||||
|
msgid "Schedule external scan"
|
||||||
|
msgstr "Programar escaneo externo"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:624
|
||||||
|
msgid ""
|
||||||
|
"Mark all pending attachments as queued and launch a background reverse-image-"
|
||||||
|
"search via the configured providers. Requires API keys in Settings."
|
||||||
|
msgstr ""
|
||||||
|
"Marca todos los adjuntos pendientes como en cola y lanza una búsqueda "
|
||||||
|
"inversa de imágenes en segundo plano a través de los proveedores "
|
||||||
|
"configurados. Requiere claves de API en Ajustes."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:630
|
||||||
|
msgid "Requeue scan errors"
|
||||||
|
msgstr "Reencolar errores de escaneo"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:631
|
||||||
|
msgid ""
|
||||||
|
"Re-queues only the attachments that failed with an error on the last "
|
||||||
|
"external scan run. Does not affect already-scanned items. Useful to retry "
|
||||||
|
"after fixing API key issues."
|
||||||
|
msgstr ""
|
||||||
|
"Reencola solo los adjuntos que fallaron con un error en la última ejecución "
|
||||||
|
"del escaneo externo. No afecta a los elementos ya escaneados. Útil para "
|
||||||
|
"reintentar después de corregir problemas con las claves de API."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:640
|
||||||
|
msgid "Reset usage data"
|
||||||
|
msgstr "Restablecer datos de uso"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:641
|
||||||
|
msgid ""
|
||||||
|
"Clears all usage rows and resets the usage-scan flag for every indexed "
|
||||||
|
"attachment. File metadata in the index is preserved. A background usage scan "
|
||||||
|
"is scheduled immediately after."
|
||||||
|
msgstr ""
|
||||||
|
"Elimina todas las filas de uso y restablece el indicador de escaneo de uso "
|
||||||
|
"para cada adjunto indexado. Los metadatos del archivo en el índice se "
|
||||||
|
"conservan. Se programa un escaneo en segundo plano inmediatamente después."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:643
|
||||||
|
msgid "This will delete all usage data. Continue?"
|
||||||
|
msgstr "Esto eliminará todos los datos de uso. ¿Continuar?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:647
|
||||||
|
msgid "Re-index media library"
|
||||||
|
msgstr "Re-indexar la biblioteca de medios"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:648
|
||||||
|
msgid ""
|
||||||
|
"Deletes all index and usage entries, then schedules a full fresh re-index. "
|
||||||
|
"External scan results are not affected. Useful if many media files have been "
|
||||||
|
"added or removed."
|
||||||
|
msgstr ""
|
||||||
|
"Elimina todas las entradas del índice y de uso, luego programa una re-"
|
||||||
|
"indexación completa. Los resultados del escaneo externo no se ven afectados. "
|
||||||
|
"Útil si se han añadido o eliminado muchos archivos multimedia."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:650
|
||||||
|
msgid "This will delete all index and usage data. Continue?"
|
||||||
|
msgstr "Esto eliminará todos los datos del índice y de uso. ¿Continuar?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:654
|
||||||
|
msgid "Purge external data"
|
||||||
|
msgstr "Purgar datos externos"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:655
|
||||||
|
msgid ""
|
||||||
|
"Deletes all external scan results and resets every attachment's external "
|
||||||
|
"status to pending. Use this before switching API providers or to force a "
|
||||||
|
"complete re-scan."
|
||||||
|
msgstr ""
|
||||||
|
"Elimina todos los resultados del escaneo externo y restablece el estado "
|
||||||
|
"externo de cada adjunto a pendiente. Úsalo antes de cambiar de proveedores "
|
||||||
|
"de API o para forzar un escaneo completo."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:657
|
||||||
|
msgid "This will delete all external scan results. Continue?"
|
||||||
|
msgstr "Esto eliminará todos los resultados del escaneo externo. ¿Continuar?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:661
|
||||||
|
msgid "Reset all data"
|
||||||
|
msgstr "Restablecer todos los datos"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:662
|
||||||
|
msgid ""
|
||||||
|
"Truncates all three plugin tables (index, usage, external results) and "
|
||||||
|
"schedules a fresh indexing run. Use this to start completely from scratch."
|
||||||
|
msgstr ""
|
||||||
|
"Vacía las tres tablas del plugin (índice, uso, resultados externos) y "
|
||||||
|
"programa una nueva indexación. Úsalo para empezar completamente desde cero."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:664
|
||||||
|
msgid ""
|
||||||
|
"This will permanently delete ALL plugin data and cannot be undone. Are you "
|
||||||
|
"absolutely sure?"
|
||||||
|
msgstr ""
|
||||||
|
"Esto eliminará TODOS los datos del plugin de forma permanente y no se puede "
|
||||||
|
"deshacer. ¿Estás absolutamente seguro?"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:675
|
||||||
|
msgid "Destructive operations"
|
||||||
|
msgstr "Operaciones destructivas"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:678
|
||||||
|
msgid ""
|
||||||
|
"These operations permanently delete plugin data. Intended for forced "
|
||||||
|
"rescans, troubleshooting, or starting fresh. A confirmation prompt will "
|
||||||
|
"appear before any action is taken."
|
||||||
|
msgstr ""
|
||||||
|
"Estas operaciones eliminan datos del plugin de forma permanente. Pensadas "
|
||||||
|
"para forzar re-escaneos, solucionar problemas o empezar desde cero. "
|
||||||
|
"Aparecerá una confirmación antes de ejecutar cualquier acción."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:726
|
||||||
|
msgid "Index media files"
|
||||||
|
msgstr "Indexar archivos multimedia"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:727
|
||||||
|
msgid ""
|
||||||
|
"Discovers unindexed images and registers them in the plugin index. Run this "
|
||||||
|
"first."
|
||||||
|
msgstr ""
|
||||||
|
"Descubre imágenes no indexadas y las registra en el índice del plugin. "
|
||||||
|
"Ejecútalo primero."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:731
|
||||||
|
msgid "Scan usage"
|
||||||
|
msgstr "Escanear uso"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:732
|
||||||
|
msgid ""
|
||||||
|
"Checks every indexed image for usage across posts, pages, and custom fields."
|
||||||
|
msgstr ""
|
||||||
|
"Comprueba el uso de cada imagen indexada en entradas, páginas y campos "
|
||||||
|
"personalizados."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:737
|
||||||
|
msgid ""
|
||||||
|
"Sends images to external providers for reverse-image search. Requires API "
|
||||||
|
"keys in Settings."
|
||||||
|
msgstr ""
|
||||||
|
"Envía imágenes a proveedores externos para búsqueda inversa de imágenes. "
|
||||||
|
"Requiere claves de API en Ajustes."
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:754
|
||||||
|
msgid "Run now"
|
||||||
|
msgstr "Ejecutar ahora"
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:757
|
||||||
|
msgid "Stop"
|
||||||
|
msgstr "Detener"
|
||||||
|
|
||||||
#. translators: %s: DB version number
|
#. translators: %s: DB version number
|
||||||
#: includes/CLI/Command.php:49
|
#: includes/CLI/Command.php:49
|
||||||
#, php-format
|
#, php-format
|
||||||
|
|
@ -495,7 +933,11 @@ msgstr "Ejecutando escaneos externos…"
|
||||||
msgid "External scan complete. %d attachments processed."
|
msgid "External scan complete. %d attachments processed."
|
||||||
msgstr "Escaneo externo completo. %d adjuntos procesados."
|
msgstr "Escaneo externo completo. %d adjuntos procesados."
|
||||||
|
|
||||||
#: includes/Core/Plugin.php:112 includes/Core/Plugin.php:113
|
#: includes/Core/Plugin.php:122 includes/Core/Plugin.php:123
|
||||||
|
msgid "Tools"
|
||||||
|
msgstr "Herramientas"
|
||||||
|
|
||||||
|
#: includes/Core/Plugin.php:135 includes/Core/Plugin.php:136
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr "Ajustes"
|
msgstr "Ajustes"
|
||||||
|
|
||||||
|
|
@ -523,14 +965,15 @@ msgstr "Último escaneo (interno)"
|
||||||
msgid "Last Scanned (external)"
|
msgid "Last Scanned (external)"
|
||||||
msgstr "Último escaneo (externo)"
|
msgstr "Último escaneo (externo)"
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:303
|
|
||||||
msgid "Provider"
|
|
||||||
msgstr "Proveedor"
|
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:307
|
|
||||||
msgid "Match Count"
|
|
||||||
msgstr "Número de coincidencias"
|
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:311
|
#: includes/Privacy/DataExporter.php:311
|
||||||
msgid "Scanned At"
|
msgid "Scanned At"
|
||||||
msgstr "Escaneado el"
|
msgstr "Escaneado el"
|
||||||
|
|
||||||
|
#~ msgid "https://robotstxt.es/plugins/media-audit/"
|
||||||
|
#~ msgstr "https://robotstxt.es/plugins/media-audit/"
|
||||||
|
|
||||||
|
#~ msgid "Javier Casares"
|
||||||
|
#~ msgstr "Javier Casares"
|
||||||
|
|
||||||
|
#~ msgid "https://javiercasares.com"
|
||||||
|
#~ msgstr "https://javiercasares.com"
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,15 @@
|
||||||
# Copyright (C) 2026 Javier Casares
|
# Copyright (C) 2026 ROBOTSTXT
|
||||||
# This file is distributed under the GPL-3.0-or-later.
|
# This file is distributed under the GPL-3.0-or-later.
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.0.0\n"
|
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.1.0\n"
|
||||||
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-mediaaudit\n"
|
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-mediaaudit\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"POT-Creation-Date: 2026-05-02T06:06:40+00:00\n"
|
"POT-Creation-Date: 2026-05-02T07:36:54+00:00\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"X-Generator: WP-CLI 2.12.0\n"
|
"X-Generator: WP-CLI 2.12.0\n"
|
||||||
"X-Domain: robotstxt-mediaaudit\n"
|
"X-Domain: robotstxt-mediaaudit\n"
|
||||||
|
|
@ -21,7 +21,7 @@ msgstr ""
|
||||||
|
|
||||||
#. Plugin URI of the plugin
|
#. Plugin URI of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "https://robotstxt.es/plugins/media-audit/"
|
msgid "https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. Description of the plugin
|
#. Description of the plugin
|
||||||
|
|
@ -31,215 +31,243 @@ msgstr ""
|
||||||
|
|
||||||
#. Author of the plugin
|
#. Author of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "Javier Casares"
|
msgid "ROBOTSTXT"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. Author URI of the plugin
|
#. Author URI of the plugin
|
||||||
#: robotstxt-mediaaudit.php
|
#: robotstxt-mediaaudit.php
|
||||||
msgid "https://javiercasares.com"
|
msgid "https://www.robotstxt.es/"
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:112
|
|
||||||
msgid "Loading…"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:113
|
|
||||||
msgid "Error loading details."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:114
|
#: includes/Admin/AuditPage.php:114
|
||||||
#: includes/Admin/AuditPage.php:190
|
msgid "Loading…"
|
||||||
msgid "This image is not used in any post."
|
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:115
|
#: includes/Admin/AuditPage.php:115
|
||||||
#: includes/Admin/AuditPage.php:152
|
msgid "Error loading details."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:116
|
||||||
|
#: includes/Admin/AuditPage.php:192
|
||||||
|
msgid "This image is not used in any post."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:117
|
||||||
|
#: includes/Admin/AuditPage.php:154
|
||||||
msgid "Usage Details"
|
msgid "Usage Details"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:131
|
#: includes/Admin/AuditPage.php:133
|
||||||
#: includes/Admin/Settings.php:325
|
#: includes/Admin/Settings.php:325
|
||||||
|
#: includes/Admin/ToolsPage.php:245
|
||||||
msgid "You do not have permission to access this page."
|
msgid "You do not have permission to access this page."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:138
|
#: includes/Admin/AuditPage.php:140
|
||||||
#: includes/Core/Plugin.php:89
|
#: includes/Core/Plugin.php:99
|
||||||
#: includes/Core/Plugin.php:90
|
#: includes/Core/Plugin.php:100
|
||||||
#: includes/Core/Plugin.php:103
|
#: includes/Core/Plugin.php:113
|
||||||
#: includes/Core/Plugin.php:104
|
#: includes/Core/Plugin.php:114
|
||||||
#: includes/Privacy/DataEraser.php:33
|
#: includes/Privacy/DataEraser.php:33
|
||||||
#: includes/Privacy/DataExporter.php:45
|
#: includes/Privacy/DataExporter.php:45
|
||||||
msgid "Media Audit"
|
msgid "Media Audit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:144
|
#: includes/Admin/AuditPage.php:146
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:153
|
#: includes/Admin/AuditPage.php:155
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:171
|
#: includes/Admin/AuditPage.php:173
|
||||||
#: includes/Admin/AuditPage.php:459
|
#: includes/Admin/AuditPage.php:461
|
||||||
#: includes/Admin/AuditPage.php:510
|
#: includes/Admin/AuditPage.php:515
|
||||||
#: includes/Admin/AuditPage.php:542
|
#: includes/Admin/AuditPage.php:648
|
||||||
|
#: includes/Admin/AuditPage.php:680
|
||||||
|
#: includes/Admin/ToolsPage.php:105
|
||||||
|
#: includes/Admin/ToolsPage.php:161
|
||||||
msgid "Insufficient permissions."
|
msgid "Insufficient permissions."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:176
|
#: includes/Admin/AuditPage.php:178
|
||||||
msgid "Invalid attachment ID."
|
msgid "Invalid attachment ID."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:184
|
#: includes/Admin/AuditPage.php:186
|
||||||
msgid "Featured Image"
|
msgid "Featured Image"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:185
|
#: includes/Admin/AuditPage.php:187
|
||||||
msgid "Post Content"
|
msgid "Post Content"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:186
|
#: includes/Admin/AuditPage.php:188
|
||||||
msgid "Custom Field"
|
msgid "Custom Field"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:194
|
#: includes/Admin/AuditPage.php:196
|
||||||
msgid "Post"
|
msgid "Post"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:195
|
#: includes/Admin/AuditPage.php:197
|
||||||
msgid "Type"
|
msgid "Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:196
|
#: includes/Admin/AuditPage.php:198
|
||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:197
|
#: includes/Admin/AuditPage.php:199
|
||||||
msgid "Status"
|
msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:240
|
#: includes/Admin/AuditPage.php:242
|
||||||
msgid "Internal Usage"
|
msgid "Internal Usage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:288
|
#: includes/Admin/AuditPage.php:290
|
||||||
msgid "External Scan Results"
|
msgid "External Scan Results"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %d: number of external matches
|
#. translators: %d: number of external matches
|
||||||
#: includes/Admin/AuditPage.php:312
|
#: includes/Admin/AuditPage.php:314
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d match"
|
msgid "%d match"
|
||||||
msgid_plural "%d matches"
|
msgid_plural "%d matches"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:317
|
#: includes/Admin/AuditPage.php:319
|
||||||
msgid "No matches"
|
msgid "No matches"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:328
|
#: includes/Admin/AuditPage.php:330
|
||||||
msgid "Domain"
|
msgid "Domain"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:329
|
#: includes/Admin/AuditPage.php:331
|
||||||
msgid "Occurrences"
|
msgid "Occurrences"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:350
|
#: includes/Admin/AuditPage.php:352
|
||||||
msgid "Consensus Domains"
|
msgid "Consensus Domains"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %d: number of providers that agree
|
#. translators: %d: number of providers that agree
|
||||||
#: includes/Admin/AuditPage.php:356
|
#: includes/Admin/AuditPage.php:358
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d provider"
|
msgid "%d provider"
|
||||||
msgid_plural "%d providers"
|
msgid_plural "%d providers"
|
||||||
msgstr[0] ""
|
msgstr[0] ""
|
||||||
msgstr[1] ""
|
msgstr[1] ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:388
|
#: includes/Admin/AuditPage.php:390
|
||||||
msgid "In Index"
|
msgid "In Index"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %d: count of images not yet indexed
|
#. translators: %d: count of images not yet indexed
|
||||||
#: includes/Admin/AuditPage.php:392
|
#: includes/Admin/AuditPage.php:394
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d not yet indexed"
|
msgid "%d not yet indexed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:395
|
#: includes/Admin/AuditPage.php:397
|
||||||
msgid "All indexed"
|
msgid "All indexed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:400
|
#: includes/Admin/AuditPage.php:402
|
||||||
#: includes/Admin/MediaListTable.php:275
|
#: includes/Admin/MediaListTable.php:278
|
||||||
msgid "Scanned"
|
msgid "Scanned"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %d: percentage
|
#. translators: %d: percentage
|
||||||
#: includes/Admin/AuditPage.php:403
|
#: includes/Admin/AuditPage.php:405
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "%d%% of index"
|
msgid "%d%% of index"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:410
|
#: includes/Admin/AuditPage.php:412
|
||||||
msgid "Used"
|
msgid "Used"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:416
|
#: includes/Admin/AuditPage.php:418
|
||||||
#: includes/Admin/MediaListTable.php:200
|
#: includes/Admin/MediaListTable.php:203
|
||||||
msgid "Unused"
|
msgid "Unused"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:423
|
#: includes/Admin/AuditPage.php:425
|
||||||
msgid "External Matches"
|
msgid "External Matches"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:473
|
#: includes/Admin/AuditPage.php:475
|
||||||
|
#: includes/Admin/AuditPage.php:529
|
||||||
msgid "Could not open output stream."
|
msgid "Could not open output stream."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:482
|
#: includes/Admin/AuditPage.php:484
|
||||||
|
#: includes/Admin/AuditPage.php:537
|
||||||
#: includes/Privacy/DataExporter.php:257
|
#: includes/Privacy/DataExporter.php:257
|
||||||
#: includes/Privacy/DataExporter.php:299
|
#: includes/Privacy/DataExporter.php:299
|
||||||
msgid "Attachment ID"
|
msgid "Attachment ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:483
|
#: includes/Admin/AuditPage.php:485
|
||||||
|
#: includes/Admin/AuditPage.php:538
|
||||||
#: includes/Admin/MediaListTable.php:52
|
#: includes/Admin/MediaListTable.php:52
|
||||||
#: includes/Privacy/DataExporter.php:261
|
#: includes/Privacy/DataExporter.php:261
|
||||||
msgid "Filename"
|
msgid "Filename"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:484
|
#: includes/Admin/AuditPage.php:486
|
||||||
|
#: includes/Admin/AuditPage.php:539
|
||||||
#: includes/Privacy/DataExporter.php:265
|
#: includes/Privacy/DataExporter.php:265
|
||||||
msgid "File URL"
|
msgid "File URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:485
|
#: includes/Admin/AuditPage.php:487
|
||||||
msgid "MIME Type"
|
msgid "MIME Type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:486
|
#: includes/Admin/AuditPage.php:488
|
||||||
msgid "File Size (bytes)"
|
msgid "File Size (bytes)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:487
|
#: includes/Admin/AuditPage.php:489
|
||||||
|
#: includes/Admin/AuditPage.php:540
|
||||||
#: includes/Admin/MediaListTable.php:56
|
#: includes/Admin/MediaListTable.php:56
|
||||||
msgid "External Status"
|
msgid "External Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:488
|
#: includes/Admin/AuditPage.php:490
|
||||||
#: includes/Admin/MediaListTable.php:54
|
#: includes/Admin/MediaListTable.php:54
|
||||||
msgid "Usage Count"
|
msgid "Usage Count"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/AuditPage.php:489
|
#: includes/Admin/AuditPage.php:491
|
||||||
msgid "Used In (post titles)"
|
msgid "Used In (post titles)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:541
|
||||||
|
#: includes/Admin/MediaListTable.php:57
|
||||||
|
msgid "Last Scanned"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:542
|
||||||
|
#: includes/Privacy/DataExporter.php:303
|
||||||
|
msgid "Provider"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:543
|
||||||
|
#: includes/Privacy/DataExporter.php:307
|
||||||
|
msgid "Match Count"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/AuditPage.php:544
|
||||||
|
msgid "Top Domains"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:51
|
#: includes/Admin/MediaListTable.php:51
|
||||||
msgid "Thumbnail"
|
msgid "Thumbnail"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
@ -252,73 +280,86 @@ msgstr ""
|
||||||
msgid "Usages"
|
msgid "Usages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:79
|
#: includes/Admin/MediaListTable.php:81
|
||||||
msgid "Run External Scan"
|
msgid "Run External Scan"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:80
|
#: includes/Admin/MediaListTable.php:82
|
||||||
msgid "Purge External Data"
|
msgid "Purge External Data"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:81
|
#: includes/Admin/MediaListTable.php:83
|
||||||
msgid "Export CSV"
|
msgid "Export CSV"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:165
|
#: includes/Admin/MediaListTable.php:84
|
||||||
|
msgid "Export External Results CSV"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/MediaListTable.php:168
|
||||||
msgid "Edit"
|
msgid "Edit"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:170
|
#: includes/Admin/MediaListTable.php:173
|
||||||
msgid "View Details"
|
msgid "View Details"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:236
|
#: includes/Admin/MediaListTable.php:239
|
||||||
msgid "(no title)"
|
msgid "(no title)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %d: number of additional usages
|
#. translators: %d: number of additional usages
|
||||||
#: includes/Admin/MediaListTable.php:251
|
#: includes/Admin/MediaListTable.php:254
|
||||||
#, php-format
|
#, php-format
|
||||||
msgid "+ %d more…"
|
msgid "+ %d more…"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:273
|
#: includes/Admin/MediaListTable.php:276
|
||||||
|
#: includes/Admin/ToolsPage.php:580
|
||||||
|
#: includes/Admin/ToolsPage.php:581
|
||||||
|
#: includes/Admin/ToolsPage.php:582
|
||||||
msgid "Pending"
|
msgid "Pending"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:274
|
#: includes/Admin/MediaListTable.php:277
|
||||||
msgid "Queued"
|
msgid "Queued"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:276
|
#: includes/Admin/MediaListTable.php:279
|
||||||
msgid "Matches Found"
|
msgid "Matches Found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:277
|
#: includes/Admin/MediaListTable.php:280
|
||||||
msgid "Error"
|
msgid "Error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:305
|
#: includes/Admin/MediaListTable.php:308
|
||||||
msgid "View Results"
|
msgid "View Results"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:336
|
#. translators: %s: human-readable time difference, e.g. "3 days"
|
||||||
|
#: includes/Admin/MediaListTable.php:350
|
||||||
|
#, php-format
|
||||||
|
msgid "%s ago"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/MediaListTable.php:380
|
||||||
msgid "All statuses"
|
msgid "All statuses"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:350
|
#: includes/Admin/MediaListTable.php:394
|
||||||
msgid "All post types"
|
msgid "All post types"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:365
|
#: includes/Admin/MediaListTable.php:409
|
||||||
msgid "Unused only"
|
msgid "Unused only"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:368
|
#: includes/Admin/MediaListTable.php:412
|
||||||
msgid "Filter"
|
msgid "Filter"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Admin/MediaListTable.php:378
|
#: includes/Admin/MediaListTable.php:422
|
||||||
msgid "No indexed attachments found. Run wp mra scan-internal to populate the index."
|
msgid "No indexed attachments found. Run wp mra scan-internal to populate the index."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -423,6 +464,325 @@ msgstr ""
|
||||||
msgid "Maximum API requests per minute per provider (1–60). Default: 10."
|
msgid "Maximum API requests per minute per provider (1–60). Default: 10."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:85
|
||||||
|
msgid "Done."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:86
|
||||||
|
msgid "Stopped."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:87
|
||||||
|
msgid "An error occurred."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:139
|
||||||
|
msgid "Invalid batch type."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:256
|
||||||
|
msgid "System Status"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:259
|
||||||
|
msgid "Operations"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:262
|
||||||
|
msgid "Direct scan runner"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:264
|
||||||
|
msgid "Run scan batches directly from your browser without relying on background jobs. Useful when WP-Cron is disabled or Action Scheduler is not running. Keep this tab open while processing."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:300
|
||||||
|
msgid "not installed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:358
|
||||||
|
msgid "Internal scan scheduled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:359
|
||||||
|
msgid "External scan scheduled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:360
|
||||||
|
msgid "Failed scans re-queued. Background scan scheduled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:361
|
||||||
|
msgid "Usage data cleared. Background scan scheduled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:362
|
||||||
|
msgid "Index cleared. Fresh indexing scheduled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:363
|
||||||
|
msgid "External scan data purged."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:364
|
||||||
|
msgid "All data reset. Fresh indexing scheduled."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:367
|
||||||
|
msgid "Operation completed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:411
|
||||||
|
msgid "Database schema"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: version number
|
||||||
|
#: includes/Admin/ToolsPage.php:417
|
||||||
|
#, php-format
|
||||||
|
msgid "v%s – up to date"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: stored version, 2: expected version
|
||||||
|
#: includes/Admin/ToolsPage.php:423
|
||||||
|
#, php-format
|
||||||
|
msgid "Installed: %1$s — Required: %2$s"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:432
|
||||||
|
msgid "Deactivate and reactivate the plugin to apply pending migrations."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:439
|
||||||
|
msgid "Action Scheduler"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:442
|
||||||
|
msgid "Available"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:444
|
||||||
|
msgid "Not available"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:449
|
||||||
|
msgid "Install and activate the Action Scheduler plugin. Background scanning will not work without it."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:456
|
||||||
|
msgid "WP-Cron"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:459
|
||||||
|
msgid "Disabled (DISABLE_WP_CRON)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:461
|
||||||
|
msgid "Enabled"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:466
|
||||||
|
msgid "Background jobs will not fire automatically. Trigger the cron externally or use WP-CLI:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:474
|
||||||
|
msgid "Internal index"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: indexed count, 2: total images
|
||||||
|
#: includes/Admin/ToolsPage.php:479
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s / %2$s images indexed"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: formatted count
|
||||||
|
#: includes/Admin/ToolsPage.php:490
|
||||||
|
#, php-format
|
||||||
|
msgid "%s image not yet indexed."
|
||||||
|
msgid_plural "%s images not yet indexed."
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:494
|
||||||
|
msgid "Schedule an internal scan below."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:502
|
||||||
|
msgid "Usage scan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: scanned count, 2: total indexed
|
||||||
|
#: includes/Admin/ToolsPage.php:507
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s / %2$s scanned for usage"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: %s: formatted count
|
||||||
|
#: includes/Admin/ToolsPage.php:518
|
||||||
|
#, php-format
|
||||||
|
msgid "%s pending."
|
||||||
|
msgid_plural "%s pending."
|
||||||
|
msgstr[0] ""
|
||||||
|
msgstr[1] ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:539
|
||||||
|
#: includes/Admin/ToolsPage.php:736
|
||||||
|
msgid "External scan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#. translators: 1: scanned 2: matches 3: queued 4: pending 5: errors
|
||||||
|
#: includes/Admin/ToolsPage.php:544
|
||||||
|
#, php-format
|
||||||
|
msgid "%1$s scanned · %2$s matches · %3$s queued · %4$s pending · %5$s errors"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:555
|
||||||
|
msgid "Some scans failed. Check that API keys are configured correctly in Settings."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:557
|
||||||
|
msgid "Schedule an external scan below to process pending items."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:575
|
||||||
|
msgid "Scheduled jobs"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:578
|
||||||
|
msgid "Action Scheduler not available."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:580
|
||||||
|
msgid "Index:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:581
|
||||||
|
msgid "Usage:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:582
|
||||||
|
msgid "External:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:587
|
||||||
|
msgid "There is work to do but no background job is scheduled. Use the operations below."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:589
|
||||||
|
msgid "WP-Cron is disabled. Jobs will not fire automatically."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:599
|
||||||
|
msgid "WP-CLI commands to process scans manually:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:616
|
||||||
|
msgid "Schedule internal scan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:617
|
||||||
|
msgid "Queue a background job to index all unindexed media files and scan their usage across posts, pages, and custom fields. Safe to run at any time — will not re-process completed work."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:623
|
||||||
|
msgid "Schedule external scan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:624
|
||||||
|
msgid "Mark all pending attachments as queued and launch a background reverse-image-search via the configured providers. Requires API keys in Settings."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:630
|
||||||
|
msgid "Requeue scan errors"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:631
|
||||||
|
msgid "Re-queues only the attachments that failed with an error on the last external scan run. Does not affect already-scanned items. Useful to retry after fixing API key issues."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:640
|
||||||
|
msgid "Reset usage data"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:641
|
||||||
|
msgid "Clears all usage rows and resets the usage-scan flag for every indexed attachment. File metadata in the index is preserved. A background usage scan is scheduled immediately after."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:643
|
||||||
|
msgid "This will delete all usage data. Continue?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:647
|
||||||
|
msgid "Re-index media library"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:648
|
||||||
|
msgid "Deletes all index and usage entries, then schedules a full fresh re-index. External scan results are not affected. Useful if many media files have been added or removed."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:650
|
||||||
|
msgid "This will delete all index and usage data. Continue?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:654
|
||||||
|
msgid "Purge external data"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:655
|
||||||
|
msgid "Deletes all external scan results and resets every attachment's external status to pending. Use this before switching API providers or to force a complete re-scan."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:657
|
||||||
|
msgid "This will delete all external scan results. Continue?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:661
|
||||||
|
msgid "Reset all data"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:662
|
||||||
|
msgid "Truncates all three plugin tables (index, usage, external results) and schedules a fresh indexing run. Use this to start completely from scratch."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:664
|
||||||
|
msgid "This will permanently delete ALL plugin data and cannot be undone. Are you absolutely sure?"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:675
|
||||||
|
msgid "Destructive operations"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:678
|
||||||
|
msgid "These operations permanently delete plugin data. Intended for forced rescans, troubleshooting, or starting fresh. A confirmation prompt will appear before any action is taken."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:726
|
||||||
|
msgid "Index media files"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:727
|
||||||
|
msgid "Discovers unindexed images and registers them in the plugin index. Run this first."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:731
|
||||||
|
msgid "Scan usage"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:732
|
||||||
|
msgid "Checks every indexed image for usage across posts, pages, and custom fields."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:737
|
||||||
|
msgid "Sends images to external providers for reverse-image search. Requires API keys in Settings."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:754
|
||||||
|
msgid "Run now"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Admin/ToolsPage.php:757
|
||||||
|
msgid "Stop"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#. translators: %s: DB version number
|
#. translators: %s: DB version number
|
||||||
#: includes/CLI/Command.php:49
|
#: includes/CLI/Command.php:49
|
||||||
#, php-format
|
#, php-format
|
||||||
|
|
@ -484,8 +844,13 @@ msgstr ""
|
||||||
msgid "External scan complete. %d attachments processed."
|
msgid "External scan complete. %d attachments processed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Core/Plugin.php:112
|
#: includes/Core/Plugin.php:122
|
||||||
#: includes/Core/Plugin.php:113
|
#: includes/Core/Plugin.php:123
|
||||||
|
msgid "Tools"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: includes/Core/Plugin.php:135
|
||||||
|
#: includes/Core/Plugin.php:136
|
||||||
msgid "Settings"
|
msgid "Settings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -513,14 +878,6 @@ msgstr ""
|
||||||
msgid "Last Scanned (external)"
|
msgid "Last Scanned (external)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:303
|
|
||||||
msgid "Provider"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:307
|
|
||||||
msgid "Match Count"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: includes/Privacy/DataExporter.php:311
|
#: includes/Privacy/DataExporter.php:311
|
||||||
msgid "Scanned At"
|
msgid "Scanned At"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
||||||
BIN
messages.mo
BIN
messages.mo
Binary file not shown.
15
readme.txt
15
readme.txt
|
|
@ -1,11 +1,11 @@
|
||||||
=== Media Audit (by ROBOTSTXT) ===
|
=== Media Audit (by ROBOTSTXT) ===
|
||||||
Contributors: javiercasares
|
Contributors: javiercasares, robotstxt
|
||||||
Tags: media, copyright, images, reverse image search, media library
|
Tags: media, copyright, images, reverse image search, media library
|
||||||
Requires at least: 6.8
|
Requires at least: 6.8
|
||||||
Tested up to: 7.0
|
Tested up to: 7.0
|
||||||
Requires PHP: 8.2
|
Requires PHP: 8.2
|
||||||
Requires Plugins: action-scheduler
|
Requires Plugins: action-scheduler
|
||||||
Stable tag: 1.0.0
|
Stable tag: 1.2.0
|
||||||
License: GPL-3.0-or-later
|
License: GPL-3.0-or-later
|
||||||
License URI: https://www.gnu.org/licenses/gpl-3.0.txt
|
License URI: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
|
|
||||||
|
|
@ -98,6 +98,17 @@ By default, no. Enable **Settings → Delete data on uninstall** if you want all
|
||||||
|
|
||||||
Only the 3 latest versions. The full changelog is in [changelog.txt](changelog.txt).
|
Only the 3 latest versions. The full changelog is in [changelog.txt](changelog.txt).
|
||||||
|
|
||||||
|
= 1.2.0 =
|
||||||
|
|
||||||
|
* Added browser-based AJAX scan runner in the Tools page (runs without WP-Cron or Action Scheduler).
|
||||||
|
* Added "Requeue scan errors" operation to retry failed external scans after fixing API key issues.
|
||||||
|
* Added "Last Scanned" column in the audit list, sortable with NULLs-last ordering.
|
||||||
|
* Added bulk action to export external scan results as a CSV file.
|
||||||
|
|
||||||
|
= 1.1.0 =
|
||||||
|
|
||||||
|
* Updated plugin URI, author, and contributor metadata.
|
||||||
|
|
||||||
= 1.0.0 =
|
= 1.0.0 =
|
||||||
|
|
||||||
* First stable release. Internal usage scanning, external reverse image search (Google Vision + TinEye), consensus detection, WP-CLI commands, GDPR privacy tools, and Spanish/Catalan translations.
|
* First stable release. Internal usage scanning, external reverse image search (Google Vision + TinEye), consensus detection, WP-CLI commands, GDPR privacy tools, and Spanish/Catalan translations.
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,16 @@
|
||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Plugin Name: Media Audit (by ROBOTSTXT)
|
* Plugin Name: Media Audit (by ROBOTSTXT)
|
||||||
* Plugin URI: https://robotstxt.es/plugins/media-audit/
|
* Plugin URI: https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit
|
||||||
* Description: Internal media library usage auditing and external reverse image search to detect potential copyright issues.
|
* Description: Internal media library usage auditing and external reverse image search to detect potential copyright issues.
|
||||||
* Version: 1.0.0
|
* Version: 1.2.0
|
||||||
* Requires at least: 6.8
|
* Requires at least: 6.8
|
||||||
* Tested up to: 7.0
|
* Tested up to: 7.0
|
||||||
* Requires PHP: 8.2
|
* Requires PHP: 8.2
|
||||||
* Requires Plugins: action-scheduler
|
* Requires Plugins: action-scheduler
|
||||||
* Author: Javier Casares
|
* Author: ROBOTSTXT
|
||||||
* Author URI: https://javiercasares.com
|
* Author URI: https://www.robotstxt.es/
|
||||||
|
* Contributors: javiercasares, robotstxt
|
||||||
* License: GPL-3.0-or-later
|
* License: GPL-3.0-or-later
|
||||||
* License URI: https://www.gnu.org/licenses/gpl-3.0.txt
|
* License URI: https://www.gnu.org/licenses/gpl-3.0.txt
|
||||||
* Text Domain: robotstxt-mediaaudit
|
* Text Domain: robotstxt-mediaaudit
|
||||||
|
|
@ -22,7 +23,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
define( 'ROBOTSTXT_MEDIAAUDIT_VERSION', '1.0.0' );
|
define( 'ROBOTSTXT_MEDIAAUDIT_VERSION', '1.2.0' );
|
||||||
define( 'ROBOTSTXT_MEDIAAUDIT_DB_VERSION', '1.0.1' );
|
define( 'ROBOTSTXT_MEDIAAUDIT_DB_VERSION', '1.0.1' );
|
||||||
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_FILE', __FILE__ );
|
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_FILE', __FILE__ );
|
||||||
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
|
||||||
|
|
|
||||||
1
vendor/composer/autoload_classmap.php
vendored
1
vendor/composer/autoload_classmap.php
vendored
|
|
@ -10,6 +10,7 @@ return array(
|
||||||
'MediaRightsAudit\\Admin\\AuditPage' => $baseDir . '/includes/Admin/AuditPage.php',
|
'MediaRightsAudit\\Admin\\AuditPage' => $baseDir . '/includes/Admin/AuditPage.php',
|
||||||
'MediaRightsAudit\\Admin\\MediaListTable' => $baseDir . '/includes/Admin/MediaListTable.php',
|
'MediaRightsAudit\\Admin\\MediaListTable' => $baseDir . '/includes/Admin/MediaListTable.php',
|
||||||
'MediaRightsAudit\\Admin\\Settings' => $baseDir . '/includes/Admin/Settings.php',
|
'MediaRightsAudit\\Admin\\Settings' => $baseDir . '/includes/Admin/Settings.php',
|
||||||
|
'MediaRightsAudit\\Admin\\ToolsPage' => $baseDir . '/includes/Admin/ToolsPage.php',
|
||||||
'MediaRightsAudit\\CLI\\Command' => $baseDir . '/includes/CLI/Command.php',
|
'MediaRightsAudit\\CLI\\Command' => $baseDir . '/includes/CLI/Command.php',
|
||||||
'MediaRightsAudit\\Core\\Activator' => $baseDir . '/includes/Core/Activator.php',
|
'MediaRightsAudit\\Core\\Activator' => $baseDir . '/includes/Core/Activator.php',
|
||||||
'MediaRightsAudit\\Core\\Database' => $baseDir . '/includes/Core/Database.php',
|
'MediaRightsAudit\\Core\\Database' => $baseDir . '/includes/Core/Database.php',
|
||||||
|
|
|
||||||
1
vendor/composer/autoload_static.php
vendored
1
vendor/composer/autoload_static.php
vendored
|
|
@ -25,6 +25,7 @@ class ComposerStaticInit957728ab3efa005f456e5f9df13a19d2
|
||||||
'MediaRightsAudit\\Admin\\AuditPage' => __DIR__ . '/../..' . '/includes/Admin/AuditPage.php',
|
'MediaRightsAudit\\Admin\\AuditPage' => __DIR__ . '/../..' . '/includes/Admin/AuditPage.php',
|
||||||
'MediaRightsAudit\\Admin\\MediaListTable' => __DIR__ . '/../..' . '/includes/Admin/MediaListTable.php',
|
'MediaRightsAudit\\Admin\\MediaListTable' => __DIR__ . '/../..' . '/includes/Admin/MediaListTable.php',
|
||||||
'MediaRightsAudit\\Admin\\Settings' => __DIR__ . '/../..' . '/includes/Admin/Settings.php',
|
'MediaRightsAudit\\Admin\\Settings' => __DIR__ . '/../..' . '/includes/Admin/Settings.php',
|
||||||
|
'MediaRightsAudit\\Admin\\ToolsPage' => __DIR__ . '/../..' . '/includes/Admin/ToolsPage.php',
|
||||||
'MediaRightsAudit\\CLI\\Command' => __DIR__ . '/../..' . '/includes/CLI/Command.php',
|
'MediaRightsAudit\\CLI\\Command' => __DIR__ . '/../..' . '/includes/CLI/Command.php',
|
||||||
'MediaRightsAudit\\Core\\Activator' => __DIR__ . '/../..' . '/includes/Core/Activator.php',
|
'MediaRightsAudit\\Core\\Activator' => __DIR__ . '/../..' . '/includes/Core/Activator.php',
|
||||||
'MediaRightsAudit\\Core\\Database' => __DIR__ . '/../..' . '/includes/Core/Database.php',
|
'MediaRightsAudit\\Core\\Database' => __DIR__ . '/../..' . '/includes/Core/Database.php',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue