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; color: #155724;
} }
.mra-badge-alert {
background: #f8d7da;
color: #721c24;
}
.mra-badge-dismissed {
background: #e8e8e8;
color: #50575e;
}
.mra-badge-match-count { .mra-badge-match-count {
background: #721c24; background: #721c24;
color: #fff; color: #fff;
@ -398,3 +408,55 @@
display: block; display: block;
margin-bottom: 6px; 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(); e.preventDefault();
openModal( $( this ).data( 'id' ) ); 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 ) ); } ( jQuery ) );

View file

@ -1,5 +1,41 @@
== Changelog == == 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 = = 1.6.0 =
_Release date: 2026-05-05_ _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; namespace MediaRightsAudit\Admin;
use MediaRightsAudit\Admin\AlertsPage;
use MediaRightsAudit\Admin\AttachmentDetailPage; use MediaRightsAudit\Admin\AttachmentDetailPage;
use MediaRightsAudit\External\ExternalScanner; use MediaRightsAudit\External\ExternalScanner;
use MediaRightsAudit\External\HostnameFilter; use MediaRightsAudit\External\HostnameFilter;
@ -131,7 +132,7 @@ class AuditPage {
* @return void * @return void
*/ */
public function render(): 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' ) ); 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 { public function ajax_usage_details(): void {
check_ajax_referer( 'mra_usage_details', 'nonce' ); 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' ) ) ); 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 { private function handle_export_csv( bool $alerts_only ): void {
check_admin_referer( 'bulk-mra-attachments' ); 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' ) ); wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
} }
@ -565,6 +566,8 @@ class AuditPage {
__( 'Alert Domains', 'robotstxt-mediaaudit' ), __( 'Alert Domains', 'robotstxt-mediaaudit' ),
__( 'Other Domains', 'robotstxt-mediaaudit' ), __( 'Other Domains', 'robotstxt-mediaaudit' ),
__( 'Ignored 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' ); $known_providers = array( 'google_vision', 'tineye', 'picdefense' );
$output = array(); $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; continue;
} }
@ -757,6 +785,8 @@ class AuditPage {
$row_data[] = implode( '; ', $alert_list ); $row_data[] = implode( '; ', $alert_list );
$row_data[] = implode( '; ', $other_list ); $row_data[] = implode( '; ', $other_list );
$row_data[] = implode( '; ', $ignored_list ); $row_data[] = implode( '; ', $ignored_list );
$row_data[] = $is_dismissed ? __( 'Yes', 'robotstxt-mediaaudit' ) : __( 'No', 'robotstxt-mediaaudit' );
$row_data[] = $dismissed_notes[ $aid ] ?? '';
$output[] = $row_data; $output[] = $row_data;
} }
@ -772,7 +802,7 @@ class AuditPage {
private function handle_run_external_scan(): void { private function handle_run_external_scan(): void {
check_admin_referer( 'bulk-mra-attachments' ); 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' ) ); wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
} }
@ -804,7 +834,7 @@ class AuditPage {
private function handle_purge_external_data(): void { private function handle_purge_external_data(): void {
check_admin_referer( 'bulk-mra-attachments' ); 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' ) ); wp_die( esc_html__( 'Insufficient permissions.', 'robotstxt-mediaaudit' ) );
} }
@ -942,8 +972,12 @@ class AuditPage {
} }
} }
$dismissed = AlertsPage::get_dismissed_ids();
$alert_count = 0; $alert_count = 0;
foreach ( $merged as $domains ) { foreach ( $merged as $aid => $domains ) {
if ( isset( $dismissed[ $aid ] ) ) {
continue;
}
if ( HostnameFilter::has_alert_domains( $domains ) ) { if ( HostnameFilter::has_alert_domains( $domains ) ) {
++$alert_count; ++$alert_count;
} }

View file

@ -7,6 +7,7 @@
namespace MediaRightsAudit\Admin; namespace MediaRightsAudit\Admin;
use MediaRightsAudit\Admin\AlertsPage;
use MediaRightsAudit\Admin\AttachmentDetailPage; use MediaRightsAudit\Admin\AttachmentDetailPage;
use MediaRightsAudit\External\HostnameFilter; use MediaRightsAudit\External\HostnameFilter;
@ -290,7 +291,23 @@ class MediaListTable extends \WP_List_Table {
$top_domains_data[ $td_key ] = $td_val; $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 ) { if ( $has_alert ) {
$out = sprintf( $out = sprintf(
@ -486,6 +503,8 @@ class MediaListTable extends \WP_List_Table {
public function prepare_items() { public function prepare_items() {
global $wpdb; global $wpdb;
$dismissed_ids = AlertsPage::get_dismissed_ids();
$per_page = 20; $per_page = 20;
$paged = $this->get_pagenum(); $paged = $this->get_pagenum();
$offset = ( $paged - 1 ) * $per_page; $offset = ( $paged - 1 ) * $per_page;
@ -508,8 +527,10 @@ class MediaListTable extends \WP_List_Table {
// Detect alert filter before normalising external_status. // Detect alert filter before normalising external_status.
$filter_alert = ( 'alert' === $external_status ); $filter_alert = ( 'alert' === $external_status );
if ( $filter_alert ) { if ( $filter_alert ) {
// Reuse existing matches WHERE logic to narrow the candidate set. // Do not restrict by external_status: attachments can have alert domains
$external_status = 'matches'; // 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 ) ) { 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' ) ); $all_ids = array_map( 'intval', array_column( $all_rows, 'attachment_id' ) );
$top_domains_by_id = self::fetch_top_domains( $all_ids ); $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(); $filtered = array();
foreach ( $all_rows as $r ) { foreach ( $all_rows as $r ) {
if ( ! is_array( $r ) ) { if ( ! is_array( $r ) ) {
@ -586,7 +607,7 @@ class MediaListTable extends \WP_List_Table {
} }
$aid_val = $r['attachment_id'] ?? null; $aid_val = $r['attachment_id'] ?? null;
$aid = is_numeric( $aid_val ) ? (int) $aid_val : 0; $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; $filtered[] = $r;
} }
} }
@ -594,11 +615,12 @@ class MediaListTable extends \WP_List_Table {
$total = count( $filtered ); $total = count( $filtered );
$rows = array_slice( $filtered, $offset, $per_page ); $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 ) { foreach ( $rows as &$row ) {
$rid_val = $row['attachment_id'] ?? null; $rid_val = $row['attachment_id'] ?? null;
$rid = is_numeric( $rid_val ) ? (int) $rid_val : 0; $rid = is_numeric( $rid_val ) ? (int) $rid_val : 0;
$row['top_domains_data'] = $top_domains_by_id[ $rid ] ?? array(); $row['top_domains_data'] = $top_domains_by_id[ $rid ] ?? array();
$row['is_dismissed'] = isset( $dismissed_ids[ $rid ] );
} }
unset( $row ); unset( $row );
} else { } else {
@ -649,6 +671,7 @@ class MediaListTable extends \WP_List_Table {
$rid_val = $row['attachment_id'] ?? null; $rid_val = $row['attachment_id'] ?? null;
$rid = is_numeric( $rid_val ) ? (int) $rid_val : 0; $rid = is_numeric( $rid_val ) ? (int) $rid_val : 0;
$row['top_domains_data'] = $top_domains_by_id[ $rid ] ?? array(); $row['top_domains_data'] = $top_domains_by_id[ $rid ] ?? array();
$row['is_dismissed'] = isset( $dismissed_ids[ $rid ] );
} }
unset( $row ); unset( $row );
} }

View file

@ -24,6 +24,7 @@ class Database {
self::migration_100(); self::migration_100();
self::migration_101(); self::migration_101();
self::migration_110(); self::migration_110();
self::migration_120();
} }
/** /**
@ -48,6 +49,10 @@ class Database {
if ( version_compare( $current, '1.1.0', '<' ) ) { if ( version_compare( $current, '1.1.0', '<' ) ) {
self::migration_110(); 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 { public static function drop_tables(): void {
global $wpdb; 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_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_external_results`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_media_usage`" ); // 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; global $wpdb;
// phpcs:disable WordPress.DB.DirectDatabaseQuery // 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_provider_status`" );
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_external_results`" ); $wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_external_results`" );
$wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_media_usage`" ); $wpdb->query( "TRUNCATE TABLE `{$wpdb->prefix}mra_media_usage`" );
@ -215,4 +222,32 @@ class Database {
); );
// phpcs:enable WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared // 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; namespace MediaRightsAudit\Core;
use MediaRightsAudit\Admin\AlertsPage;
use MediaRightsAudit\Admin\AttachmentDetailPage; use MediaRightsAudit\Admin\AttachmentDetailPage;
use MediaRightsAudit\Admin\AuditPage; use MediaRightsAudit\Admin\AuditPage;
use MediaRightsAudit\Admin\Settings; use MediaRightsAudit\Admin\Settings;
@ -27,6 +28,13 @@ use MediaRightsAudit\Privacy\DataExporter;
*/ */
class Plugin { class Plugin {
/**
* Alerts page controller.
*
* @var AlertsPage
*/
private AlertsPage $alerts_page;
/** /**
* Settings page handler. * Settings page handler.
* *
@ -59,6 +67,7 @@ class Plugin {
* Initialises dependencies. * Initialises dependencies.
*/ */
public function __construct() { public function __construct() {
$this->alerts_page = new AlertsPage();
$this->settings = new Settings(); $this->settings = new Settings();
$this->audit_page = new AuditPage(); $this->audit_page = new AuditPage();
$this->tools_page = new ToolsPage(); $this->tools_page = new ToolsPage();
@ -127,6 +136,19 @@ class Plugin {
array( $this->audit_page, 'render' ) 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( $tools_suffix = add_submenu_page(
'robotstxt-mediaaudit', 'robotstxt-mediaaudit',
__( 'Tools', 'robotstxt-mediaaudit' ), __( 'Tools', 'robotstxt-mediaaudit' ),

View file

@ -99,7 +99,7 @@ abstract class AbstractProvider {
} }
arsort( $counts ); 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( $row = $wpdb->get_row(
$wpdb->prepare( $wpdb->prepare(
"SELECT "SELECT
SUM(status = 'queued') AS queued_count, SUM(status = 'queued') AS queued_count,
SUM(status = 'error') AS error_count,
SUM(status = 'scanned') AS scanned_count SUM(status = 'scanned') AS scanned_count
FROM {$wpdb->prefix}mra_provider_status FROM {$wpdb->prefix}mra_provider_status
WHERE attachment_id = %d", 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; $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; $scanned_count = isset( $row['scanned_count'] ) && is_numeric( $row['scanned_count'] ) ? (int) $row['scanned_count'] : 0;
if ( $queued_count > 0 ) { if ( $queued_count > 0 ) {
@ -544,9 +542,6 @@ class ExternalScanner {
$new_status = ( is_numeric( $match_sum ) && (int) $match_sum > 0 ) ? 'matches' : 'scanned'; $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->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->prefix . 'mra_media_index', $wpdb->prefix . 'mra_media_index',
array( array(

Binary file not shown.

View file

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

View file

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

View file

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

View file

@ -5,7 +5,7 @@ Requires at least: 6.8
Tested up to: 7.0 Tested up to: 7.0
Requires PHP: 8.2 Requires PHP: 8.2
Requires Plugins: action-scheduler Requires Plugins: action-scheduler
Stable tag: 1.6.0 Stable tag: 1.7.0
License: GPL-3.0-or-later License: GPL-3.0-or-later
License URI: https://www.gnu.org/licenses/gpl-3.0.txt License URI: https://www.gnu.org/licenses/gpl-3.0.txt
@ -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. * **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. * **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. * **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. * **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. * **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. * **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 Name: Media Audit (by ROBOTSTXT)
* Plugin URI: https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit * Plugin URI: https://git.robotstxt.es/ROBOTSTXT/robotstxt-mediaaudit
* Description: Internal media library usage auditing and external reverse image search to detect potential copyright issues. * Description: Internal media library usage auditing and external reverse image search to detect potential copyright issues.
* Version: 1.6.0 * Version: 1.7.0
* Requires at least: 6.8 * Requires at least: 6.8
* Tested up to: 7.0 * Tested up to: 7.0
* Requires PHP: 8.2 * Requires PHP: 8.2
@ -23,8 +23,8 @@ if ( ! defined( 'ABSPATH' ) ) {
exit; exit;
} }
define( 'ROBOTSTXT_MEDIAAUDIT_VERSION', '1.6.0' ); define( 'ROBOTSTXT_MEDIAAUDIT_VERSION', '1.7.0' );
define( 'ROBOTSTXT_MEDIAAUDIT_DB_VERSION', '1.1.0' ); define( 'ROBOTSTXT_MEDIAAUDIT_DB_VERSION', '1.2.0' );
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_FILE', __FILE__ ); define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_FILE', __FILE__ );
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); define( 'ROBOTSTXT_MEDIAAUDIT_PLUGIN_URL', plugin_dir_url( __FILE__ ) );

View file

@ -23,6 +23,7 @@ if ( ! $delete ) {
global $wpdb; global $wpdb;
// Drop tables in reverse dependency order. // 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_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_external_results`" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery
$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}mra_media_usage`" ); // 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( return array(
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php', 'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'MediaRightsAudit\\Admin\\AlertsPage' => $baseDir . '/includes/Admin/AlertsPage.php',
'MediaRightsAudit\\Admin\\AttachmentDetailPage' => $baseDir . '/includes/Admin/AttachmentDetailPage.php', 'MediaRightsAudit\\Admin\\AttachmentDetailPage' => $baseDir . '/includes/Admin/AttachmentDetailPage.php',
'MediaRightsAudit\\Admin\\AuditPage' => $baseDir . '/includes/Admin/AuditPage.php', 'MediaRightsAudit\\Admin\\AuditPage' => $baseDir . '/includes/Admin/AuditPage.php',
'MediaRightsAudit\\Admin\\MediaListTable' => $baseDir . '/includes/Admin/MediaListTable.php', 'MediaRightsAudit\\Admin\\MediaListTable' => $baseDir . '/includes/Admin/MediaListTable.php',

View file

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