This commit is contained in:
Javier Casares 2026-06-03 06:30:49 +00:00
commit 4402f3570d
20 changed files with 1683 additions and 382 deletions

View file

@ -117,6 +117,16 @@
color: #155724;
}
.mra-badge-alert {
background: #f8d7da;
color: #721c24;
}
.mra-badge-dismissed {
background: #e8e8e8;
color: #50575e;
}
.mra-badge-match-count {
background: #721c24;
color: #fff;
@ -398,3 +408,55 @@
display: block;
margin-bottom: 6px;
}
/* -----------------------------------------------------------------------
Alerts page
----------------------------------------------------------------------- */
/* Alert domain list in alerts table */
.mra-alert-domains {
margin: 0;
padding: 0;
list-style: none;
}
.mra-alert-domains li {
margin-bottom: 4px;
font-size: 13px;
}
.mra-alert-domains small {
color: #787c82;
}
/* Alerts table */
.mra-alerts-table {
margin-top: 12px;
}
.mra-alerts-table th {
font-weight: 600;
}
/* Dismiss inline form row */
.mra-dismiss-row td {
background: #f6f7f7;
padding: 12px 16px;
}
.mra-dismiss-form-inner {
max-width: 600px;
}
.mra-dismiss-form-inner label {
display: block;
font-weight: 600;
margin-bottom: 6px;
font-size: 13px;
}
.mra-dismiss-form-inner textarea {
display: block;
width: 100%;
box-sizing: border-box;
}

View file

@ -147,5 +147,21 @@
e.preventDefault();
openModal( $( this ).data( 'id' ) );
} );
// Dismiss toggle — Alerts page.
$( document ).on( 'click', '.mra-dismiss-toggle', function () {
var targetId = $( this ).data( 'target' );
var $row = $( '#' + targetId );
$row.prop( 'hidden', function ( i, v ) { return !v; } );
$( this ).text( $row.prop( 'hidden' ) ? 'Dismiss' : 'Cancel' );
} );
// Cancel button inside dismiss form row.
$( document ).on( 'click', '.mra-dismiss-cancel', function () {
var $row = $( this ).closest( 'tr.mra-dismiss-row' );
var rowId = $row.attr( 'id' );
$row.prop( 'hidden', true );
$( '[data-target="' + rowId + '"]' ).text( 'Dismiss' );
} );
} );
} ( jQuery ) );

View file

@ -1,5 +1,41 @@
== Changelog ==
= 1.7.0 =
_Release date: 2026-05-11_
**Added**
* New **Alerts** admin page (Media Audit → Alerts) with two tabs:
* *Active Alerts* — lists all attachments with active (non-dismissed) alert-domain matches. Each row has a "Dismiss" button that expands an inline form to add optional notes.
* *Dismissed Alerts* — lists alerts that have been manually dismissed, with the dismissal notes, who dismissed them, and when. Each row has a "Reactivate" button to restore the alert.
* New DB table `mra_dismissed_alerts` (schema migration 1.2.0): stores attachment ID, dismissed-by user ID, timestamp, and free-text notes (up to 1,000 characters).
* Dashboard "Alert" card now counts only active (non-dismissed) alerts.
* Alert filter in the Media Audit list now excludes dismissed alerts.
* External Status column shows a grey "Dismissed" badge instead of the red "Alert" badge for dismissed attachments.
* "Export CSV (Alerts only)" bulk action now excludes dismissed alerts. Both CSV exports include new "Dismissed" and "Dismissed Notes" columns.
* `top_domains` stored per provider raised from 10 to 50 entries to prevent low-frequency alert domains from being silently discarded.
**Fixed**
* Alert filter in Media Audit list was incorrectly restricted to `external_status = 'matches'`, causing it to miss attachments whose alert domains were found but whose aggregate status had not yet been updated to `matches`. The filter now correctly matches the dashboard card count.
* Capability checks in `AuditPage` (render, AJAX handler, CSV export, bulk actions) used the weaker `edit_posts` capability instead of the `edit_others_posts` used in the menu registration.
**Schema changes:** `ROBOTSTXT_MEDIAAUDIT_DB_VERSION` → `1.2.0`
**Compatibility**
* WordPress: 6.8 - 7.0
* PHP: 8.2 - 8.5
* WP-CLI: 2.x
**Tests**
* PHP Coding Standards: WPCS 3.x / PHPCS 3.x
* PHPStan: level 9
* PHPCompatibility: PHP 8.2 - 8.5
* PHPUnit: 48 tests, 78 assertions
= 1.6.0 =
_Release date: 2026-05-05_

View file

