333 lines
14 KiB
PHP
333 lines
14 KiB
PHP
<?php
|
|
/**
|
|
* Admin page view: ROBOTSTXT Plugins catalog.
|
|
*
|
|
* Catalog table (Plugin · Version · Requires WP · Requires PHP · Price ·
|
|
* Action · Status) with an always-open detail row under each plugin
|
|
* (website link + description), an intro paragraph, and Support /
|
|
* Payments sections below the table.
|
|
*
|
|
* @package Robotstxt_Manager
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Variables provided by Robotstxt_Manager_Admin::render_page().
|
|
*
|
|
* @var list<array<string,mixed>> $catalog
|
|
* @var array<string, array{installed:bool, active:bool, version:string}> $local
|
|
*/
|
|
|
|
$client_configured = Robotstxt_Manager_Core_Client::from_options()->is_configured();
|
|
$refresh_url = add_query_arg(
|
|
array(
|
|
'action' => 'robotstxt_manager_refresh_catalog',
|
|
),
|
|
admin_url( 'admin-post.php' )
|
|
);
|
|
$refresh_url = wp_nonce_url( $refresh_url, 'robotstxt_manager_refresh_catalog' );
|
|
$refreshed = isset( $_GET['refreshed'] ) && '1' === $_GET['refreshed']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
|
|
|
// Action notice from an install/activate/update redirect.
|
|
$notice_result = '';
|
|
$notice_message = '';
|
|
|
|
if ( isset( $_GET['robotstxt_manager_result'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display-only, set by this plugin's own redirects.
|
|
$raw_result = wp_unslash( $_GET['robotstxt_manager_result'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized on the next line.
|
|
if ( is_string( $raw_result ) ) {
|
|
$notice_result = sanitize_key( $raw_result );
|
|
}
|
|
}
|
|
|
|
if ( isset( $_GET['robotstxt_manager_message'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- display-only, set by this plugin's own redirects.
|
|
$raw_message = wp_unslash( $_GET['robotstxt_manager_message'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized on the next line after decoding.
|
|
if ( is_string( $raw_message ) ) {
|
|
$notice_message = sanitize_text_field( rawurldecode( $raw_message ) );
|
|
}
|
|
}
|
|
|
|
$local_wp_version = (string) get_bloginfo( 'version' );
|
|
$local_php_version = (string) PHP_VERSION;
|
|
$compat_warnings = 0;
|
|
?>
|
|
|
|
<div class="wrap">
|
|
<h1><?php esc_html_e( 'Manager (by ROBOTSTXT) — Plugins', 'robotstxt-manager' ); ?></h1>
|
|
|
|
<p class="description">
|
|
<?php esc_html_e( 'This is the ROBOTSTXT plugin store: the catalog of plugins published by ROBOTSTXT, installable and updatable straight from your own wp-admin. Free plugins install with one click; premium plugins require an annual subscription that you purchase on our website.', 'robotstxt-manager' ); ?>
|
|
</p>
|
|
|
|
<?php if ( $refreshed ) : ?>
|
|
<div class="notice notice-success is-dismissible"><p><?php esc_html_e( 'Catalog refreshed.', 'robotstxt-manager' ); ?></p></div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ( '' !== $notice_message && in_array( $notice_result, array( 'success', 'error' ), true ) ) : ?>
|
|
<div class="notice notice-<?php echo esc_attr( $notice_result ); ?> is-dismissible"><p><?php echo esc_html( $notice_message ); ?></p></div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ( ! $client_configured ) : ?>
|
|
<div class="notice notice-error">
|
|
<p>
|
|
<?php
|
|
echo wp_kses_post(
|
|
sprintf(
|
|
/* translators: %s: settings URL. */
|
|
__( 'ROBOTSTXT Manager is not configured yet. <a href="%s">Set the Store URL and API key</a> to see your plugin catalog.', 'robotstxt-manager' ),
|
|
esc_url( admin_url( 'admin.php?page=' . Robotstxt_Manager_Settings::PAGE_SLUG ) )
|
|
)
|
|
);
|
|
?>
|
|
</p>
|
|
</div>
|
|
<?php elseif ( empty( $catalog ) ) : ?>
|
|
<div class="notice notice-warning">
|
|
<p>
|
|
<?php esc_html_e( 'No plugins were returned by the ROBOTSTXT store. Check the Store URL and API key on the Settings page, or click Refresh to try again.', 'robotstxt-manager' ); ?>
|
|
</p>
|
|
</div>
|
|
<p><a class="button" href="<?php echo esc_url( $refresh_url ); ?>"><?php esc_html_e( 'Refresh catalog', 'robotstxt-manager' ); ?></a></p>
|
|
<?php else : ?>
|
|
<p>
|
|
<a class="button" href="<?php echo esc_url( $refresh_url ); ?>"><?php esc_html_e( 'Refresh catalog', 'robotstxt-manager' ); ?></a>
|
|
</p>
|
|
|
|
<table class="wp-list-table widefat striped robotstxt-manager-catalog">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col"><?php esc_html_e( 'Plugin', 'robotstxt-manager' ); ?></th>
|
|
<th scope="col"><?php esc_html_e( 'Version', 'robotstxt-manager' ); ?></th>
|
|
<th scope="col"><?php esc_html_e( 'Requires WP', 'robotstxt-manager' ); ?></th>
|
|
<th scope="col"><?php esc_html_e( 'Requires PHP', 'robotstxt-manager' ); ?></th>
|
|
<th scope="col"><?php esc_html_e( 'Price', 'robotstxt-manager' ); ?></th>
|
|
<th scope="col"><?php esc_html_e( 'Action', 'robotstxt-manager' ); ?></th>
|
|
<th scope="col"><?php esc_html_e( 'Status', 'robotstxt-manager' ); ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ( $catalog as $entry ) : ?>
|
|
<?php
|
|
$raw_slug = $entry['slug'] ?? '';
|
|
$raw_name = $entry['name'] ?? '';
|
|
$raw_kind = $entry['type'] ?? 'free';
|
|
$raw_cost = $entry['price_annual'] ?? 0;
|
|
$raw_ver = $entry['current_version'] ?? '';
|
|
$raw_url = $entry['page_url'] ?? '';
|
|
$raw_home = $entry['homepage'] ?? '';
|
|
$raw_desc = $entry['description'] ?? '';
|
|
$raw_rwp = $entry['requires_wp'] ?? '';
|
|
$raw_rphp = $entry['requires_php'] ?? '';
|
|
|
|
$slug = is_string( $raw_slug ) ? $raw_slug : '';
|
|
$name = is_string( $raw_name ) ? $raw_name : $slug;
|
|
$kind = is_string( $raw_kind ) ? $raw_kind : 'free';
|
|
$cost = is_numeric( $raw_cost ) ? (float) ( $raw_cost + 0.0 ) : 0.0;
|
|
$remote_v = is_string( $raw_ver ) ? $raw_ver : '';
|
|
$page_url = is_string( $raw_url ) ? $raw_url : '';
|
|
$homepage = is_string( $raw_home ) ? $raw_home : '';
|
|
$desc = is_string( $raw_desc ) ? trim( $raw_desc ) : '';
|
|
$req_wp = is_string( $raw_rwp ) ? $raw_rwp : '';
|
|
$req_php = is_string( $raw_rphp ) ? $raw_rphp : '';
|
|
|
|
$website_url = '' !== $page_url ? $page_url : $homepage;
|
|
$has_detail = ( '' !== $website_url || '' !== $desc );
|
|
|
|
$raw_reqs = $entry['requires_plugins'] ?? '';
|
|
$req_slugs = array();
|
|
if ( is_string( $raw_reqs ) && '' !== trim( $raw_reqs ) ) {
|
|
foreach ( explode( ',', $raw_reqs ) as $part ) {
|
|
$dep = sanitize_key( trim( $part ) );
|
|
if ( '' !== $dep ) {
|
|
$req_slugs[] = $dep;
|
|
}
|
|
}
|
|
}
|
|
$has_detail = $has_detail || array() !== $req_slugs;
|
|
|
|
// Compatibility checks.
|
|
$wp_ok = '' === $req_wp || version_compare( $local_wp_version, $req_wp, '>=' );
|
|
$php_ok = '' === $req_php || version_compare( $local_php_version, $req_php, '>=' );
|
|
|
|
if ( ! $wp_ok || ! $php_ok ) {
|
|
++$compat_warnings;
|
|
}
|
|
|
|
$raw_state = $local[ $slug ] ?? array(
|
|
'installed' => false,
|
|
'active' => false,
|
|
'version' => '',
|
|
);
|
|
$l_installed = (bool) ( $raw_state['installed'] ?? false );
|
|
$l_active = (bool) ( $raw_state['active'] ?? false );
|
|
$raw_lv = $raw_state['version'] ?? '';
|
|
$l_version = is_string( $raw_lv ) ? $raw_lv : '';
|
|
|
|
$update_available = $l_installed && '' !== $remote_v && '' !== $l_version
|
|
&& version_compare( $l_version, $remote_v, '<' );
|
|
|
|
$row_class = ( ! $wp_ok || ! $php_ok ) ? ' robotstxt-manager-row--incompatible' : '';
|
|
?>
|
|
<tr class="<?php echo esc_attr( ltrim( $row_class ) ); ?>">
|
|
<td class="robotstxt-manager-name-cell">
|
|
<strong><?php echo esc_html( $name ); ?></strong>
|
|
</td>
|
|
<td><?php echo '' !== $remote_v ? esc_html( $remote_v ) : '—'; ?></td>
|
|
<td>
|
|
<?php if ( '' !== $req_wp ) : ?>
|
|
<span class="<?php echo $wp_ok ? 'robotstxt-manager-compat--ok' : 'robotstxt-manager-compat--fail'; ?>">
|
|
<?php echo esc_html( $req_wp ); ?>
|
|
<?php if ( ! $wp_ok ) : ?>
|
|
<span class="robotstxt-manager-compat-warning" title="<?php esc_attr_e( 'Your site runs WordPress', 'robotstxt-manager' ); ?> <?php echo esc_attr( $local_wp_version ); ?>"> ⚠</span>
|
|
<?php endif; ?>
|
|
</span>
|
|
<?php else : ?>
|
|
—
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php if ( '' !== $req_php ) : ?>
|
|
<span class="<?php echo $php_ok ? 'robotstxt-manager-compat--ok' : 'robotstxt-manager-compat--fail'; ?>">
|
|
<?php echo esc_html( $req_php ); ?>
|
|
<?php if ( ! $php_ok ) : ?>
|
|
<span class="robotstxt-manager-compat-warning" title="<?php esc_attr_e( 'Your server runs PHP', 'robotstxt-manager' ); ?> <?php echo esc_attr( $local_php_version ); ?>"> ⚠</span>
|
|
<?php endif; ?>
|
|
</span>
|
|
<?php else : ?>
|
|
—
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
if ( $cost > 0.0 || 'premium' === $kind ) {
|
|
echo esc_html(
|
|
sprintf(
|
|
/* translators: %s: formatted price number. */
|
|
__( '€%s / year', 'robotstxt-manager' ),
|
|
number_format_i18n( $cost, 0 )
|
|
)
|
|
);
|
|
} else {
|
|
echo esc_html__( 'Free', 'robotstxt-manager' );
|
|
}
|
|
?>
|
|
</td>
|
|
<td>
|
|
<?php if ( ! $l_installed ) : ?>
|
|
<?php if ( ! $wp_ok || ! $php_ok ) : ?>
|
|
<span class="description"><?php esc_html_e( 'Incompatible', 'robotstxt-manager' ); ?></span>
|
|
<?php else : ?>
|
|
<?php if ( $cost > 0.0 && '' !== $page_url ) : ?>
|
|
<a class="button button-secondary" href="<?php echo esc_url( $page_url ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Buy', 'robotstxt-manager' ); ?></a>
|
|
<?php endif; ?>
|
|
<?php
|
|
$install_class = ( $cost > 0.0 && '' !== $page_url ) ? 'button-secondary' : 'button-primary';
|
|
?>
|
|
<a class="button <?php echo esc_attr( $install_class ); ?>" href="<?php echo esc_url( Robotstxt_Manager_Admin::action_url( 'install', $slug ) ); ?>"><?php esc_html_e( 'Install', 'robotstxt-manager' ); ?></a>
|
|
<?php endif; ?>
|
|
<?php elseif ( ! $l_active ) : ?>
|
|
<a class="button button-primary" href="<?php echo esc_url( Robotstxt_Manager_Admin::action_url( 'activate', $slug ) ); ?>"><?php esc_html_e( 'Activate', 'robotstxt-manager' ); ?></a>
|
|
<?php elseif ( $update_available ) : ?>
|
|
<a class="button button-secondary" href="<?php echo esc_url( Robotstxt_Manager_Admin::action_url( 'update', $slug ) ); ?>"><?php esc_html_e( 'Update', 'robotstxt-manager' ); ?></a>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
if ( ! $l_installed ) {
|
|
echo '<span class="robotstxt-manager-state robotstxt-manager-state--not-installed">' . esc_html__( 'Not installed', 'robotstxt-manager' ) . '</span>';
|
|
} elseif ( ! $l_active ) {
|
|
echo '<span class="robotstxt-manager-state robotstxt-manager-state--inactive">' . esc_html__( 'Installed (inactive)', 'robotstxt-manager' ) . '</span>';
|
|
} elseif ( $update_available ) {
|
|
echo '<span class="robotstxt-manager-state robotstxt-manager-state--update">' . esc_html(
|
|
sprintf(
|
|
/* translators: 1: installed version, 2: available version. */
|
|
__( 'Update available (v%1$s → v%2$s)', 'robotstxt-manager' ),
|
|
$l_version,
|
|
$remote_v
|
|
)
|
|
) . '</span>';
|
|
} else {
|
|
echo '<span class="robotstxt-manager-state robotstxt-manager-state--ok">' . esc_html__( 'Up to date', 'robotstxt-manager' ) . '</span>';
|
|
}
|
|
?>
|
|
</td>
|
|
</tr>
|
|
<?php if ( $has_detail ) : ?>
|
|
<tr class="robotstxt-manager-detail-row">
|
|
<td colspan="7">
|
|
<?php if ( '' !== $website_url ) : ?>
|
|
<a href="<?php echo esc_url( $website_url ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Visit website', 'robotstxt-manager' ); ?> <span class="screen-reader-text"><?php echo esc_html( sprintf( /* translators: %s: plugin name. */ __( '(about %s)', 'robotstxt-manager' ), $name ) ); ?></span></a>
|
|
<?php endif; ?>
|
|
<?php if ( '' !== $desc ) : ?>
|
|
<span class="robotstxt-manager-detail-description"><?php echo esc_html( $desc ); ?></span>
|
|
<?php endif; ?>
|
|
<?php if ( array() !== $req_slugs ) : ?>
|
|
<span class="robotstxt-manager-detail-requires">
|
|
<?php
|
|
echo esc_html(
|
|
sprintf(
|
|
/* translators: %s: list of plugin slugs. */
|
|
__( 'Requires: %s', 'robotstxt-manager' ),
|
|
implode( ', ', $req_slugs )
|
|
)
|
|
);
|
|
?>
|
|
</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
|
|
<h2><?php esc_html_e( 'Support', 'robotstxt-manager' ); ?></h2>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Need help with a ROBOTSTXT plugin? Visit the plugin\'s website (the link in its row above) for documentation and guides, or contact us through our website — we are happy to help.', 'robotstxt-manager' ); ?>
|
|
</p>
|
|
|
|
<h2><?php esc_html_e( 'Payments, and how it works', 'robotstxt-manager' ); ?></h2>
|
|
<p class="description">
|
|
<?php esc_html_e( 'Free plugins install instantly at no cost. Premium plugins are annual subscriptions: you pay once on our website and the subscription renews automatically every year until you cancel. You can cancel at any time from your ROBOTSTXT account page — access keeps working until the end of the paid period. All payments are processed securely by Mollie; we never see or store your card details.', 'robotstxt-manager' ); ?>
|
|
</p>
|
|
|
|
<?php if ( $compat_warnings > 0 ) : ?>
|
|
<div class="notice notice-warning inline" style="margin-top:1em">
|
|
<p>
|
|
<?php
|
|
echo esc_html(
|
|
sprintf(
|
|
/* translators: %d: number of incompatible plugins. */
|
|
_n( '%d plugin in the catalog is not compatible with this site\'s WordPress or PHP version.', '%d plugins in the catalog are not compatible with this site\'s WordPress or PHP version.', $compat_warnings, 'robotstxt-manager' ),
|
|
$compat_warnings
|
|
)
|
|
);
|
|
?>
|
|
<?php
|
|
echo esc_html(
|
|
sprintf(
|
|
/* translators: 1: local WP version, 2: local PHP version. */
|
|
__( 'This site runs WordPress %1$s on PHP %2$s.', 'robotstxt-manager' ),
|
|
$local_wp_version,
|
|
$local_php_version
|
|
)
|
|
);
|
|
?>
|
|
</p>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<style>
|
|
.robotstxt-manager-compat--ok { color: #00a32a; }
|
|
.robotstxt-manager-compat--fail { color: #d63638; font-weight: 600; }
|
|
.robotstxt-manager-compat-warning { cursor: help; }
|
|
.robotstxt-manager-row--incompatible { background-color: #fef7f0 !important; }
|
|
|
|
/* Detail rows (always open): muted, attached to the row above. */
|
|
.robotstxt-manager-detail-row td { border-top: none !important; padding-top: 0; }
|
|
.robotstxt-manager-detail-description { color: #50575e; }
|
|
</style>
|