@ -0,0 +1,769 @@
<?php
/**
* Admin page controller for the Alerts view.
*
* @package MediaRightsAudit\Admin
*/
namespace MediaRightsAudit\Admin;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use MediaRightsAudit\External\HostnameFilter;
use MediaRightsAudit\Admin\AttachmentDetailPage;
/**
* Registers and renders the Alerts admin page.
*
* Responsibilities:
* - Display active (non-dismissed) alert rows.
* - Display dismissed alert rows.
* - Handle dismiss / reactivate POST actions via PRG.
* - Provide static helpers for dismissed-ID lookups (cached per request).
*/
class AlertsPage {
/**
* Nonce action for all alert operations.
*/
const NONCE_ACTION = 'mra_alert_action';
/**
* Nonce field name.
*/
const NONCE_FIELD = 'mra_alert_nonce';
/**
* Maximum length of dismissal notes.
*/
const NOTES_MAX = 1000;
/**
* Rows per page for paginated tabs.
*/
const PER_PAGE = 25;
/**
* In-request cache of dismissed attachment IDs.
*
* @var array<int, true>|null
*/
private static ?array $dismissed_cache = null;
/**
* Hook suffix assigned by add_submenu_page().
*
* @var string
*/
private string $hook_suffix = '';
// -------------------------------------------------------------------------
// Public static data methods
// -------------------------------------------------------------------------
/**
* Returns all dismissed attachment IDs as a map keyed by attachment_id.
*
* Cached for the lifetime of the current request.
*
* @return array<int, true>
*/
public static function get_dismissed_ids(): array {
if ( null !== self::$dismissed_cache ) {
return self::$dismissed_cache;
}
global $wpdb;
// phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
$rows = $wpdb->get_col(
"SELECT attachment_id FROM {$wpdb->prefix}mra_dismissed_alerts"
);
self::$dismissed_cache = array();
if ( is_array( $rows ) ) {
foreach ( $rows as $id ) {
if ( is_numeric( $id ) ) {
self::$dismissed_cache[ (int) $id ] = true;
}
}
}
return self::$dismissed_cache;
}
/**
* Invalidates the in-request dismissed-IDs cache.
*
* @return void
*/
public static function invalidate_cache(): void {
self::$dismissed_cache = null;
}
/**
* Inserts or replaces a dismissal record for an attachment.
*
* @param int $attachment_id WordPress attachment post ID.
* @param int $user_id WordPress user ID performing the dismissal.
* @param string $notes Optional notes (max NOTES_MAX chars).
*
* @return void
*/
public static function dismiss( int $attachment_id, int $user_id, string $notes ): void {
global $wpdb;
$notes = mb_substr( $notes, 0, self::NOTES_MAX );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query(
$wpdb->prepare(
"INSERT INTO {$wpdb->prefix}mra_dismissed_alerts
(attachment_id, dismissed_by, dismissed_at, notes)
VALUES (%d, %d, %s, %s)
ON DUPLICATE KEY UPDATE
dismissed_by = VALUES(dismissed_by),
dismissed_at = VALUES(dismissed_at),
notes = VALUES(notes)",
$attachment_id,
$user_id,
current_time( 'mysql' ),
$notes
)
);
self::invalidate_cache();
}
/**
* Removes a dismissal record, making the alert active again.
*
* @param int $attachment_id WordPress attachment post ID.
*
* @return void
*/
public static function reactivate( int $attachment_id ): void {
global $wpdb;
// phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
$wpdb->delete(
$wpdb->prefix . 'mra_dismissed_alerts',
array( 'attachment_id' => $attachment_id ),
array( '%d' )
);
self::invalidate_cache();
}
// -------------------------------------------------------------------------
// Instance methods
// -------------------------------------------------------------------------
/**
* Stores the hook suffix and registers the load-* action.
*
* @param string $suffix Hook suffix from 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 Alerts page.
*
* @param string $hook Current admin page hook suffix.
*
* @return void
*/
public function enqueue_assets( string $hook ): void {
if ( '' === $this->hook_suffix || $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 );
}
/**
* Fires before the admin page HTML is output.
*
* Processes dismiss / reactivate POST actions and issues a PRG redirect.
*
* @return void
*/
public function handle_load(): void {
if ( ! isset( $_POST[ self::NONCE_FIELD ] ) ) {
return;
}
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'You do not have permission to perform this action.', 'robotstxt-mediaaudit' ) );
}
check_admin_referer( self::NONCE_ACTION, self::NONCE_FIELD );
$op_raw = isset( $_POST['mra_alert_op'] ) && is_string( $_POST['mra_alert_op'] )
? sanitize_key( wp_unslash( $_POST['mra_alert_op'] ) )
: '';
$aid_raw = isset( $_POST['mra_attachment_id'] ) && is_string( $_POST['mra_attachment_id'] )
? (int) sanitize_text_field( wp_unslash( $_POST['mra_attachment_id'] ) )
: 0;
$notice = 'error';
if ( $aid_raw > 0 ) {
if ( 'dismiss' === $op_raw ) {
$notes_raw = isset( $_POST['mra_notes'] ) && is_string( $_POST['mra_notes'] )
? sanitize_textarea_field( wp_unslash( $_POST['mra_notes'] ) )
: '';
self::dismiss( $aid_raw, get_current_user_id(), $notes_raw );
$notice = 'dismissed';
} elseif ( 'reactivate' === $op_raw ) {
self::reactivate( $aid_raw );
$notice = 'reactivated';
}
}
// Read tab from POST body (the hidden input in the form), fall back to GET.
$tab_raw = isset( $_POST['mra_tab'] ) && is_string( $_POST['mra_tab'] ) ? sanitize_key( wp_unslash( $_POST['mra_tab'] ) ) : '';
$tab = in_array( $tab_raw, array( 'active', 'dismissed' ), true ) ? $tab_raw : $this->get_active_tab();
wp_safe_redirect(
add_query_arg(
array(
'page' => 'robotstxt-mediaaudit-alerts',
'tab' => $tab,
'mra_notice' => $notice,
'mra_op' => $op_raw,
),
admin_url( 'admin.php' )
)
);
exit;
}
/**
* Renders the Alerts admin page.
*
* @return void
*/
public function render(): void {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'You do not have permission to access this page.', 'robotstxt-mediaaudit' ) );
}
$active_rows = self::get_active_alert_rows();
$dismissed_rows = self::get_dismissed_rows();
$tab = $this->get_active_tab();
$notice = $this->get_notice_data();
$active_count = count( $active_rows );
$dismissed_count = count( $dismissed_rows );
$paged = max( 1, isset( $_GET['paged'] ) && is_numeric( $_GET['paged'] ) ? (int) $_GET['paged'] : 1 ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$offset = ( $paged - 1 ) * self::PER_PAGE;
$page_url = add_query_arg( 'page', 'robotstxt-mediaaudit-alerts', admin_url( 'admin.php' ) );
?>
<div class="wrap">
<h1><?php esc_html_e( 'Alerts', 'robotstxt-mediaaudit' ); ?></h1>
<?php $this->render_notice( $notice ); ?>
<nav class="nav-tab-wrapper">
<a
class="nav-tab<?php echo ( 'active' === $tab ) ? ' nav-tab-active' : ''; ?>"
href="<?php echo esc_url( add_query_arg( 'tab', 'active', $page_url ) ); ?>"
>
<?php
printf(
/* translators: %d: count of active alerts */
esc_html__( 'Active Alerts (%d)', 'robotstxt-mediaaudit' ),
(int) $active_count
);
?>
</a>
<a
class="nav-tab<?php echo ( 'dismissed' === $tab ) ? ' nav-tab-active' : ''; ?>"
href="<?php echo esc_url( add_query_arg( 'tab', 'dismissed', $page_url ) ); ?>"
>
<?php
printf(
/* translators: %d: count of dismissed alerts */
esc_html__( 'Dismissed Alerts (%d)', 'robotstxt-mediaaudit' ),
(int) $dismissed_count
);
?>
</a>
</nav>
<?php if ( 'active' === $tab ) : ?>
<?php
$page_rows = array_slice( $active_rows, $offset, self::PER_PAGE );
$this->render_active_tab( $page_rows, $active_count, $paged, $page_url );
?>
<?php else : ?>
<?php
$page_rows = array_slice( $dismissed_rows, $offset, self::PER_PAGE );
$this->render_dismissed_tab( $page_rows, $dismissed_count, $paged, $page_url );
?>
<?php endif; ?>
</div>
<?php
}
// -------------------------------------------------------------------------
// Private rendering helpers
// -------------------------------------------------------------------------
/**
* Returns the active tab slug ('active' or 'dismissed').
*
* @return string
*/
private function get_active_tab(): string {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$tab = isset( $_GET['tab'] ) && is_string( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : 'active';
return in_array( $tab, array( 'active', 'dismissed' ), true ) ? $tab : 'active';
}
/**
* Reads PRG query parameters and returns structured notice data.
*
* @return array{type: string, op: string}|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'] : '' ) );
$op = sanitize_key( wp_unslash( isset( $_GET['mra_op'] ) && is_string( $_GET['mra_op'] ) ? $_GET['mra_op'] : '' ) );
// phpcs:enable WordPress.Security.NonceVerification.Recommended
return array(
'type' => $type,
'op' => $op,
);
}
/**
* Renders a WP admin notice based on the PRG redirect result.
*
* @param array{type: string, op: string}|null $notice Notice data array, or null.
*
* @return void
*/
private function render_notice( ?array $notice ): void {
if ( null === $notice ) {
return;
}
$type = $notice['type'];
$messages = array(
'dismissed' => __( 'Alert dismissed successfully.', 'robotstxt-mediaaudit' ),
'reactivated' => __( 'Alert reactivated successfully.', 'robotstxt-mediaaudit' ),
'error' => __( 'An error occurred. Please try again.', 'robotstxt-mediaaudit' ),
);
$class = ( 'error' === $type ) ? 'notice-error' : 'notice-success';
$msg = $messages[ $type ] ?? __( 'Operation completed.', 'robotstxt-mediaaudit' );
?>
<div class="notice <?php echo esc_attr( $class ); ?> is-dismissible">
<p><?php echo esc_html( $msg ); ?></p>
</div>
<?php
}
/**
* Renders the Active Alerts tab.
*
* @param array<int, array<string, mixed>> $rows Page rows.
* @param int $total Total row count.
* @param int $paged Current page number.
* @param string $page_url Base page URL.
*
* @return void
*/
private function render_active_tab( array $rows, int $total, int $paged, string $page_url ): void {
if ( empty( $rows ) ) {
echo '<p>' . esc_html__( 'No active alerts found.', 'robotstxt-mediaaudit' ) . '</p>';
return;
}
?>
<table class="widefat striped mra-alerts-table">
<thead>
<tr>
<th style="width:50px"><?php esc_html_e( 'Thumbnail', 'robotstxt-mediaaudit' ); ?></th>
<th><?php esc_html_e( 'Filename', 'robotstxt-mediaaudit' ); ?></th>
<th><?php esc_html_e( 'Alert Domains', 'robotstxt-mediaaudit' ); ?></th>
<th style="width:80px"><?php esc_html_e( 'Usage', 'robotstxt-mediaaudit' ); ?></th>
<th style="width:120px"><?php esc_html_e( 'Actions', 'robotstxt-mediaaudit' ); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ( $rows as $index => $row ) : ?>
<?php
$aid_val = $row['attachment_id'] ?? 0;
$aid = is_numeric( $aid_val ) ? (int) $aid_val : 0;
$file_name_raw = $row['file_name'] ?? '';
$file_name = is_string( $file_name_raw ) ? $file_name_raw : '';
$file_url_raw = $row['file_url'] ?? '';
$file_url = is_string( $file_url_raw ) ? $file_url_raw : '';
$usage_cnt_raw = $row['usage_count'] ?? 0;
$usage_count = is_numeric( $usage_cnt_raw ) ? (int) $usage_cnt_raw : 0;
$domains_raw = $row['top_domains_data'] ?? array();
$domains = is_array( $domains_raw ) ? $domains_raw : array();
$dismiss_id = 'mra-dismiss-row-' . $aid;
$thumb = wp_get_attachment_image( $aid, array( 40, 40 ), false, array( 'class' => 'mra-thumb' ) );
if ( ! $thumb ) {
$thumb = '<span class="dashicons dashicons-format-image" style="font-size:40px;line-height:1;"></span>';
}
?>
<tr>
<td>
<a href="<?php echo esc_url( $file_url ); ?>" target="_blank"><?php echo $thumb; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></a>
</td>
<td>
<a href="<?php echo esc_url( $file_url ); ?>" target="_blank"><?php echo esc_html( '' !== $file_name ? $file_name : '—' ); ?></a>
<div class="row-actions">
<?php
$edit_link = get_edit_post_link( $aid );
$row_links = array();
if ( $edit_link ) {
$row_links[] = '<a href="' . esc_url( $edit_link ) . '">' . esc_html__( 'Edit', 'robotstxt-mediaaudit' ) . '</a>';
}
$row_links[] = '<a href="' . esc_url( AttachmentDetailPage::url( $aid ) ) . '"><strong>' . esc_html__( 'Full Report', 'robotstxt-mediaaudit' ) . '</strong></a>';
echo implode( ' | ', $row_links ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
?>
</div>
</td>
<td>
<?php if ( ! empty( $domains ) ) : ?>
<ul class="mra-alert-domains">
<?php foreach ( $domains as $domain => $count ) : ?>
<li>
<span class="mra-badge mra-badge-alert"><?php esc_html_e( 'Alert', 'robotstxt-mediaaudit' ); ?></span>
<?php echo esc_html( $domain ); ?>
<small>(<?php echo esc_html( number_format_i18n( is_numeric( $count ) ? (int) $count : 0 ) ); ?>)</small>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</td>
<td><?php echo esc_html( number_format_i18n( $usage_count ) ); ?></td>
<td>
<button
type="button"
class="button mra-dismiss-toggle"
data-target="<?php echo esc_attr( $dismiss_id ); ?>"
><?php esc_html_e( 'Dismiss', 'robotstxt-mediaaudit' ); ?></button>
</td>
</tr>
<tr id="<?php echo esc_attr( $dismiss_id ); ?>" class="mra-dismiss-row" hidden>
<td colspan="5">
<div class="mra-dismiss-form-inner">
<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=robotstxt-mediaaudit-alerts' ) ); ?>">
<?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_FIELD ); ?>
<input type="hidden" name="mra_alert_op" value="dismiss" />
<input type="hidden" name="mra_attachment_id" value="<?php echo esc_attr( (string) $aid ); ?>" />
<input type="hidden" name="mra_tab" value="active" />
<label for="mra-notes-<?php echo esc_attr( (string) $aid ); ?>">
<?php esc_html_e( 'Notes (optional):', 'robotstxt-mediaaudit' ); ?>
</label>
<textarea
id="mra-notes-<?php echo esc_attr( (string) $aid ); ?>"
name="mra_notes"
rows="2"
maxlength="<?php echo esc_attr( (string) self::NOTES_MAX ); ?>"
class="large-text"
></textarea>
<div style="margin-top:8px">
<button type="submit" class="button button-primary"><?php esc_html_e( 'Confirm Dismiss', 'robotstxt-mediaaudit' ); ?></button>
<button type="button" class="button mra-dismiss-cancel"><?php esc_html_e( 'Cancel', 'robotstxt-mediaaudit' ); ?></button>
</div>
</form>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php
$pagination = paginate_links(
array(
'base' => add_query_arg( 'paged', '%#%', add_query_arg( 'tab', 'active', $page_url ) ),
'format' => '',
'current' => $paged,
'total' => (int) ceil( $total / self::PER_PAGE ),
'prev_text' => '&laquo;',
'next_text' => '&raquo;',
)
);
if ( $pagination ) {
echo '<div class="tablenav"><div class="tablenav-pages">' . $pagination . '</div></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
/**
* Renders the Dismissed Alerts tab.
*
* @param array<int, array<string, mixed>> $rows Page rows.
* @param int $total Total row count.
* @param int $paged Current page number.
* @param string $page_url Base page URL.
*
* @return void
*/
private function render_dismissed_tab( array $rows, int $total, int $paged, string $page_url ): void {
if ( empty( $rows ) ) {
echo '<p>' . esc_html__( 'No dismissed alerts.', 'robotstxt-mediaaudit' ) . '</p>';
return;
}
?>
<table class="widefat striped mra-alerts-table">
<thead>
<tr>
<th style="width:50px"><?php esc_html_e( 'Thumbnail', 'robotstxt-mediaaudit' ); ?></th>
<th><?php esc_html_e( 'Filename', 'robotstxt-mediaaudit' ); ?></th>
<th><?php esc_html_e( 'Alert Domains', 'robotstxt-mediaaudit' ); ?></th>
<th><?php esc_html_e( 'Notes', 'robotstxt-mediaaudit' ); ?></th>
<th><?php esc_html_e( 'Dismissed By', 'robotstxt-mediaaudit' ); ?></th>
<th><?php esc_html_e( 'Dismissed At', 'robotstxt-mediaaudit' ); ?></th>
<th style="width:120px"><?php esc_html_e( 'Actions', 'robotstxt-mediaaudit' ); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ( $rows as $row ) : ?>
<?php
$aid_val = $row['attachment_id'] ?? 0;
$aid = is_numeric( $aid_val ) ? (int) $aid_val : 0;
$file_name_raw = $row['file_name'] ?? '';
$file_name = is_string( $file_name_raw ) ? $file_name_raw : '';
$file_url_raw = $row['file_url'] ?? '';
$file_url = is_string( $file_url_raw ) ? $file_url_raw : '';
$notes_raw = $row['notes'] ?? '';
$notes = is_string( $notes_raw ) ? $notes_raw : '';
$dis_by_raw = $row['dismissed_by'] ?? 0;
$dismissed_by = is_numeric( $dis_by_raw ) ? (int) $dis_by_raw : 0;
$dis_at_raw = $row['dismissed_at'] ?? '';
$dismissed_at = is_string( $dis_at_raw ) ? $dis_at_raw : '';
$domains_raw = $row['top_domains_data'] ?? array();
$domains = is_array( $domains_raw ) ? $domains_raw : array();
$user = $dismissed_by > 0 ? get_user_by( 'id', $dismissed_by ) : false;
$display_name = ( $user && isset( $user->display_name ) ) ? $user->display_name : (string) $dismissed_by;
$thumb = wp_get_attachment_image( $aid, array( 40, 40 ), false, array( 'class' => 'mra-thumb' ) );
if ( ! $thumb ) {
$thumb = '<span class="dashicons dashicons-format-image" style="font-size:40px;line-height:1;"></span>';
}
?>
<tr>
<td>
<a href="<?php echo esc_url( $file_url ); ?>" target="_blank"><?php echo $thumb; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></a>
</td>
<td>
<a href="<?php echo esc_url( $file_url ); ?>" target="_blank"><?php echo esc_html( '' !== $file_name ? $file_name : '—' ); ?></a>
<div class="row-actions">
<?php
$edit_link = get_edit_post_link( $aid );
$row_links2 = array();
if ( $edit_link ) {
$row_links2[] = '<a href="' . esc_url( $edit_link ) . '">' . esc_html__( 'Edit', 'robotstxt-mediaaudit' ) . '</a>';
}
$row_links2[] = '<a href="' . esc_url( AttachmentDetailPage::url( $aid ) ) . '"><strong>' . esc_html__( 'Full Report', 'robotstxt-mediaaudit' ) . '</strong></a>';
echo implode( ' | ', $row_links2 ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
?>
</div>
</td>
<td>
<?php if ( ! empty( $domains ) ) : ?>
<ul class="mra-alert-domains">
<?php foreach ( $domains as $domain => $count ) : ?>
<li>
<span class="mra-badge mra-badge-dismissed"><?php esc_html_e( 'Dismissed', 'robotstxt-mediaaudit' ); ?></span>
<?php echo esc_html( $domain ); ?>
<small>(<?php echo esc_html( number_format_i18n( is_numeric( $count ) ? (int) $count : 0 ) ); ?>)</small>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</td>
<td><?php echo esc_html( $notes ); ?></td>
<td><?php echo esc_html( $display_name ); ?></td>
<td><?php echo esc_html( $dismissed_at ); ?></td>
<td>
<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=robotstxt-mediaaudit-alerts' ) ); ?>" style="display:inline">
<?php wp_nonce_field( self::NONCE_ACTION, self::NONCE_FIELD ); ?>
<input type="hidden" name="mra_alert_op" value="reactivate" />
<input type="hidden" name="mra_attachment_id" value="<?php echo esc_attr( (string) $aid ); ?>" />
<input type="hidden" name="mra_tab" value="dismissed" />
<button type="submit" class="button"><?php esc_html_e( 'Reactivate', 'robotstxt-mediaaudit' ); ?></button>
</form>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php
$pagination = paginate_links(
array(
'base' => add_query_arg( 'paged', '%#%', add_query_arg( 'tab', 'dismissed', $page_url ) ),
'format' => '',
'current' => $paged,
'total' => (int) ceil( $total / self::PER_PAGE ),
'prev_text' => '&laquo;',
'next_text' => '&raquo;',
)
);
if ( $pagination ) {
echo '<div class="tablenav"><div class="tablenav-pages">' . $pagination . '</div></div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
// -------------------------------------------------------------------------
// Private static data methods
// -------------------------------------------------------------------------
/**
* Queries active (non-dismissed) alert rows.
*
* Fetches all mra_media_index candidates that have at least one row in
* mra_external_results (via EXISTS), excludes dismissed attachments via LEFT JOIN,
* bulk-fetches top_domains, and PHP-filters to only rows with at least one alert domain.
*
* @return array<int, array<string, mixed>>
*/
private static function get_active_alert_rows(): array {
global $wpdb;
// phpcs:disable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$candidates = $wpdb->get_results(
"SELECT i.attachment_id, i.file_name, i.file_url,
(SELECT COUNT(*) FROM {$wpdb->prefix}mra_media_usage mu WHERE mu.attachment_id = i.attachment_id) AS usage_count
FROM {$wpdb->prefix}mra_media_index i
LEFT JOIN {$wpdb->prefix}mra_dismissed_alerts da ON da.attachment_id = i.attachment_id
WHERE da.attachment_id IS NULL
AND EXISTS (SELECT 1 FROM {$wpdb->prefix}mra_external_results er WHERE er.attachment_id = i.attachment_id)
ORDER BY i.attachment_id ASC",
ARRAY_A
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
if ( ! is_array( $candidates ) || empty( $candidates ) ) {
return array();
}
$all_ids = array_map( 'intval', array_column( $candidates, 'attachment_id' ) );
$top_domains_by_id = MediaListTable::fetch_top_domains( $all_ids );
$result = array();
foreach ( $candidates as $row ) {
if ( ! is_array( $row ) ) {
continue;
}
$aid_val = $row['attachment_id'] ?? null;
$aid = is_numeric( $aid_val ) ? (int) $aid_val : 0;
$domains = $top_domains_by_id[ $aid ] ?? array();
// Keep only alert-classified domains.
$alert_domains = array();
foreach ( $domains as $domain => $count ) {
if ( HostnameFilter::classify( $domain ) === 'alert' ) {
$alert_domains[ $domain ] = $count;
}
}
if ( empty( $alert_domains ) ) {
continue;
}
$result[] = array(
'attachment_id' => $aid,
'file_name' => is_string( $row['file_name'] ?? null ) ? $row['file_name'] : '',
'file_url' => is_string( $row['file_url'] ?? null ) ? $row['file_url'] : '',
'usage_count' => is_numeric( $row['usage_count'] ?? null ) ? (int) $row['usage_count'] : 0,
'top_domains_data' => $alert_domains,
);
}
return $result;
}
/**
* Queries dismissed alert rows.
*
* Fetches all mra_dismissed_alerts records LEFT JOINed with mra_media_index,
* bulk-fetches top_domains, and PHP-filters to alert domains only.
*
* @return array<int, array<string, mixed>>
*/
private static function get_dismissed_rows(): array {
global $wpdb;
// phpcs:disable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$candidates = $wpdb->get_results(
"SELECT da.attachment_id, da.dismissed_by, da.dismissed_at, da.notes,
COALESCE(i.file_name, '') AS file_name,
COALESCE(i.file_url, '') AS file_url
FROM {$wpdb->prefix}mra_dismissed_alerts da
LEFT JOIN {$wpdb->prefix}mra_media_index i ON i.attachment_id = da.attachment_id
ORDER BY da.dismissed_at DESC",
ARRAY_A
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
if ( ! is_array( $candidates ) || empty( $candidates ) ) {
return array();
}
$all_ids = array_map( 'intval', array_column( $candidates, 'attachment_id' ) );
$top_domains_by_id = MediaListTable::fetch_top_domains( $all_ids );
$result = array();
foreach ( $candidates as $row ) {
if ( ! is_array( $row ) ) {
continue;
}
$aid_val = $row['attachment_id'] ?? null;
$aid = is_numeric( $aid_val ) ? (int) $aid_val : 0;
$domains = $top_domains_by_id[ $aid ] ?? array();
// Keep only alert-classified domains.
$alert_domains = array();
foreach ( $domains as $domain => $count ) {
if ( HostnameFilter::classify( $domain ) === 'alert' ) {
$alert_domains[ $domain ] = $count;
}
}
$result[] = array(
'attachment_id' => $aid,
'file_name' => is_string( $row['file_name'] ?? null ) ? $row['file_name'] : '',
'file_url' => is_string( $row['file_url'] ?? null ) ? $row['file_url'] : '',
'dismissed_by' => is_numeric( $row['dismissed_by'] ?? null ) ? (int) $row['dismissed_by'] : 0,
'dismissed_at' => is_string( $row['dismissed_at'] ?? null ) ? $row['dismissed_at'] : '',
'notes' => is_string( $row['notes'] ?? null ) ? $row['notes'] : '',
'top_domains_data' => $alert_domains,
);
}
return $result;
}
}

View file

@ -7,6 +7,7 @@
namespace MediaRightsAudit\Admin;
use MediaRightsAudit\Admin\AlertsPage;
use MediaRightsAudit\Admin\AttachmentDetailPage;
use MediaRightsAudit\External\ExternalScanner;
use MediaRightsAudit\External\HostnameFilter;
@ -131,7 +132,7 @@ class AuditPage {
* @return void
*/
public function render(): void {
if ( ! current_user_can( 'edit_posts' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'You do not have permission to access this page.', 'robotstxt-mediaaudit' ) );
}
@ -171,7 +172,7 @@ class AuditPage {
public function ajax_usage_details(): void {
check_ajax_referer( 'mra_usage_details', 'nonce' );
if ( ! current_user_can( 'edit_posts' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) ) );
}
@ -525,7 +526,7 @@ class AuditPage {
private function handle_export_csv( bool $alerts_only ): void {
check_admin_referer( 'bulk-mra-attachments' );
if ( ! current_user_can( 'edit_posts' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
}
@ -565,6 +566,8 @@ class AuditPage {
__( 'Alert Domains', 'robotstxt-mediaaudit' ),
__( 'Other Domains', 'robotstxt-mediaaudit' ),
__( 'Ignored Domains', 'robotstxt-mediaaudit' ),
__( 'Dismissed', 'robotstxt-mediaaudit' ),
__( 'Dismissed Notes', 'robotstxt-mediaaudit' ),
)
);
@ -696,6 +699,29 @@ class AuditPage {
}
}
// Fetch dismissed IDs and notes for CSV columns.
$dismissed_ids = AlertsPage::get_dismissed_ids();
// phpcs:disable WordPress.DB.DirectDatabaseQuery
$dismissed_notes_rows = $wpdb->get_results(
"SELECT attachment_id, notes FROM {$wpdb->prefix}mra_dismissed_alerts",
ARRAY_A
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery
$dismissed_notes = array();
if ( is_array( $dismissed_notes_rows ) ) {
foreach ( $dismissed_notes_rows as $dn ) {
if ( is_array( $dn ) ) {
$dn_aid_raw = $dn['attachment_id'] ?? null;
$dn_aid = is_numeric( $dn_aid_raw ) ? (int) $dn_aid_raw : 0;
if ( $dn_aid > 0 ) {
$dismissed_notes[ $dn_aid ] = is_string( $dn['notes'] ?? null ) ? (string) $dn['notes'] : '';
}
}
}
}
$known_providers = array( 'google_vision', 'tineye', 'picdefense' );
$output = array();
@ -731,9 +757,11 @@ class AuditPage {
}
}
$has_alert = ! empty( $alert_list );
$has_alert = ! empty( $alert_list );
$is_dismissed = isset( $dismissed_ids[ $aid ] );
if ( $alerts_only && ! $has_alert ) {
// Skip row if alerts_only and either no alert or already dismissed.
if ( $alerts_only && ( ! $has_alert || $is_dismissed ) ) {
continue;
}
@ -757,6 +785,8 @@ class AuditPage {
$row_data[] = implode( '; ', $alert_list );
$row_data[] = implode( '; ', $other_list );
$row_data[] = implode( '; ', $ignored_list );
$row_data[] = $is_dismissed ? __( 'Yes', 'robotstxt-mediaaudit' ) : __( 'No', 'robotstxt-mediaaudit' );
$row_data[] = $dismissed_notes[ $aid ] ?? '';
$output[] = $row_data;
}
@ -772,7 +802,7 @@ class AuditPage {
private function handle_run_external_scan(): void {
check_admin_referer( 'bulk-mra-attachments' );
if ( ! current_user_can( 'edit_posts' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
}
@ -804,7 +834,7 @@ class AuditPage {
private function handle_purge_external_data(): void {
check_admin_referer( 'bulk-mra-attachments' );
if ( ! current_user_can( 'edit_posts' ) ) {
if ( ! current_user_can( 'edit_others_posts' ) ) {
wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
}
@ -942,8 +972,12 @@ class AuditPage {
}
}
$dismissed = AlertsPage::get_dismissed_ids();
$alert_count = 0;
foreach ( $merged as $domains ) {
foreach ( $merged as $aid => $domains ) {
if ( isset( $dismissed[ $aid ] ) ) {
continue;
}
if ( HostnameFilter::has_alert_domains( $domains ) ) {
++$alert_count;
}

View file

@ -7,6 +7,7 @@
namespace MediaRightsAudit\Admin;
use MediaRightsAudit\Admin\AlertsPage;
use MediaRightsAudit\Admin\AttachmentDetailPage;
use MediaRightsAudit\External\HostnameFilter;
@ -290,7 +291,23 @@ class MediaListTable extends \WP_List_Table {
$top_domains_data[ $td_key ] = $td_val;
}
}
$has_alert = ! empty( $top_domains_data ) && HostnameFilter::has_alert_domains( $top_domains_data );
$has_alert = ! empty( $top_domains_data ) && HostnameFilter::has_alert_domains( $top_domains_data );
$is_dismissed = ! empty( $item['is_dismissed'] );
if ( $has_alert && $is_dismissed ) {
$aid_val = $item['attachment_id'];
$aid = is_numeric( $aid_val ) ? (int) $aid_val : 0;
$out = sprintf(
'<span class="mra-badge mra-badge-dismissed">%s</span>',
esc_html__( 'Dismissed', 'robotstxt-mediaaudit' )
);
$out .= sprintf(
' <a href="#" class="mra-view-details" data-id="%d">%s</a>',
$aid,
esc_html__( 'View Results', 'robotstxt-mediaaudit' )
);
return $out;
}
if ( $has_alert ) {
$out = sprintf(
@ -486,6 +503,8 @@ class MediaListTable extends \WP_List_Table {
public function prepare_items() {
global $wpdb;
$dismissed_ids = AlertsPage::get_dismissed_ids();
$per_page = 20;
$paged = $this->get_pagenum();
$offset = ( $paged - 1 ) * $per_page;
@ -508,8 +527,10 @@ class MediaListTable extends \WP_List_Table {
// Detect alert filter before normalising external_status.
$filter_alert = ( 'alert' === $external_status );
if ( $filter_alert ) {
// Reuse existing matches WHERE logic to narrow the candidate set.
$external_status = 'matches';
// Do not restrict by external_status: attachments can have alert domains
// even when external_status is not 'matches'. The PHP pass below handles
// the real filter, consistent with get_alert_attachment_count().
$external_status = '';
}
if ( ! in_array( $external_status, self::EXTERNAL_STATUSES, true ) ) {
@ -578,7 +599,7 @@ class MediaListTable extends \WP_List_Table {
$all_ids = array_map( 'intval', array_column( $all_rows, 'attachment_id' ) );
$top_domains_by_id = self::fetch_top_domains( $all_ids );
// PHP-filter: keep only rows that have at least one alert domain.
// PHP-filter: keep only rows that have at least one alert domain and are not dismissed.
$filtered = array();
foreach ( $all_rows as $r ) {
if ( ! is_array( $r ) ) {
@ -586,7 +607,7 @@ class MediaListTable extends \WP_List_Table {
}
$aid_val = $r['attachment_id'] ?? null;
$aid = is_numeric( $aid_val ) ? (int) $aid_val : 0;
if ( HostnameFilter::has_alert_domains( $top_domains_by_id[ $aid ] ?? array() ) ) {
if ( HostnameFilter::has_alert_domains( $top_domains_by_id[ $aid ] ?? array() ) && ! isset( $dismissed_ids[ $aid ] ) ) {
$filtered[] = $r;
}
}
@ -594,11 +615,12 @@ class MediaListTable extends \WP_List_Table {
$total = count( $filtered );
$rows = array_slice( $filtered, $offset, $per_page );
// Attach top_domains_data for the page slice.
// Attach top_domains_data and is_dismissed for the page slice.
foreach ( $rows as &$row ) {
$rid_val = $row['attachment_id'] ?? null;
$rid = is_numeric( $rid_val ) ? (int) $rid_val : 0;
$row['top_domains_data'] = $top_domains_by_id[ $rid ] ?? array();
$row['is_dismissed'] = isset( $dismissed_ids[ $rid ] );
}
unset( $row );
} else {
@ -649,6 +671,7 @@ class MediaListTable extends \WP_List_Table {
$rid_val = $row['attachment_id'] ?? null;
$rid = is_numeric( $rid_val ) ? (int) $rid_val : 0;
$row['top_domains_data'] = $top_domains_by_id[ $rid ] ?? array();
$row['is_dismissed'] = isset( $dismissed_ids[ $rid ] );
}
unset( $row );
}

View file

@ -24,6 +24,7 @@ class Database {
self::migration_100();
self::migration_101();
self::migration_110();
self::migration_120();
}
/**
@ -48,6 +49,10 @@ class Database {
if ( version_compare( $current, '1.1.0', '<' ) ) {
self::migration_110();
}
if ( version_compare( $current, '1.2.0', '<' ) ) {
self::migration_120();
}
}
/**
@ -57,6 +62,7 @@ class Database {
*/
public static function drop_tables(): void {
global $wpdb;
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_dismissed_alerts`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_provider_status`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_external_results`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_media_usage`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
@ -74,6 +80,7 @@ class Database {
global $wpdb;
// phpcs:disable WordPress.DB.DirectDatabaseQuery
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_dismissed_alerts`" );
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_provider_status`" );
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_external_results`" );
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_media_usage`" );
@ -215,4 +222,32 @@ class Database {
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared
}
/**
* Migration 1.2.0 creates the mra_dismissed_alerts table.
*
* Stores per-attachment alert dismissal records with dismisser, timestamp,
* and optional notes. Primary key on attachment_id (one dismissal per image).
*
* Safe to re-run: dbDelta skips existing tables.
*
* @return void
*/
private static function migration_120(): void {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
dbDelta(
"CREATE TABLE {$wpdb->prefix}mra_dismissed_alerts (
attachment_id bigint(20) unsigned NOT NULL,
dismissed_by bigint(20) unsigned NOT NULL DEFAULT 0,
dismissed_at datetime NOT NULL,
notes text NOT NULL DEFAULT '',
PRIMARY KEY (attachment_id)
) {$charset_collate};"
);
}
}

View file

@ -7,6 +7,7 @@
namespace MediaRightsAudit\Core;
use MediaRightsAudit\Admin\AlertsPage;
use MediaRightsAudit\Admin\AttachmentDetailPage;
use MediaRightsAudit\Admin\AuditPage;
use MediaRightsAudit\Admin\Settings;
@ -27,6 +28,13 @@ use MediaRightsAudit\Privacy\DataExporter;
*/
class Plugin {
/**
* Alerts page controller.
*
* @var AlertsPage
*/
private AlertsPage $alerts_page;
/**
* Settings page handler.
*
@ -59,6 +67,7 @@ class Plugin {
* Initialises dependencies.
*/
public function __construct() {
$this->alerts_page = new AlertsPage();
$this->settings = new Settings();
$this->audit_page = new AuditPage();
$this->tools_page = new ToolsPage();
@ -127,6 +136,19 @@ class Plugin {
array( $this->audit_page, 'render' )
);
$alerts_suffix = add_submenu_page(
'robotstxt-mediaaudit',
__( 'Alerts', 'robotstxt-mediaaudit' ),
__( 'Alerts', 'robotstxt-mediaaudit' ),
'edit_others_posts',
'robotstxt-mediaaudit-alerts',
array( $this->alerts_page, 'render' )
);
if ( is_string( $alerts_suffix ) ) {
$this->alerts_page->set_hook_suffix( $alerts_suffix );
}
$tools_suffix = add_submenu_page(
'robotstxt-mediaaudit',
__( 'Tools', 'robotstxt-mediaaudit' ),

View file

@ -99,7 +99,7 @@ abstract class AbstractProvider {
}
arsort( $counts );
return array_slice( $counts, 0, 10, true );
return array_slice( $counts, 0, 50, true );
}
/**

View file

@ -507,8 +507,7 @@ class ExternalScanner {
$row = $wpdb->get_row(
$wpdb->prepare(
"SELECT
SUM(status = 'queued') AS queued_count,
SUM(status = 'error') AS error_count,
SUM(status = 'queued') AS queued_count,
SUM(status = 'scanned') AS scanned_count
FROM {$wpdb->prefix}mra_provider_status
WHERE attachment_id = %d",
@ -523,7 +522,6 @@ class ExternalScanner {
}
$queued_count = isset( $row['queued_count'] ) && is_numeric( $row['queued_count'] ) ? (int) $row['queued_count'] : 0;
$error_count = isset( $row['error_count'] ) && is_numeric( $row['error_count'] ) ? (int) $row['error_count'] : 0;
$scanned_count = isset( $row['scanned_count'] ) && is_numeric( $row['scanned_count'] ) ? (int) $row['scanned_count'] : 0;
if ( $queued_count > 0 ) {
@ -544,9 +542,6 @@ class ExternalScanner {
$new_status = ( is_numeric( $match_sum ) && (int) $match_sum > 0 ) ? 'matches' : 'scanned';
}
// Suppress unused variable inspection: $error_count is available for future use.
unset( $error_count );
$wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->prefix . 'mra_media_index',
array(

Binary file not shown.

View file

@ -2,10 +2,10 @@
# This file is distributed under the GPL-3.0-or-later.
msgid ""
msgstr ""
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.6.0\n"
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.7.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-"
"mediaaudit\n"
"POT-Creation-Date: 2026-05-05T10:39:07+00:00\n"
"POT-Creation-Date: 2026-05-11T07:13:58+00:00\n"
"PO-Revision-Date: 2026-05-01 07:41+0000\n"
"Last-Translator: Javier Casares <javier@casares.org>\n"
"Language-Team: Catalan <ca@li.org>\n"
@ -45,13 +45,136 @@ msgstr ""
msgid "https://www.robotstxt.es/"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:40 includes/Admin/AuditPage.php:135
#: includes/Admin/Settings.php:898 includes/Admin/ToolsPage.php:253
#: includes/Admin/AlertsPage.php:210
msgid "You do not have permission to perform this action."
msgstr "No teniu permís per accedir a aquesta pàgina."
#: includes/Admin/AlertsPage.php:263 includes/Admin/AttachmentDetailPage.php:40
#: includes/Admin/AuditPage.php:136 includes/Admin/Settings.php:898
#: includes/Admin/ToolsPage.php:253
msgid "You do not have permission to access this page."
msgstr "No teniu permís per accedir a aquesta pàgina."
#: includes/Admin/AlertsPage.php:280 includes/Core/Plugin.php:141
#: includes/Core/Plugin.php:142
msgid "Alerts"
msgstr "Alertes"
#. translators: %d: count of active alerts
#: includes/Admin/AlertsPage.php:292
#, php-format
msgid "Active Alerts (%d)"
msgstr "Alertes actives (%d)"
#. translators: %d: count of dismissed alerts
#: includes/Admin/AlertsPage.php:304
#, php-format
msgid "Dismissed Alerts (%d)"
msgstr "Alertes descartades (%d)"
#: includes/Admin/AlertsPage.php:376
msgid "Alert dismissed successfully."
msgstr "Alerta descartada correctament."
#: includes/Admin/AlertsPage.php:377
msgid "Alert reactivated successfully."
msgstr "Alerta reactivada correctament."
#: includes/Admin/AlertsPage.php:378
msgid "An error occurred. Please try again."
msgstr "S'ha produït un error. Si us plau, torna-ho a intentar."
#: includes/Admin/AlertsPage.php:382 includes/Admin/ToolsPage.php:376
msgid "Operation completed."
msgstr "Operació completada."
#: includes/Admin/AlertsPage.php:402
msgid "No active alerts found."
msgstr "No s'han trobat alertes actives."
#: includes/Admin/AlertsPage.php:409 includes/Admin/AlertsPage.php:541
#: includes/Admin/MediaListTable.php:55
msgid "Thumbnail"
msgstr "Miniatura"
#: includes/Admin/AlertsPage.php:410 includes/Admin/AlertsPage.php:542
#: includes/Admin/AttachmentDetailPage.php:87 includes/Admin/AuditPage.php:554
#: includes/Admin/MediaListTable.php:56 includes/Privacy/DataExporter.php:261
msgid "Filename"
msgstr "Nom de fitxer"
#: includes/Admin/AlertsPage.php:411 includes/Admin/AlertsPage.php:543
#: includes/Admin/AttachmentDetailPage.php:372 includes/Admin/AuditPage.php:566
msgid "Alert Domains"
msgstr "Dominis d'alerta"
#: includes/Admin/AlertsPage.php:412
msgid "Usage"
msgstr "Usos"
#: includes/Admin/AlertsPage.php:413 includes/Admin/AlertsPage.php:547
msgid "Actions"
msgstr "Accions"
#: includes/Admin/AlertsPage.php:447 includes/Admin/AlertsPage.php:587
#: includes/Admin/MediaListTable.php:172
msgid "Edit"
msgstr "Edita"
#: includes/Admin/AlertsPage.php:449 includes/Admin/AlertsPage.php:589
#: includes/Admin/MediaListTable.php:182
msgid "Full Report"
msgstr "Informe complet"
#: includes/Admin/AlertsPage.php:459 includes/Admin/AuditPage.php:382
#: includes/Admin/AuditPage.php:489 includes/Admin/MediaListTable.php:315
#: includes/Admin/MediaListTable.php:452
msgid "Alert"
msgstr "Alerta"
#: includes/Admin/AlertsPage.php:473
msgid "Dismiss"
msgstr "Descartar"
#: includes/Admin/AlertsPage.php:485
msgid "Notes (optional):"
msgstr "Notes (opcional):"
#: includes/Admin/AlertsPage.php:495
msgid "Confirm Dismiss"
msgstr "Confirmar descart"
#: includes/Admin/AlertsPage.php:496
msgid "Cancel"
msgstr "Cancel·lar"
#: includes/Admin/AlertsPage.php:534
msgid "No dismissed alerts."
msgstr "No hi ha alertes descartades."
#: includes/Admin/AlertsPage.php:544
msgid "Notes"
msgstr "Notes"
#: includes/Admin/AlertsPage.php:545
msgid "Dismissed By"
msgstr "Descartada per"
#: includes/Admin/AlertsPage.php:546
msgid "Dismissed At"
msgstr "Descartada el"
#: includes/Admin/AlertsPage.php:599 includes/Admin/AuditPage.php:569
#: includes/Admin/MediaListTable.php:302
msgid "Dismissed"
msgstr "Descartada"
#: includes/Admin/AlertsPage.php:616
msgid "Reactivate"
msgstr "Reactivar"
#: includes/Admin/AttachmentDetailPage.php:51
#: includes/Admin/AttachmentDetailPage.php:56 includes/Admin/AuditPage.php:180
#: includes/Admin/AttachmentDetailPage.php:56 includes/Admin/AuditPage.php:181
msgid "Invalid attachment ID."
msgstr "Identificador de fitxer adjunt no vàlid."
@ -64,21 +187,16 @@ msgid "File Information"
msgstr "Informació del fitxer"
#: includes/Admin/AttachmentDetailPage.php:81
#: includes/Admin/MediaListTable.php:56
#: includes/Admin/MediaListTable.php:57
msgid "ID"
msgstr "ID"
#: includes/Admin/AttachmentDetailPage.php:87 includes/Admin/AuditPage.php:553
#: includes/Admin/MediaListTable.php:55 includes/Privacy/DataExporter.php:261
msgid "Filename"
msgstr "Nom de fitxer"
#: includes/Admin/AttachmentDetailPage.php:94 includes/Admin/AuditPage.php:554
#: includes/Admin/AttachmentDetailPage.php:94 includes/Admin/AuditPage.php:555
#: includes/Privacy/DataExporter.php:265
msgid "File URL"
msgstr "URL del fitxer"
#: includes/Admin/AttachmentDetailPage.php:102 includes/Admin/AuditPage.php:555
#: includes/Admin/AttachmentDetailPage.php:102 includes/Admin/AuditPage.php:556
msgid "MIME Type"
msgstr "Tipus MIME"
@ -90,24 +208,24 @@ msgstr "Mida del fitxer"
msgid "Internal scan date"
msgstr "Data de l'exploració interna"
#: includes/Admin/AttachmentDetailPage.php:124 includes/Admin/AuditPage.php:558
#: includes/Admin/MediaListTable.php:59
#: includes/Admin/AttachmentDetailPage.php:124 includes/Admin/AuditPage.php:559
#: includes/Admin/MediaListTable.php:60
msgid "External Status"
msgstr "Estat extern"
#: includes/Admin/AttachmentDetailPage.php:139 includes/Admin/AuditPage.php:244
#: includes/Admin/AttachmentDetailPage.php:139 includes/Admin/AuditPage.php:245
msgid "Internal Usage"
msgstr "Ús intern"
#: includes/Admin/AttachmentDetailPage.php:144 includes/Admin/AuditPage.php:188
#: includes/Admin/AttachmentDetailPage.php:144 includes/Admin/AuditPage.php:189
msgid "Featured Image"
msgstr "Imatge destacada"
#: includes/Admin/AttachmentDetailPage.php:145 includes/Admin/AuditPage.php:189
#: includes/Admin/AttachmentDetailPage.php:145 includes/Admin/AuditPage.php:190
msgid "Post Content"
msgstr "Contingut de l'entrada"
#: includes/Admin/AttachmentDetailPage.php:146 includes/Admin/AuditPage.php:190
#: includes/Admin/AttachmentDetailPage.php:146 includes/Admin/AuditPage.php:191
msgid "Custom Field"
msgstr "Camp personalitzat"
@ -115,24 +233,24 @@ msgstr "Camp personalitzat"
msgid "Not used in any post."
msgstr "Aquest fitxer no s'utilitza en cap entrada."
#: includes/Admin/AttachmentDetailPage.php:154 includes/Admin/AuditPage.php:198
#: includes/Admin/AttachmentDetailPage.php:154 includes/Admin/AuditPage.php:199
msgid "Post"
msgstr "Entrada"
#: includes/Admin/AttachmentDetailPage.php:155 includes/Admin/AuditPage.php:199
#: includes/Admin/AttachmentDetailPage.php:155 includes/Admin/AuditPage.php:200
msgid "Type"
msgstr "Tipus"
#: includes/Admin/AttachmentDetailPage.php:156 includes/Admin/AuditPage.php:200
#: includes/Admin/AttachmentDetailPage.php:156 includes/Admin/AuditPage.php:201
msgid "Context"
msgstr "Context"
#: includes/Admin/AttachmentDetailPage.php:157 includes/Admin/AuditPage.php:201
#: includes/Admin/AuditPage.php:373
#: includes/Admin/AttachmentDetailPage.php:157 includes/Admin/AuditPage.php:202
#: includes/Admin/AuditPage.php:374
msgid "Status"
msgstr "Estat"
#: includes/Admin/AttachmentDetailPage.php:198 includes/Admin/AuditPage.php:293
#: includes/Admin/AttachmentDetailPage.php:198 includes/Admin/AuditPage.php:294
msgid "External Scan Results"
msgstr "Resultats de l'exploració externa"
@ -141,7 +259,7 @@ msgid "No external scan data available."
msgstr "No hi ha dades d'exploració externa disponibles."
#. translators: %d: number of external matches
#: includes/Admin/AttachmentDetailPage.php:313 includes/Admin/AuditPage.php:323
#: includes/Admin/AttachmentDetailPage.php:313 includes/Admin/AuditPage.php:324
#, php-format
msgid "%d match"
msgid_plural "%d matches"
@ -154,10 +272,6 @@ msgstr[1] "%d coincidències"
msgid "scanned %s"
msgstr "explorat el %s"
#: includes/Admin/AttachmentDetailPage.php:372 includes/Admin/AuditPage.php:565
msgid "Alert Domains"
msgstr "Dominis d'alerta"
#: includes/Admin/AttachmentDetailPage.php:373
msgid ""
"These domains are associated with copyright-protected content and may "
@ -168,21 +282,21 @@ msgstr ""
#: includes/Admin/AttachmentDetailPage.php:376
#: includes/Admin/AttachmentDetailPage.php:392
#: includes/Admin/AttachmentDetailPage.php:408 includes/Admin/AuditPage.php:371
#: includes/Admin/AttachmentDetailPage.php:408 includes/Admin/AuditPage.php:372
msgid "Domain"
msgstr "Domini"
#: includes/Admin/AttachmentDetailPage.php:377
#: includes/Admin/AttachmentDetailPage.php:393
#: includes/Admin/AttachmentDetailPage.php:409 includes/Admin/AuditPage.php:372
#: includes/Admin/AttachmentDetailPage.php:409 includes/Admin/AuditPage.php:373
msgid "Occurrences"
msgstr "Aparicions"
#: includes/Admin/AttachmentDetailPage.php:389 includes/Admin/AuditPage.php:566
#: includes/Admin/AttachmentDetailPage.php:389 includes/Admin/AuditPage.php:567
msgid "Other Domains"
msgstr "Altres dominis"
#: includes/Admin/AttachmentDetailPage.php:405 includes/Admin/AuditPage.php:567
#: includes/Admin/AttachmentDetailPage.php:405 includes/Admin/AuditPage.php:568
msgid "Ignored Domains"
msgstr "Dominis ignorats"
@ -267,247 +381,235 @@ msgstr "Similitud"
msgid "Labels"
msgstr "Etiquetes"
#: includes/Admin/AuditPage.php:116
#: includes/Admin/AuditPage.php:117
msgid "Loading…"
msgstr "S'està carregant…"
#: includes/Admin/AuditPage.php:117
#: includes/Admin/AuditPage.php:118
msgid "Error loading details."
msgstr "S'ha produït un error en carregar els detalls."
#: includes/Admin/AuditPage.php:118 includes/Admin/AuditPage.php:194
#: includes/Admin/AuditPage.php:119 includes/Admin/AuditPage.php:195
msgid "This image is not used in any post."
msgstr "Aquesta imatge no s'utilitza en cap entrada."
#: includes/Admin/AuditPage.php:119 includes/Admin/AuditPage.php:156
#: includes/Admin/AuditPage.php:120 includes/Admin/AuditPage.php:157
msgid "Usage Details"
msgstr "Detalls d'ús"
#: includes/Admin/AuditPage.php:142 includes/Core/Plugin.php:109
#: includes/Core/Plugin.php:110 includes/Core/Plugin.php:123
#: includes/Core/Plugin.php:124 includes/Privacy/DataEraser.php:33
#: includes/Admin/AuditPage.php:143 includes/Core/Plugin.php:118
#: includes/Core/Plugin.php:119 includes/Core/Plugin.php:132
#: includes/Core/Plugin.php:133 includes/Privacy/DataEraser.php:33
#: includes/Privacy/DataExporter.php:45
msgid "Media Audit"
msgstr "Auditoria de mitjans"
#: includes/Admin/AuditPage.php:148
#: includes/Admin/AuditPage.php:149
msgid "Search"
msgstr "Cerca"
#: includes/Admin/AuditPage.php:157
#: includes/Admin/AuditPage.php:158
msgid "Close"
msgstr "Tanca"
#: includes/Admin/AuditPage.php:175 includes/Admin/AuditPage.php:529
#: includes/Admin/AuditPage.php:776 includes/Admin/AuditPage.php:808
#: includes/Admin/AuditPage.php:176 includes/Admin/AuditPage.php:530
#: includes/Admin/AuditPage.php:806 includes/Admin/AuditPage.php:838
#: includes/Admin/ToolsPage.php:105 includes/Admin/ToolsPage.php:165
msgid "Insufficient permissions."
msgstr "Permisos insuficients."
#: includes/Admin/AuditPage.php:328
#: includes/Admin/AuditPage.php:329
msgid "No matches"
msgstr "Sense coincidències"
#: includes/Admin/AuditPage.php:381 includes/Admin/AuditPage.php:488
#: includes/Admin/MediaListTable.php:298 includes/Admin/MediaListTable.php:435
msgid "Alert"
msgstr "Alerta"
#: includes/Admin/AuditPage.php:403
#: includes/Admin/AuditPage.php:404
msgid "Consensus Domains"
msgstr "Dominis de consens"
#. translators: %d: number of providers that agree
#: includes/Admin/AuditPage.php:409
#: includes/Admin/AuditPage.php:410
#, php-format
msgid "%d provider"
msgid_plural "%d providers"
msgstr[0] "%d proveïdor"
msgstr[1] "%d proveïdors"
#: includes/Admin/AuditPage.php:419
#: includes/Admin/AuditPage.php:420
msgid "View full report →"
msgstr "Veure l'informe complet →"
#: includes/Admin/AuditPage.php:445
#: includes/Admin/AuditPage.php:446
msgid "In Index"
msgstr "A l'índex"
#. translators: %d: count of images not yet indexed
#: includes/Admin/AuditPage.php:449
#: includes/Admin/AuditPage.php:450
#, php-format
msgid "%d not yet indexed"
msgstr "%d encara no indexades"
#: includes/Admin/AuditPage.php:452
#: includes/Admin/AuditPage.php:453
msgid "All indexed"
msgstr "Totes indexades"
#: includes/Admin/AuditPage.php:457 includes/Admin/MediaListTable.php:329
#: includes/Admin/AuditPage.php:458 includes/Admin/MediaListTable.php:346
msgid "Scanned"
msgstr "Explorades"
#. translators: %d: percentage
#: includes/Admin/AuditPage.php:460
#: includes/Admin/AuditPage.php:461
#, php-format
msgid "%d%% of index"
msgstr "%d%% de l'índex"
#: includes/Admin/AuditPage.php:467
#: includes/Admin/AuditPage.php:468
msgid "Used"
msgstr "Usades"
#: includes/Admin/AuditPage.php:473 includes/Admin/MediaListTable.php:211
#: includes/Admin/AuditPage.php:474 includes/Admin/MediaListTable.php:212
msgid "Unused"
msgstr "No usades"
#: includes/Admin/AuditPage.php:480
#: includes/Admin/AuditPage.php:481
msgid "External Matches"
msgstr "Coincidències externes"
#: includes/Admin/AuditPage.php:543
#: includes/Admin/AuditPage.php:544
msgid "Could not open output stream."
msgstr "No s'ha pogut obrir el flux de sortida."
#: includes/Admin/AuditPage.php:552 includes/Privacy/DataExporter.php:257
#: includes/Admin/AuditPage.php:553 includes/Privacy/DataExporter.php:257
#: includes/Privacy/DataExporter.php:299
msgid "Attachment ID"
msgstr "ID del fitxer adjunt"
#: includes/Admin/AuditPage.php:556
#: includes/Admin/AuditPage.php:557
msgid "File Size (bytes)"
msgstr "Mida del fitxer (bytes)"
#: includes/Admin/AuditPage.php:557
#: includes/Admin/AuditPage.php:558
msgid "Internal Scan Date"
msgstr "Data de l'escaneig intern"
#: includes/Admin/AuditPage.php:559
#: includes/Admin/AuditPage.php:560
msgid "Has Alert"
msgstr "Té alerta"
#: includes/Admin/AuditPage.php:560 includes/Admin/MediaListTable.php:57
#: includes/Admin/AuditPage.php:561 includes/Admin/MediaListTable.php:58
msgid "Usage Count"
msgstr "Nombre d'usos"
#: includes/Admin/AuditPage.php:561
#: includes/Admin/AuditPage.php:562
msgid "Used In"
msgstr "Usat a"
#: includes/Admin/AuditPage.php:562
#: includes/Admin/AuditPage.php:563
msgid "Google Vision — Matches"
msgstr "Google Vision — Coincidències"
#: includes/Admin/AuditPage.php:563
#: includes/Admin/AuditPage.php:564
msgid "TinEye — Matches"
msgstr "TinEye — Coincidències"
#: includes/Admin/AuditPage.php:564
#: includes/Admin/AuditPage.php:565
msgid "PicDefense — Matches"
msgstr "PicDefense — Coincidències"
#: includes/Admin/AuditPage.php:748
#: includes/Admin/AuditPage.php:570
msgid "Dismissed Notes"
msgstr "Notes de descart"
#: includes/Admin/AuditPage.php:776 includes/Admin/AuditPage.php:788
msgid "Yes"
msgstr "Sí"
#: includes/Admin/AuditPage.php:748
#: includes/Admin/AuditPage.php:776 includes/Admin/AuditPage.php:788
msgid "No"
msgstr "No"
#: includes/Admin/MediaListTable.php:54
msgid "Thumbnail"
msgstr "Miniatura"
#: includes/Admin/MediaListTable.php:58
#: includes/Admin/MediaListTable.php:59
msgid "Usages"
msgstr "Usos"
#: includes/Admin/MediaListTable.php:60
#: includes/Admin/MediaListTable.php:61
msgid "Last Scanned"
msgstr "Darrera exploració"
#: includes/Admin/MediaListTable.php:84
#: includes/Admin/MediaListTable.php:85
msgid "Run External Scan"
msgstr "Executar exploració externa"
#: includes/Admin/MediaListTable.php:85
#: includes/Admin/MediaListTable.php:86
msgid "Purge External Data"
msgstr "Eliminar dades externes"
#: includes/Admin/MediaListTable.php:86
#: includes/Admin/MediaListTable.php:87
msgid "Export CSV"
msgstr "Exportar CSV"
#: includes/Admin/MediaListTable.php:87
#: includes/Admin/MediaListTable.php:88
msgid "Export CSV (Alerts only)"
msgstr "Exportar CSV (només alertes)"
#: includes/Admin/MediaListTable.php:171
msgid "Edit"
msgstr "Edita"
#: includes/Admin/MediaListTable.php:176
#: includes/Admin/MediaListTable.php:177
msgid "View Details"
msgstr "Visualitza els detalls"
#: includes/Admin/MediaListTable.php:181
msgid "Full Report"
msgstr "Informe complet"
#: includes/Admin/MediaListTable.php:247
#: includes/Admin/MediaListTable.php:248
msgid "(no title)"
msgstr "(sense títol)"
#. translators: %d: number of additional usages
#: includes/Admin/MediaListTable.php:262
#: includes/Admin/MediaListTable.php:263
#, php-format
msgid "+ %d more…"
msgstr "+ %d més…"
#: includes/Admin/MediaListTable.php:320 includes/Admin/MediaListTable.php:359
#: includes/Admin/MediaListTable.php:307 includes/Admin/MediaListTable.php:337
#: includes/Admin/MediaListTable.php:376
msgid "View Results"
msgstr "Visualitza els resultats"
#: includes/Admin/MediaListTable.php:327 includes/Admin/ToolsPage.php:589
#: includes/Admin/MediaListTable.php:344 includes/Admin/ToolsPage.php:589
#: includes/Admin/ToolsPage.php:590 includes/Admin/ToolsPage.php:591
msgid "Pending"
msgstr "Pendent"
#: includes/Admin/MediaListTable.php:328
#: includes/Admin/MediaListTable.php:345
msgid "Queued"
msgstr "En cua"
#: includes/Admin/MediaListTable.php:330
#: includes/Admin/MediaListTable.php:347
msgid "Matches Found"
msgstr "Coincidències trobades"
#: includes/Admin/MediaListTable.php:331
#: includes/Admin/MediaListTable.php:348
msgid "Error"
msgstr "Error"
#. translators: %s: human-readable time difference, e.g. "3 days"
#: includes/Admin/MediaListTable.php:401
#: includes/Admin/MediaListTable.php:418
#, php-format
msgid "%s ago"
msgstr "fa %s"
#: includes/Admin/MediaListTable.php:431
#: includes/Admin/MediaListTable.php:448
msgid "All statuses"
msgstr "Tots els estats"
#: includes/Admin/MediaListTable.php:450
#: includes/Admin/MediaListTable.php:467
msgid "All post types"
msgstr "Tots els tipus d'entrada"
#: includes/Admin/MediaListTable.php:465
#: includes/Admin/MediaListTable.php:482
msgid "Unused only"
msgstr "Només no usades"
#: includes/Admin/MediaListTable.php:468
#: includes/Admin/MediaListTable.php:485
msgid "Filter"
msgstr "Filtra"
#: includes/Admin/MediaListTable.php:478
#: includes/Admin/MediaListTable.php:495
msgid ""
"No indexed attachments found. Run wp mra scan-internal to populate the index."
msgstr ""
@ -797,10 +899,6 @@ msgstr "Dades d'exploració externa eliminades."
msgid "All data reset. Fresh indexing scheduled."
msgstr "Totes les dades restablertes. Nova indexació programada."
#: includes/Admin/ToolsPage.php:376
msgid "Operation completed."
msgstr "Operació completada."
#: includes/Admin/ToolsPage.php:420
msgid "Database schema"
msgstr "Esquema de base de dades"
@ -819,7 +917,7 @@ msgstr "Instal·lat: %1$s — Requerit: %2$s"
#: includes/Admin/ToolsPage.php:441
msgid "Deactivate and reactivate the plugin to apply pending migrations."
msgstr ""
msgstr "Desactiva i reactiva el plugin per aplicar les migracions pendents."
"Desactiveu i reactiveu el connector per aplicar les migracions pendents."
#: includes/Admin/ToolsPage.php:448
@ -1207,15 +1305,15 @@ msgstr "S'estan executant les exploracions externes…"
msgid "External scan complete. %d attachments processed."
msgstr "Exploració externa completada. %d fitxers adjunts processats."
#: includes/Core/Plugin.php:132 includes/Core/Plugin.php:133
#: includes/Core/Plugin.php:154 includes/Core/Plugin.php:155
msgid "Tools"
msgstr "Eines"
#: includes/Core/Plugin.php:145 includes/Core/Plugin.php:146
#: includes/Core/Plugin.php:167 includes/Core/Plugin.php:168
msgid "Settings"
msgstr "Configuració"
#: includes/Core/Plugin.php:154
#: includes/Core/Plugin.php:176
msgid "Attachment Report"
msgstr "Informe del fitxer adjunt"

View file

@ -2,10 +2,10 @@
# This file is distributed under the GPL-3.0-or-later.
msgid ""
msgstr ""
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.6.0\n"
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.7.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-"
"mediaaudit\n"
"POT-Creation-Date: 2026-05-05T10:39:07+00:00\n"
"POT-Creation-Date: 2026-05-11T07:13:58+00:00\n"
"PO-Revision-Date: 2026-05-01 07:41+0000\n"
"Last-Translator: Javier Casares <javier@casares.org>\n"
"Language-Team: Spanish (Spain) <es@li.org>\n"
@ -45,13 +45,136 @@ msgstr ""
msgid "https://www.robotstxt.es/"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:40 includes/Admin/AuditPage.php:135
#: includes/Admin/Settings.php:898 includes/Admin/ToolsPage.php:253
#: includes/Admin/AlertsPage.php:210
msgid "You do not have permission to perform this action."
msgstr "No tienes permiso para realizar esta acción."
#: includes/Admin/AlertsPage.php:263 includes/Admin/AttachmentDetailPage.php:40
#: includes/Admin/AuditPage.php:136 includes/Admin/Settings.php:898
#: includes/Admin/ToolsPage.php:253
msgid "You do not have permission to access this page."
msgstr "No tienes permiso para acceder a esta página."
#: includes/Admin/AlertsPage.php:280 includes/Core/Plugin.php:141
#: includes/Core/Plugin.php:142
msgid "Alerts"
msgstr "Alertas"
#. translators: %d: count of active alerts
#: includes/Admin/AlertsPage.php:292
#, php-format
msgid "Active Alerts (%d)"
msgstr "Alertas activas (%d)"
#. translators: %d: count of dismissed alerts
#: includes/Admin/AlertsPage.php:304
#, php-format
msgid "Dismissed Alerts (%d)"
msgstr "Alertas descartadas (%d)"
#: includes/Admin/AlertsPage.php:376
msgid "Alert dismissed successfully."
msgstr "Alerta descartada correctamente."
#: includes/Admin/AlertsPage.php:377
msgid "Alert reactivated successfully."
msgstr "Alerta reactivada correctamente."
#: includes/Admin/AlertsPage.php:378
msgid "An error occurred. Please try again."
msgstr "Se ha producido un error. Por favor, inténtalo de nuevo."
#: includes/Admin/AlertsPage.php:382 includes/Admin/ToolsPage.php:376
msgid "Operation completed."
msgstr "Operación completada."
#: includes/Admin/AlertsPage.php:402
msgid "No active alerts found."
msgstr "No se encontraron alertas activas."
#: includes/Admin/AlertsPage.php:409 includes/Admin/AlertsPage.php:541
#: includes/Admin/MediaListTable.php:55
msgid "Thumbnail"
msgstr "Miniatura"
#: includes/Admin/AlertsPage.php:410 includes/Admin/AlertsPage.php:542
#: includes/Admin/AttachmentDetailPage.php:87 includes/Admin/AuditPage.php:554
#: includes/Admin/MediaListTable.php:56 includes/Privacy/DataExporter.php:261
msgid "Filename"
msgstr "Nombre de archivo"
#: includes/Admin/AlertsPage.php:411 includes/Admin/AlertsPage.php:543
#: includes/Admin/AttachmentDetailPage.php:372 includes/Admin/AuditPage.php:566
msgid "Alert Domains"
msgstr "Dominios de alerta"
#: includes/Admin/AlertsPage.php:412
msgid "Usage"
msgstr "Usos"
#: includes/Admin/AlertsPage.php:413 includes/Admin/AlertsPage.php:547
msgid "Actions"
msgstr "Acciones"
#: includes/Admin/AlertsPage.php:447 includes/Admin/AlertsPage.php:587
#: includes/Admin/MediaListTable.php:172
msgid "Edit"
msgstr "Editar"
#: includes/Admin/AlertsPage.php:449 includes/Admin/AlertsPage.php:589
#: includes/Admin/MediaListTable.php:182
msgid "Full Report"
msgstr "Informe completo"
#: includes/Admin/AlertsPage.php:459 includes/Admin/AuditPage.php:382
#: includes/Admin/AuditPage.php:489 includes/Admin/MediaListTable.php:315
#: includes/Admin/MediaListTable.php:452
msgid "Alert"
msgstr "Alerta"
#: includes/Admin/AlertsPage.php:473
msgid "Dismiss"
msgstr "Descartar"
#: includes/Admin/AlertsPage.php:485
msgid "Notes (optional):"
msgstr "Notas (opcional):"
#: includes/Admin/AlertsPage.php:495
msgid "Confirm Dismiss"
msgstr "Confirmar descarte"
#: includes/Admin/AlertsPage.php:496
msgid "Cancel"
msgstr "Cancelar"
#: includes/Admin/AlertsPage.php:534
msgid "No dismissed alerts."
msgstr "No hay alertas descartadas."
#: includes/Admin/AlertsPage.php:544
msgid "Notes"
msgstr "Notas"
#: includes/Admin/AlertsPage.php:545
msgid "Dismissed By"
msgstr "Descartada por"
#: includes/Admin/AlertsPage.php:546
msgid "Dismissed At"
msgstr "Descartada el"
#: includes/Admin/AlertsPage.php:599 includes/Admin/AuditPage.php:569
#: includes/Admin/MediaListTable.php:302
msgid "Dismissed"
msgstr "Descartada"
#: includes/Admin/AlertsPage.php:616
msgid "Reactivate"
msgstr "Reactivar"
#: includes/Admin/AttachmentDetailPage.php:51
#: includes/Admin/AttachmentDetailPage.php:56 includes/Admin/AuditPage.php:180
#: includes/Admin/AttachmentDetailPage.php:56 includes/Admin/AuditPage.php:181
msgid "Invalid attachment ID."
msgstr "ID de adjunto no válido."
@ -64,21 +187,16 @@ msgid "File Information"
msgstr "Información del archivo"
#: includes/Admin/AttachmentDetailPage.php:81
#: includes/Admin/MediaListTable.php:56
#: includes/Admin/MediaListTable.php:57
msgid "ID"
msgstr "ID"
#: includes/Admin/AttachmentDetailPage.php:87 includes/Admin/AuditPage.php:553
#: includes/Admin/MediaListTable.php:55 includes/Privacy/DataExporter.php:261
msgid "Filename"
msgstr "Nombre de archivo"
#: includes/Admin/AttachmentDetailPage.php:94 includes/Admin/AuditPage.php:554
#: includes/Admin/AttachmentDetailPage.php:94 includes/Admin/AuditPage.php:555
#: includes/Privacy/DataExporter.php:265
msgid "File URL"
msgstr "URL del archivo"
#: includes/Admin/AttachmentDetailPage.php:102 includes/Admin/AuditPage.php:555
#: includes/Admin/AttachmentDetailPage.php:102 includes/Admin/AuditPage.php:556
msgid "MIME Type"
msgstr "Tipo MIME"
@ -90,24 +208,24 @@ msgstr "Tamaño del archivo"
msgid "Internal scan date"
msgstr "Fecha del escaneo interno"
#: includes/Admin/AttachmentDetailPage.php:124 includes/Admin/AuditPage.php:558
#: includes/Admin/MediaListTable.php:59
#: includes/Admin/AttachmentDetailPage.php:124 includes/Admin/AuditPage.php:559
#: includes/Admin/MediaListTable.php:60
msgid "External Status"
msgstr "Estado externo"
#: includes/Admin/AttachmentDetailPage.php:139 includes/Admin/AuditPage.php:244
#: includes/Admin/AttachmentDetailPage.php:139 includes/Admin/AuditPage.php:245
msgid "Internal Usage"
msgstr "Uso interno"
#: includes/Admin/AttachmentDetailPage.php:144 includes/Admin/AuditPage.php:188
#: includes/Admin/AttachmentDetailPage.php:144 includes/Admin/AuditPage.php:189
msgid "Featured Image"
msgstr "Imagen destacada"
#: includes/Admin/AttachmentDetailPage.php:145 includes/Admin/AuditPage.php:189
#: includes/Admin/AttachmentDetailPage.php:145 includes/Admin/AuditPage.php:190
msgid "Post Content"
msgstr "Contenido de la entrada"
#: includes/Admin/AttachmentDetailPage.php:146 includes/Admin/AuditPage.php:190
#: includes/Admin/AttachmentDetailPage.php:146 includes/Admin/AuditPage.php:191
msgid "Custom Field"
msgstr "Campo personalizado"
@ -115,24 +233,24 @@ msgstr "Campo personalizado"
msgid "Not used in any post."
msgstr "Este archivo no se usa en ninguna entrada."
#: includes/Admin/AttachmentDetailPage.php:154 includes/Admin/AuditPage.php:198
#: includes/Admin/AttachmentDetailPage.php:154 includes/Admin/AuditPage.php:199
msgid "Post"
msgstr "Entrada"
#: includes/Admin/AttachmentDetailPage.php:155 includes/Admin/AuditPage.php:199
#: includes/Admin/AttachmentDetailPage.php:155 includes/Admin/AuditPage.php:200
msgid "Type"
msgstr "Tipo"
#: includes/Admin/AttachmentDetailPage.php:156 includes/Admin/AuditPage.php:200
#: includes/Admin/AttachmentDetailPage.php:156 includes/Admin/AuditPage.php:201
msgid "Context"
msgstr "Contexto"
#: includes/Admin/AttachmentDetailPage.php:157 includes/Admin/AuditPage.php:201
#: includes/Admin/AuditPage.php:373
#: includes/Admin/AttachmentDetailPage.php:157 includes/Admin/AuditPage.php:202
#: includes/Admin/AuditPage.php:374
msgid "Status"
msgstr "Estado"
#: includes/Admin/AttachmentDetailPage.php:198 includes/Admin/AuditPage.php:293
#: includes/Admin/AttachmentDetailPage.php:198 includes/Admin/AuditPage.php:294
msgid "External Scan Results"
msgstr "Resultados del escaneo externo"
@ -141,7 +259,7 @@ msgid "No external scan data available."
msgstr "No hay datos de escaneo externo disponibles."
#. translators: %d: number of external matches
#: includes/Admin/AttachmentDetailPage.php:313 includes/Admin/AuditPage.php:323
#: includes/Admin/AttachmentDetailPage.php:313 includes/Admin/AuditPage.php:324
#, php-format
msgid "%d match"
msgid_plural "%d matches"
@ -154,10 +272,6 @@ msgstr[1] "%d coincidencias"
msgid "scanned %s"
msgstr "escaneado el %s"
#: includes/Admin/AttachmentDetailPage.php:372 includes/Admin/AuditPage.php:565
msgid "Alert Domains"
msgstr "Dominios de alerta"
#: includes/Admin/AttachmentDetailPage.php:373
msgid ""
"These domains are associated with copyright-protected content and may "
@ -168,21 +282,21 @@ msgstr ""
#: includes/Admin/AttachmentDetailPage.php:376
#: includes/Admin/AttachmentDetailPage.php:392
#: includes/Admin/AttachmentDetailPage.php:408 includes/Admin/AuditPage.php:371
#: includes/Admin/AttachmentDetailPage.php:408 includes/Admin/AuditPage.php:372
msgid "Domain"
msgstr "Dominio"
#: includes/Admin/AttachmentDetailPage.php:377
#: includes/Admin/AttachmentDetailPage.php:393
#: includes/Admin/AttachmentDetailPage.php:409 includes/Admin/AuditPage.php:372
#: includes/Admin/AttachmentDetailPage.php:409 includes/Admin/AuditPage.php:373
msgid "Occurrences"
msgstr "Apariciones"
#: includes/Admin/AttachmentDetailPage.php:389 includes/Admin/AuditPage.php:566
#: includes/Admin/AttachmentDetailPage.php:389 includes/Admin/AuditPage.php:567
msgid "Other Domains"
msgstr "Otros dominios"
#: includes/Admin/AttachmentDetailPage.php:405 includes/Admin/AuditPage.php:567
#: includes/Admin/AttachmentDetailPage.php:405 includes/Admin/AuditPage.php:568
msgid "Ignored Domains"
msgstr "Dominios ignorados"
@ -267,247 +381,235 @@ msgstr "Similitud"
msgid "Labels"
msgstr "Etiquetas"
#: includes/Admin/AuditPage.php:116
#: includes/Admin/AuditPage.php:117
msgid "Loading…"
msgstr "Cargando…"
#: includes/Admin/AuditPage.php:117
#: includes/Admin/AuditPage.php:118
msgid "Error loading details."
msgstr "Error al cargar los detalles."
#: includes/Admin/AuditPage.php:118 includes/Admin/AuditPage.php:194
#: includes/Admin/AuditPage.php:119 includes/Admin/AuditPage.php:195
msgid "This image is not used in any post."
msgstr "Esta imagen no se usa en ninguna entrada."
#: includes/Admin/AuditPage.php:119 includes/Admin/AuditPage.php:156
#: includes/Admin/AuditPage.php:120 includes/Admin/AuditPage.php:157
msgid "Usage Details"
msgstr "Detalles de uso"
#: includes/Admin/AuditPage.php:142 includes/Core/Plugin.php:109
#: includes/Core/Plugin.php:110 includes/Core/Plugin.php:123
#: includes/Core/Plugin.php:124 includes/Privacy/DataEraser.php:33
#: includes/Admin/AuditPage.php:143 includes/Core/Plugin.php:118
#: includes/Core/Plugin.php:119 includes/Core/Plugin.php:132
#: includes/Core/Plugin.php:133 includes/Privacy/DataEraser.php:33
#: includes/Privacy/DataExporter.php:45
msgid "Media Audit"
msgstr "Auditoría de medios"
#: includes/Admin/AuditPage.php:148
#: includes/Admin/AuditPage.php:149
msgid "Search"
msgstr "Buscar"
#: includes/Admin/AuditPage.php:157
#: includes/Admin/AuditPage.php:158
msgid "Close"
msgstr "Cerrar"
#: includes/Admin/AuditPage.php:175 includes/Admin/AuditPage.php:529
#: includes/Admin/AuditPage.php:776 includes/Admin/AuditPage.php:808
#: includes/Admin/AuditPage.php:176 includes/Admin/AuditPage.php:530
#: includes/Admin/AuditPage.php:806 includes/Admin/AuditPage.php:838
#: includes/Admin/ToolsPage.php:105 includes/Admin/ToolsPage.php:165
msgid "Insufficient permissions."
msgstr "Permisos insuficientes."
#: includes/Admin/AuditPage.php:328
#: includes/Admin/AuditPage.php:329
msgid "No matches"
msgstr "Sin coincidencias"
#: includes/Admin/AuditPage.php:381 includes/Admin/AuditPage.php:488
#: includes/Admin/MediaListTable.php:298 includes/Admin/MediaListTable.php:435
msgid "Alert"
msgstr "Alerta"
#: includes/Admin/AuditPage.php:403
#: includes/Admin/AuditPage.php:404
msgid "Consensus Domains"
msgstr "Dominios de consenso"
#. translators: %d: number of providers that agree
#: includes/Admin/AuditPage.php:409
#: includes/Admin/AuditPage.php:410
#, php-format
msgid "%d provider"
msgid_plural "%d providers"
msgstr[0] "%d proveedor"
msgstr[1] "%d proveedores"
#: includes/Admin/AuditPage.php:419
#: includes/Admin/AuditPage.php:420
msgid "View full report →"
msgstr "Ver informe completo →"
#: includes/Admin/AuditPage.php:445
#: includes/Admin/AuditPage.php:446
msgid "In Index"
msgstr "En el índice"
#. translators: %d: count of images not yet indexed
#: includes/Admin/AuditPage.php:449
#: includes/Admin/AuditPage.php:450
#, php-format
msgid "%d not yet indexed"
msgstr "%d aún no indexadas"
#: includes/Admin/AuditPage.php:452
#: includes/Admin/AuditPage.php:453
msgid "All indexed"
msgstr "Todas indexadas"
#: includes/Admin/AuditPage.php:457 includes/Admin/MediaListTable.php:329
#: includes/Admin/AuditPage.php:458 includes/Admin/MediaListTable.php:346
msgid "Scanned"
msgstr "Escaneadas"
#. translators: %d: percentage
#: includes/Admin/AuditPage.php:460
#: includes/Admin/AuditPage.php:461
#, php-format
msgid "%d%% of index"
msgstr "%d%% del índice"
#: includes/Admin/AuditPage.php:467
#: includes/Admin/AuditPage.php:468
msgid "Used"
msgstr "Usadas"
#: includes/Admin/AuditPage.php:473 includes/Admin/MediaListTable.php:211
#: includes/Admin/AuditPage.php:474 includes/Admin/MediaListTable.php:212
msgid "Unused"
msgstr "Sin usar"
#: includes/Admin/AuditPage.php:480
#: includes/Admin/AuditPage.php:481
msgid "External Matches"
msgstr "Coincidencias externas"
#: includes/Admin/AuditPage.php:543
#: includes/Admin/AuditPage.php:544
msgid "Could not open output stream."
msgstr "No se pudo abrir el flujo de salida."
#: includes/Admin/AuditPage.php:552 includes/Privacy/DataExporter.php:257
#: includes/Admin/AuditPage.php:553 includes/Privacy/DataExporter.php:257
#: includes/Privacy/DataExporter.php:299
msgid "Attachment ID"
msgstr "ID del adjunto"
#: includes/Admin/AuditPage.php:556
#: includes/Admin/AuditPage.php:557
msgid "File Size (bytes)"
msgstr "Tamaño del archivo (bytes)"
#: includes/Admin/AuditPage.php:557
#: includes/Admin/AuditPage.php:558
msgid "Internal Scan Date"
msgstr "Fecha del escaneo interno"
#: includes/Admin/AuditPage.php:559
#: includes/Admin/AuditPage.php:560
msgid "Has Alert"
msgstr "Tiene alerta"
#: includes/Admin/AuditPage.php:560 includes/Admin/MediaListTable.php:57
#: includes/Admin/AuditPage.php:561 includes/Admin/MediaListTable.php:58
msgid "Usage Count"
msgstr "Número de usos"
#: includes/Admin/AuditPage.php:561
#: includes/Admin/AuditPage.php:562
msgid "Used In"
msgstr "Usado en"
#: includes/Admin/AuditPage.php:562
#: includes/Admin/AuditPage.php:563
msgid "Google Vision — Matches"
msgstr "Google Vision — Coincidencias"
#: includes/Admin/AuditPage.php:563
#: includes/Admin/AuditPage.php:564
msgid "TinEye — Matches"
msgstr "TinEye — Coincidencias"
#: includes/Admin/AuditPage.php:564
#: includes/Admin/AuditPage.php:565
msgid "PicDefense — Matches"
msgstr "PicDefense — Coincidencias"
#: includes/Admin/AuditPage.php:748
#: includes/Admin/AuditPage.php:570
msgid "Dismissed Notes"
msgstr "Notas de descarte"
#: includes/Admin/AuditPage.php:776 includes/Admin/AuditPage.php:788
msgid "Yes"
msgstr "Sí"
#: includes/Admin/AuditPage.php:748
#: includes/Admin/AuditPage.php:776 includes/Admin/AuditPage.php:788
msgid "No"
msgstr "No"
#: includes/Admin/MediaListTable.php:54
msgid "Thumbnail"
msgstr "Miniatura"
#: includes/Admin/MediaListTable.php:58
#: includes/Admin/MediaListTable.php:59
msgid "Usages"
msgstr "Usos"
#: includes/Admin/MediaListTable.php:60
#: includes/Admin/MediaListTable.php:61
msgid "Last Scanned"
msgstr "Último escaneo"
#: includes/Admin/MediaListTable.php:84
#: includes/Admin/MediaListTable.php:85
msgid "Run External Scan"
msgstr "Ejecutar escaneo externo"
#: includes/Admin/MediaListTable.php:85
#: includes/Admin/MediaListTable.php:86
msgid "Purge External Data"
msgstr "Purgar datos externos"
#: includes/Admin/MediaListTable.php:86
#: includes/Admin/MediaListTable.php:87
msgid "Export CSV"
msgstr "Exportar CSV"
#: includes/Admin/MediaListTable.php:87
#: includes/Admin/MediaListTable.php:88
msgid "Export CSV (Alerts only)"
msgstr "Exportar CSV (solo alertas)"
#: includes/Admin/MediaListTable.php:171
msgid "Edit"
msgstr "Editar"
#: includes/Admin/MediaListTable.php:176
#: includes/Admin/MediaListTable.php:177
msgid "View Details"
msgstr "Ver detalles"
#: includes/Admin/MediaListTable.php:181
msgid "Full Report"
msgstr "Informe completo"
#: includes/Admin/MediaListTable.php:247
#: includes/Admin/MediaListTable.php:248
msgid "(no title)"
msgstr "(sin título)"
#. translators: %d: number of additional usages
#: includes/Admin/MediaListTable.php:262
#: includes/Admin/MediaListTable.php:263
#, php-format
msgid "+ %d more…"
msgstr "+ %d más…"
#: includes/Admin/MediaListTable.php:320 includes/Admin/MediaListTable.php:359
#: includes/Admin/MediaListTable.php:307 includes/Admin/MediaListTable.php:337
#: includes/Admin/MediaListTable.php:376
msgid "View Results"
msgstr "Ver resultados"
#: includes/Admin/MediaListTable.php:327 includes/Admin/ToolsPage.php:589
#: includes/Admin/MediaListTable.php:344 includes/Admin/ToolsPage.php:589
#: includes/Admin/ToolsPage.php:590 includes/Admin/ToolsPage.php:591
msgid "Pending"
msgstr "Pendiente"
#: includes/Admin/MediaListTable.php:328
#: includes/Admin/MediaListTable.php:345
msgid "Queued"
msgstr "En cola"
#: includes/Admin/MediaListTable.php:330
#: includes/Admin/MediaListTable.php:347
msgid "Matches Found"
msgstr "Coincidencias encontradas"
#: includes/Admin/MediaListTable.php:331
#: includes/Admin/MediaListTable.php:348
msgid "Error"
msgstr "Error"
#. translators: %s: human-readable time difference, e.g. "3 days"
#: includes/Admin/MediaListTable.php:401
#: includes/Admin/MediaListTable.php:418
#, php-format
msgid "%s ago"
msgstr "hace %s"
#: includes/Admin/MediaListTable.php:431
#: includes/Admin/MediaListTable.php:448
msgid "All statuses"
msgstr "Todos los estados"
#: includes/Admin/MediaListTable.php:450
#: includes/Admin/MediaListTable.php:467
msgid "All post types"
msgstr "Todos los tipos de entrada"
#: includes/Admin/MediaListTable.php:465
#: includes/Admin/MediaListTable.php:482
msgid "Unused only"
msgstr "Solo sin usar"
#: includes/Admin/MediaListTable.php:468
#: includes/Admin/MediaListTable.php:485
msgid "Filter"
msgstr "Filtrar"
#: includes/Admin/MediaListTable.php:478
#: includes/Admin/MediaListTable.php:495
msgid ""
"No indexed attachments found. Run wp mra scan-internal to populate the index."
msgstr ""
@ -799,10 +901,6 @@ msgstr "Datos de escaneo externo eliminados."
msgid "All data reset. Fresh indexing scheduled."
msgstr "Todos los datos restablecidos. Re-indexación programada."
#: includes/Admin/ToolsPage.php:376
msgid "Operation completed."
msgstr "Operación completada."
#: includes/Admin/ToolsPage.php:420
msgid "Database schema"
msgstr "Esquema de base de datos"
@ -821,7 +919,7 @@ msgstr "Instalado: %1$s — Requerido: %2$s"
#: includes/Admin/ToolsPage.php:441
msgid "Deactivate and reactivate the plugin to apply pending migrations."
msgstr ""
msgstr "Desactiva y reactiva el plugin para aplicar las migraciones pendientes."
"Desactiva y reactiva el plugin para aplicar las migraciones pendientes."
#: includes/Admin/ToolsPage.php:448
@ -1208,15 +1306,15 @@ msgstr "Ejecutando escaneos externos…"
msgid "External scan complete. %d attachments processed."
msgstr "Escaneo externo completo. %d adjuntos procesados."
#: includes/Core/Plugin.php:132 includes/Core/Plugin.php:133
#: includes/Core/Plugin.php:154 includes/Core/Plugin.php:155
msgid "Tools"
msgstr "Herramientas"
#: includes/Core/Plugin.php:145 includes/Core/Plugin.php:146
#: includes/Core/Plugin.php:167 includes/Core/Plugin.php:168
msgid "Settings"
msgstr "Ajustes"
#: includes/Core/Plugin.php:154
#: includes/Core/Plugin.php:176
msgid "Attachment Report"
msgstr "Informe del archivo adjunto"

View file

@ -2,14 +2,14 @@
# This file is distributed under the GPL-3.0-or-later.
msgid ""
msgstr ""
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.6.0\n"
"Project-Id-Version: Media Audit (by ROBOTSTXT) 1.7.0\n"
"Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/robotstxt-mediaaudit\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2026-05-05T10:39:07+00:00\n"
"POT-Creation-Date: 2026-05-11T07:13:58+00:00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"X-Generator: WP-CLI 2.12.0\n"
"X-Domain: robotstxt-mediaaudit\n"
@ -39,16 +39,153 @@ msgstr ""
msgid "https://www.robotstxt.es/"
msgstr ""
#: includes/Admin/AlertsPage.php:210
msgid "You do not have permission to perform this action."
msgstr ""
#: includes/Admin/AlertsPage.php:263
#: includes/Admin/AttachmentDetailPage.php:40
#: includes/Admin/AuditPage.php:135
#: includes/Admin/AuditPage.php:136
#: includes/Admin/Settings.php:898
#: includes/Admin/ToolsPage.php:253
msgid "You do not have permission to access this page."
msgstr ""
#: includes/Admin/AlertsPage.php:280
#: includes/Core/Plugin.php:141
#: includes/Core/Plugin.php:142
msgid "Alerts"
msgstr ""
#. translators: %d: count of active alerts
#: includes/Admin/AlertsPage.php:292
#, php-format
msgid "Active Alerts (%d)"
msgstr ""
#. translators: %d: count of dismissed alerts
#: includes/Admin/AlertsPage.php:304
#, php-format
msgid "Dismissed Alerts (%d)"
msgstr ""
#: includes/Admin/AlertsPage.php:376
msgid "Alert dismissed successfully."
msgstr ""
#: includes/Admin/AlertsPage.php:377
msgid "Alert reactivated successfully."
msgstr ""
#: includes/Admin/AlertsPage.php:378
msgid "An error occurred. Please try again."
msgstr ""
#: includes/Admin/AlertsPage.php:382
#: includes/Admin/ToolsPage.php:376
msgid "Operation completed."
msgstr ""
#: includes/Admin/AlertsPage.php:402
msgid "No active alerts found."
msgstr ""
#: includes/Admin/AlertsPage.php:409
#: includes/Admin/AlertsPage.php:541
#: includes/Admin/MediaListTable.php:55
msgid "Thumbnail"
msgstr ""
#: includes/Admin/AlertsPage.php:410
#: includes/Admin/AlertsPage.php:542
#: includes/Admin/AttachmentDetailPage.php:87
#: includes/Admin/AuditPage.php:554
#: includes/Admin/MediaListTable.php:56
#: includes/Privacy/DataExporter.php:261
msgid "Filename"
msgstr ""
#: includes/Admin/AlertsPage.php:411
#: includes/Admin/AlertsPage.php:543
#: includes/Admin/AttachmentDetailPage.php:372
#: includes/Admin/AuditPage.php:566
msgid "Alert Domains"
msgstr ""
#: includes/Admin/AlertsPage.php:412
msgid "Usage"
msgstr ""
#: includes/Admin/AlertsPage.php:413
#: includes/Admin/AlertsPage.php:547
msgid "Actions"
msgstr ""
#: includes/Admin/AlertsPage.php:447
#: includes/Admin/AlertsPage.php:587
#: includes/Admin/MediaListTable.php:172
msgid "Edit"
msgstr ""
#: includes/Admin/AlertsPage.php:449
#: includes/Admin/AlertsPage.php:589
#: includes/Admin/MediaListTable.php:182
msgid "Full Report"
msgstr ""
#: includes/Admin/AlertsPage.php:459
#: includes/Admin/AuditPage.php:382
#: includes/Admin/AuditPage.php:489
#: includes/Admin/MediaListTable.php:315
#: includes/Admin/MediaListTable.php:452
msgid "Alert"
msgstr ""
#: includes/Admin/AlertsPage.php:473
msgid "Dismiss"
msgstr ""
#: includes/Admin/AlertsPage.php:485
msgid "Notes (optional):"
msgstr ""
#: includes/Admin/AlertsPage.php:495
msgid "Confirm Dismiss"
msgstr ""
#: includes/Admin/AlertsPage.php:496
msgid "Cancel"
msgstr ""
#: includes/Admin/AlertsPage.php:534
msgid "No dismissed alerts."
msgstr ""
#: includes/Admin/AlertsPage.php:544
msgid "Notes"
msgstr ""
#: includes/Admin/AlertsPage.php:545
msgid "Dismissed By"
msgstr ""
#: includes/Admin/AlertsPage.php:546
msgid "Dismissed At"
msgstr ""
#: includes/Admin/AlertsPage.php:599
#: includes/Admin/AuditPage.php:569
#: includes/Admin/MediaListTable.php:302
msgid "Dismissed"
msgstr ""
#: includes/Admin/AlertsPage.php:616
msgid "Reactivate"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:51
#: includes/Admin/AttachmentDetailPage.php:56
#: includes/Admin/AuditPage.php:180
#: includes/Admin/AuditPage.php:181
msgid "Invalid attachment ID."
msgstr ""
@ -61,25 +198,18 @@ msgid "File Information"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:81
#: includes/Admin/MediaListTable.php:56
#: includes/Admin/MediaListTable.php:57
msgid "ID"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:87
#: includes/Admin/AuditPage.php:553
#: includes/Admin/MediaListTable.php:55
#: includes/Privacy/DataExporter.php:261
msgid "Filename"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:94
#: includes/Admin/AuditPage.php:554
#: includes/Admin/AuditPage.php:555
#: includes/Privacy/DataExporter.php:265
msgid "File URL"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:102
#: includes/Admin/AuditPage.php:555
#: includes/Admin/AuditPage.php:556
msgid "MIME Type"
msgstr ""
@ -92,28 +222,28 @@ msgid "Internal scan date"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:124
#: includes/Admin/AuditPage.php:558
#: includes/Admin/MediaListTable.php:59
#: includes/Admin/AuditPage.php:559
#: includes/Admin/MediaListTable.php:60
msgid "External Status"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:139
#: includes/Admin/AuditPage.php:244
#: includes/Admin/AuditPage.php:245
msgid "Internal Usage"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:144
#: includes/Admin/AuditPage.php:188
#: includes/Admin/AuditPage.php:189
msgid "Featured Image"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:145
#: includes/Admin/AuditPage.php:189
#: includes/Admin/AuditPage.php:190
msgid "Post Content"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:146
#: includes/Admin/AuditPage.php:190
#: includes/Admin/AuditPage.php:191
msgid "Custom Field"
msgstr ""
@ -122,28 +252,28 @@ msgid "Not used in any post."
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:154
#: includes/Admin/AuditPage.php:198
#: includes/Admin/AuditPage.php:199
msgid "Post"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:155
#: includes/Admin/AuditPage.php:199
#: includes/Admin/AuditPage.php:200
msgid "Type"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:156
#: includes/Admin/AuditPage.php:200
#: includes/Admin/AuditPage.php:201
msgid "Context"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:157
#: includes/Admin/AuditPage.php:201
#: includes/Admin/AuditPage.php:373
#: includes/Admin/AuditPage.php:202
#: includes/Admin/AuditPage.php:374
msgid "Status"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:198
#: includes/Admin/AuditPage.php:293
#: includes/Admin/AuditPage.php:294
msgid "External Scan Results"
msgstr ""
@ -153,7 +283,7 @@ msgstr ""
#. translators: %d: number of external matches
#: includes/Admin/AttachmentDetailPage.php:313
#: includes/Admin/AuditPage.php:323
#: includes/Admin/AuditPage.php:324
#, php-format
msgid "%d match"
msgid_plural "%d matches"
@ -166,11 +296,6 @@ msgstr[1] ""
msgid "scanned %s"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:372
#: includes/Admin/AuditPage.php:565
msgid "Alert Domains"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:373
msgid "These domains are associated with copyright-protected content and may indicate a copyright risk."
msgstr ""
@ -178,24 +303,24 @@ msgstr ""
#: includes/Admin/AttachmentDetailPage.php:376
#: includes/Admin/AttachmentDetailPage.php:392
#: includes/Admin/AttachmentDetailPage.php:408
#: includes/Admin/AuditPage.php:371
#: includes/Admin/AuditPage.php:372
msgid "Domain"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:377
#: includes/Admin/AttachmentDetailPage.php:393
#: includes/Admin/AttachmentDetailPage.php:409
#: includes/Admin/AuditPage.php:372
#: includes/Admin/AuditPage.php:373
msgid "Occurrences"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:389
#: includes/Admin/AuditPage.php:566
#: includes/Admin/AuditPage.php:567
msgid "Other Domains"
msgstr ""
#: includes/Admin/AttachmentDetailPage.php:405
#: includes/Admin/AuditPage.php:567
#: includes/Admin/AuditPage.php:568
msgid "Ignored Domains"
msgstr ""
@ -278,264 +403,252 @@ msgstr ""
msgid "Labels"
msgstr ""
#: includes/Admin/AuditPage.php:116
#: includes/Admin/AuditPage.php:117
msgid "Loading…"
msgstr ""
#: includes/Admin/AuditPage.php:117
#: includes/Admin/AuditPage.php:118
msgid "Error loading details."
msgstr ""
#: includes/Admin/AuditPage.php:118
#: includes/Admin/AuditPage.php:194
#: includes/Admin/AuditPage.php:119
#: includes/Admin/AuditPage.php:195
msgid "This image is not used in any post."
msgstr ""
#: includes/Admin/AuditPage.php:119
#: includes/Admin/AuditPage.php:156
#: includes/Admin/AuditPage.php:120
#: includes/Admin/AuditPage.php:157
msgid "Usage Details"
msgstr ""
#: includes/Admin/AuditPage.php:142
#: includes/Core/Plugin.php:109
#: includes/Core/Plugin.php:110
#: includes/Core/Plugin.php:123
#: includes/Core/Plugin.php:124
#: includes/Admin/AuditPage.php:143
#: includes/Core/Plugin.php:118
#: includes/Core/Plugin.php:119
#: includes/Core/Plugin.php:132
#: includes/Core/Plugin.php:133
#: includes/Privacy/DataEraser.php:33
#: includes/Privacy/DataExporter.php:45
msgid "Media Audit"
msgstr ""
#: includes/Admin/AuditPage.php:148
#: includes/Admin/AuditPage.php:149
msgid "Search"
msgstr ""
#: includes/Admin/AuditPage.php:157
#: includes/Admin/AuditPage.php:158
msgid "Close"
msgstr ""
#: includes/Admin/AuditPage.php:175
#: includes/Admin/AuditPage.php:529
#: includes/Admin/AuditPage.php:776
#: includes/Admin/AuditPage.php:808
#: includes/Admin/AuditPage.php:176
#: includes/Admin/AuditPage.php:530
#: includes/Admin/AuditPage.php:806
#: includes/Admin/AuditPage.php:838
#: includes/Admin/ToolsPage.php:105
#: includes/Admin/ToolsPage.php:165
msgid "Insufficient permissions."
msgstr ""
#: includes/Admin/AuditPage.php:328
#: includes/Admin/AuditPage.php:329
msgid "No matches"
msgstr ""
#: includes/Admin/AuditPage.php:381
#: includes/Admin/AuditPage.php:488
#: includes/Admin/MediaListTable.php:298
#: includes/Admin/MediaListTable.php:435
msgid "Alert"
msgstr ""
#: includes/Admin/AuditPage.php:403
#: includes/Admin/AuditPage.php:404
msgid "Consensus Domains"
msgstr ""
#. translators: %d: number of providers that agree
#: includes/Admin/AuditPage.php:409
#: includes/Admin/AuditPage.php:410
#, php-format
msgid "%d provider"
msgid_plural "%d providers"
msgstr[0] ""
msgstr[1] ""
#: includes/Admin/AuditPage.php:419
#: includes/Admin/AuditPage.php:420
msgid "View full report →"
msgstr ""
#: includes/Admin/AuditPage.php:445
#: includes/Admin/AuditPage.php:446
msgid "In Index"
msgstr ""
#. translators: %d: count of images not yet indexed
#: includes/Admin/AuditPage.php:449
#: includes/Admin/AuditPage.php:450
#, php-format
msgid "%d not yet indexed"
msgstr ""
#: includes/Admin/AuditPage.php:452
#: includes/Admin/AuditPage.php:453
msgid "All indexed"
msgstr ""
#: includes/Admin/AuditPage.php:457
#: includes/Admin/MediaListTable.php:329
#: includes/Admin/AuditPage.php:458
#: includes/Admin/MediaListTable.php:346
msgid "Scanned"
msgstr ""
#. translators: %d: percentage
#: includes/Admin/AuditPage.php:460
#: includes/Admin/AuditPage.php:461
#, php-format
msgid "%d%% of index"
msgstr ""
#: includes/Admin/AuditPage.php:467
#: includes/Admin/AuditPage.php:468
msgid "Used"
msgstr ""
#: includes/Admin/AuditPage.php:473
#: includes/Admin/MediaListTable.php:211
#: includes/Admin/AuditPage.php:474
#: includes/Admin/MediaListTable.php:212
msgid "Unused"
msgstr ""
#: includes/Admin/AuditPage.php:480
#: includes/Admin/AuditPage.php:481
msgid "External Matches"
msgstr ""
#: includes/Admin/AuditPage.php:543
#: includes/Admin/AuditPage.php:544
msgid "Could not open output stream."
msgstr ""
#: includes/Admin/AuditPage.php:552
#: includes/Admin/AuditPage.php:553
#: includes/Privacy/DataExporter.php:257
#: includes/Privacy/DataExporter.php:299
msgid "Attachment ID"
msgstr ""
#: includes/Admin/AuditPage.php:556
#: includes/Admin/AuditPage.php:557
msgid "File Size (bytes)"
msgstr ""
#: includes/Admin/AuditPage.php:557
#: includes/Admin/AuditPage.php:558
msgid "Internal Scan Date"
msgstr ""
#: includes/Admin/AuditPage.php:559
#: includes/Admin/AuditPage.php:560
msgid "Has Alert"
msgstr ""
#: includes/Admin/AuditPage.php:560
#: includes/Admin/MediaListTable.php:57
#: includes/Admin/AuditPage.php:561
#: includes/Admin/MediaListTable.php:58
msgid "Usage Count"
msgstr ""
#: includes/Admin/AuditPage.php:561
#: includes/Admin/AuditPage.php:562
msgid "Used In"
msgstr ""
#: includes/Admin/AuditPage.php:562
#: includes/Admin/AuditPage.php:563
msgid "Google Vision — Matches"
msgstr ""
#: includes/Admin/AuditPage.php:563
#: includes/Admin/AuditPage.php:564
msgid "TinEye — Matches"
msgstr ""
#: includes/Admin/AuditPage.php:564
#: includes/Admin/AuditPage.php:565
msgid "PicDefense — Matches"
msgstr ""
#: includes/Admin/AuditPage.php:748
#: includes/Admin/AuditPage.php:570
msgid "Dismissed Notes"
msgstr ""
#: includes/Admin/AuditPage.php:776
#: includes/Admin/AuditPage.php:788
msgid "Yes"
msgstr ""
#: includes/Admin/AuditPage.php:748
#: includes/Admin/AuditPage.php:776
#: includes/Admin/AuditPage.php:788
msgid "No"
msgstr ""
#: includes/Admin/MediaListTable.php:54
msgid "Thumbnail"
msgstr ""
#: includes/Admin/MediaListTable.php:58
#: includes/Admin/MediaListTable.php:59
msgid "Usages"
msgstr ""
#: includes/Admin/MediaListTable.php:60
#: includes/Admin/MediaListTable.php:61
msgid "Last Scanned"
msgstr ""
#: includes/Admin/MediaListTable.php:84
#: includes/Admin/MediaListTable.php:85
msgid "Run External Scan"
msgstr ""
#: includes/Admin/MediaListTable.php:85
#: includes/Admin/MediaListTable.php:86
msgid "Purge External Data"
msgstr ""
#: includes/Admin/MediaListTable.php:86
#: includes/Admin/MediaListTable.php:87
msgid "Export CSV"
msgstr ""
#: includes/Admin/MediaListTable.php:87
#: includes/Admin/MediaListTable.php:88
msgid "Export CSV (Alerts only)"
msgstr ""
#: includes/Admin/MediaListTable.php:171
msgid "Edit"
msgstr ""
#: includes/Admin/MediaListTable.php:176
#: includes/Admin/MediaListTable.php:177
msgid "View Details"
msgstr ""
#: includes/Admin/MediaListTable.php:181
msgid "Full Report"
msgstr ""
#: includes/Admin/MediaListTable.php:247
#: includes/Admin/MediaListTable.php:248
msgid "(no title)"
msgstr ""
#. translators: %d: number of additional usages
#: includes/Admin/MediaListTable.php:262
#: includes/Admin/MediaListTable.php:263
#, php-format
msgid "+ %d more…"
msgstr ""
#: includes/Admin/MediaListTable.php:320
#: includes/Admin/MediaListTable.php:359
#: includes/Admin/MediaListTable.php:307
#: includes/Admin/MediaListTable.php:337
#: includes/Admin/MediaListTable.php:376
msgid "View Results"
msgstr ""
#: includes/Admin/MediaListTable.php:327
#: includes/Admin/MediaListTable.php:344
#: includes/Admin/ToolsPage.php:589
#: includes/Admin/ToolsPage.php:590
#: includes/Admin/ToolsPage.php:591
msgid "Pending"
msgstr ""
#: includes/Admin/MediaListTable.php:328
#: includes/Admin/MediaListTable.php:345
msgid "Queued"
msgstr ""
#: includes/Admin/MediaListTable.php:330
#: includes/Admin/MediaListTable.php:347
msgid "Matches Found"
msgstr ""
#: includes/Admin/MediaListTable.php:331
#: includes/Admin/MediaListTable.php:348
msgid "Error"
msgstr ""
#. translators: %s: human-readable time difference, e.g. "3 days"
#: includes/Admin/MediaListTable.php:401
#: includes/Admin/MediaListTable.php:418
#, php-format
msgid "%s ago"
msgstr ""
#: includes/Admin/MediaListTable.php:431
#: includes/Admin/MediaListTable.php:448
msgid "All statuses"
msgstr ""
#: includes/Admin/MediaListTable.php:450
#: includes/Admin/MediaListTable.php:467
msgid "All post types"
msgstr ""
#: includes/Admin/MediaListTable.php:465
#: includes/Admin/MediaListTable.php:482
msgid "Unused only"
msgstr ""
#: includes/Admin/MediaListTable.php:468
#: includes/Admin/MediaListTable.php:485
msgid "Filter"
msgstr ""
#: includes/Admin/MediaListTable.php:478
#: includes/Admin/MediaListTable.php:495
msgid "No indexed attachments found. Run wp mra scan-internal to populate the index."
msgstr ""
@ -774,10 +887,6 @@ msgstr ""
msgid "All data reset. Fresh indexing scheduled."
msgstr ""
#: includes/Admin/ToolsPage.php:376
msgid "Operation completed."
msgstr ""
#: includes/Admin/ToolsPage.php:420
msgid "Database schema"
msgstr ""
@ -1098,17 +1207,17 @@ msgstr ""
msgid "External scan complete. %d attachments processed."
msgstr ""
#: includes/Core/Plugin.php:132
#: includes/Core/Plugin.php:133
#: includes/Core/Plugin.php:154
#: includes/Core/Plugin.php:155
msgid "Tools"
msgstr ""
#: includes/Core/Plugin.php:145
#: includes/Core/Plugin.php:146
#: includes/Core/Plugin.php:167
#: includes/Core/Plugin.php:168
msgid "Settings"
msgstr ""
#: includes/Core/Plugin.php:154
#: includes/Core/Plugin.php:176
msgid "Attachment Report"
msgstr ""

View file

@ -5,7 +5,7 @@ Requires at least: 6.8
Tested up to: 7.0
Requires PHP: 8.2
Requires Plugins: action-scheduler
Stable tag: 1.6.0
Stable tag: 1.7.0
License: GPL-3.0-or-later
License URI: https://www.gnu.org/licenses/gpl-3.0.txt
@ -21,6 +21,7 @@ Media Audit helps site owners and editors understand where their media files are
* **External reverse image search** — submits images to Google Cloud Vision (Web Detection) and TinEye Commercial API to find matching pages across the web.
* **Consensus detection** — surfaces domains independently confirmed by multiple providers, providing stronger copyright-risk signals.
* **Audit list** — filterable admin page showing each attachment's external scan status, alert classification, and top matching domains.
* **Alert management** — dedicated Alerts page to review active copyright-risk alerts and dismiss false positives with optional notes. Dismissed alerts are tracked separately and can be reactivated at any time.
* **WP-CLI support** — run or schedule scans from the command line.
* **GDPR compliance** — full WordPress privacy API integration for personal data export and erasure on request.
* **Async processing** — all scanning runs via Action Scheduler to avoid blocking web requests.

View file

@ -3,7 +3,7 @@
* Plugin Name: Media Audit (by ROBOTSTXT)
* 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.
* Version: 1.6.0
* Version: 1.7.0
* Requires at least: 6.8
* Tested up to: 7.0
* Requires PHP: 8.2
@ -23,8 +23,8 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
define( 'ROBOTSTXT_MEDIAAUDIT_VERSION', '1.6.0' );
define( 'ROBOTSTXT_MEDIAAUDIT_DB_VERSION', '1.1.0' );
define( 'ROBOTSTXT_MEDIAAUDIT_VERSION', '1.7.0' );
define( 'ROBOTSTXT_MEDIAAUDIT_DB_VERSION', '1.2.0' );
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_FILE', __FILE__ );
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_URL', plugin_dir_url( __FILE__ ) );

View file

@ -23,6 +23,7 @@ if ( ! $delete ) {
global $wpdb;
// Drop tables in reverse dependency order.
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_dismissed_alerts`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_provider_status`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_external_results`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_media_usage`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery

View file

@ -7,6 +7,7 @@ $baseDir = dirname($vendorDir);
return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'MediaRightsAudit\\Admin\\AlertsPage' => $baseDir . '/includes/Admin/AlertsPage.php',
'MediaRightsAudit\\Admin\\AttachmentDetailPage' => $baseDir . '/includes/Admin/AttachmentDetailPage.php',
'MediaRightsAudit\\Admin\\AuditPage' => $baseDir . '/includes/Admin/AuditPage.php',
'MediaRightsAudit\\Admin\\MediaListTable' => $baseDir . '/includes/Admin/MediaListTable.php',

View file

@ -22,6 +22,7 @@ class ComposerStaticInit957728ab3efa005f456e5f9df13a19d2
public static $classMap = array (
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'MediaRightsAudit\\Admin\\AlertsPage' => __DIR__ . '/../..' . '/includes/Admin/AlertsPage.php',
'MediaRightsAudit\\Admin\\AttachmentDetailPage' => __DIR__ . '/../..' . '/includes/Admin/AttachmentDetailPage.php',
'MediaRightsAudit\\Admin\\AuditPage' => __DIR__ . '/../..' . '/includes/Admin/AuditPage.php',
'MediaRightsAudit\\Admin\\MediaListTable' => __DIR__ . '/../..' . '/includes/Admin/MediaListTable.php',