芝麻web文件管理V1.00
', self::get_akismet_form_fields() . '', $html );
return $html;
}
public static function append_custom_form_fields( $html ) {
$html .= self::get_akismet_form_fields();
return $html;
}
/**
* Ensure that any Akismet-added form fields are included in the comment-check call.
*
* @param array $form
* @param array $data Some plugins will supply the POST data via the filter, since they don't
* read it directly from $_POST.
* @return array $form
*/
public static function prepare_custom_form_values( $form, $data = null ) {
if ( 'fluentform/akismet_fields' === current_filter() && did_filter( 'fluentform_akismet_fields' ) ) {
// Already updated the form fields via the legacy filter.
return $form;
}
if ( is_null( $data ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Missing
$data = $_POST;
}
$prefix = 'ak_';
// Contact Form 7 uses _wpcf7 as a prefix to know which fields to exclude from comment_content.
if ( 'wpcf7_akismet_parameters' === current_filter() ) {
$prefix = '_wpcf7_ak_';
}
foreach ( $data as $key => $val ) {
if ( 0 === strpos( $key, $prefix ) ) {
$form[ 'POST_ak_' . substr( $key, strlen( $prefix ) ) ] = $val;
}
}
return $form;
}
private static function bail_on_activation( $message, $deactivate = true ) {
?>
$plugin ) {
if ( $plugin === $akismet ) {
$plugins[$i] = false;
$update = true;
}
}
if ( $update ) {
update_option( 'active_plugins', array_filter( $plugins ) );
}
}
exit;
}
public static function view( $name, array $args = array() ) {
$args = apply_filters( 'akismet_view_arguments', $args, $name );
foreach ( $args as $key => $val ) {
$$key = $val;
}
load_plugin_textdomain( 'akismet' );
$file = AKISMET__PLUGIN_DIR . 'views/'. $name . '.php';
include( $file );
}
/**
* Attached to activate_{ plugin_basename( __FILES__ ) } by register_activation_hook()
* @static
*/
public static function plugin_activation() {
if ( version_compare( $GLOBALS['wp_version'], AKISMET__MINIMUM_WP_VERSION, '<' ) ) {
load_plugin_textdomain( 'akismet' );
$message = '
'.sprintf(esc_html__( 'Akismet %s requires WordPress %s or higher.' , 'akismet'), AKISMET_VERSION, AKISMET__MINIMUM_WP_VERSION ).' '.sprintf(__('Please
upgrade WordPress to a current version, or
downgrade to version 2.4 of the Akismet plugin .', 'akismet'), 'https://codex.wordpress.org/Upgrading_WordPress', 'https://wordpress.org/extend/plugins/akismet/download/');
Akismet::bail_on_activation( $message );
} elseif ( ! empty( $_SERVER['SCRIPT_NAME'] ) && false !== strpos( $_SERVER['SCRIPT_NAME'], '/wp-admin/plugins.php' ) ) {
add_option( 'Activated_Akismet', true );
}
}
/**
* Removes all connection options
* @static
*/
public static function plugin_deactivation( ) {
self::deactivate_key( self::get_api_key() );
// Remove any scheduled cron jobs.
$akismet_cron_events = array(
'akismet_schedule_cron_recheck',
'akismet_scheduled_delete',
);
foreach ( $akismet_cron_events as $akismet_cron_event ) {
$timestamp = wp_next_scheduled( $akismet_cron_event );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, $akismet_cron_event );
}
}
}
/**
* Essentially a copy of WP's build_query but one that doesn't expect pre-urlencoded values.
*
* @param array $args An array of key => value pairs
* @return string A string ready for use as a URL query string.
*/
public static function build_query( $args ) {
return _http_build_query( $args, '', '&' );
}
/**
* Log debugging info to the error log.
*
* Enabled when WP_DEBUG_LOG is enabled (and WP_DEBUG, since according to
* core, "WP_DEBUG_DISPLAY and WP_DEBUG_LOG perform no function unless
* WP_DEBUG is true), but can be disabled via the akismet_debug_log filter.
*
* @param mixed $akismet_debug The data to log.
*/
public static function log( $akismet_debug ) {
if ( apply_filters( 'akismet_debug_log', defined( 'WP_DEBUG' ) && WP_DEBUG && defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG && defined( 'AKISMET_DEBUG' ) && AKISMET_DEBUG ) ) {
error_log( print_r( compact( 'akismet_debug' ), true ) );
}
}
/**
* Check pingbacks for spam before they're saved to the DB.
*
* @param string $method The XML-RPC method that was called.
* @param array $args This and the $server arg are marked as optional since plugins might still be
* calling do_action( 'xmlrpc_action', [...] ) without the arguments that were added in WP 5.7.
* @param wp_xmlrpc_server $server
*/
public static function pre_check_pingback( $method, $args = array(), $server = null ) {
if ( $method !== 'pingback.ping' ) {
return;
}
/*
* $args looks like this:
*
* Array
* (
* [0] => http://www.example.net/?p=1 // Site that created the pingback.
* [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
* )
*/
if ( ! is_null( $server ) && ! empty( $args[1] ) ) {
$is_multicall = false;
$multicall_count = 0;
if ( 'system.multicall' === $server->message->methodName ) {
$is_multicall = true;
$multicall_count = is_countable( $server->message->params ) ? count( $server->message->params ) : 0;
}
$post_id = url_to_postid( $args[1] );
// If pingbacks aren't open on this post, we'll still check whether this request is part of a potential DDOS,
// but indicate to the server that pingbacks are indeed closed so we don't include this request in the user's stats,
// since the user has already done their part by disabling pingbacks.
$pingbacks_closed = false;
$post = get_post( $post_id );
if ( ! $post || ! pings_open( $post ) ) {
$pingbacks_closed = true;
}
$comment = array(
'comment_author_url' => $args[0],
'comment_post_ID' => $post_id,
'comment_author' => '',
'comment_author_email' => '',
'comment_content' => '',
'comment_type' => 'pingback',
'akismet_pre_check' => '1',
'comment_pingback_target' => $args[1],
'pingbacks_closed' => $pingbacks_closed ? '1' : '0',
'is_multicall' => $is_multicall,
'multicall_count' => $multicall_count,
);
$comment = self::auto_check_comment( $comment, 'xml-rpc' );
if ( isset( $comment['akismet_result'] ) && 'true' == $comment['akismet_result'] ) {
// Sad: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
$server->error( new IXR_Error( 0, 'Invalid discovery target' ) );
// Also note that if this was part of a multicall, a spam result will prevent the subsequent calls from being executed.
// This is probably fine, but it raises the bar for what should be acceptable as a false positive.
}
}
}
/**
* Ensure that we are loading expected scalar values from akismet_as_submitted commentmeta.
*
* @param mixed $meta_value
* @return mixed
*/
private static function sanitize_comment_as_submitted( $meta_value ) {
if ( empty( $meta_value ) ) {
return $meta_value;
}
$meta_value = (array) $meta_value;
foreach ( $meta_value as $key => $value ) {
if ( ! is_scalar( $value ) ) {
unset( $meta_value[ $key ] );
} else {
// These can change, so they're not explicitly listed in comment_as_submitted_allowed_keys.
if ( strpos( $key, 'POST_ak_' ) === 0 ) {
continue;
}
if ( ! isset( self::$comment_as_submitted_allowed_keys[ $key ] ) ) {
unset( $meta_value[ $key ] );
}
}
}
return $meta_value;
}
public static function predefined_api_key() {
if ( defined( 'WPCOM_API_KEY' ) ) {
return true;
}
return apply_filters( 'akismet_predefined_api_key', false );
}
/**
* Controls the display of a privacy related notice underneath the comment form using the `akismet_comment_form_privacy_notice` option and filter respectively.
* Default is top not display the notice, leaving the choice to site admins, or integrators.
*/
public static function display_comment_form_privacy_notice() {
if ( 'display' !== apply_filters( 'akismet_comment_form_privacy_notice', get_option( 'akismet_comment_form_privacy_notice', 'hide' ) ) ) {
return;
}
echo apply_filters(
'akismet_comment_form_privacy_notice_markup',
''
);
}
public static function load_form_js() {
if (
! is_admin()
&& ( ! function_exists( 'amp_is_request' ) || ! amp_is_request() )
&& self::get_api_key()
) {
wp_register_script( 'akismet-frontend', plugin_dir_url( __FILE__ ) . '_inc/akismet-frontend.js', array(), filemtime( plugin_dir_path( __FILE__ ) . '_inc/akismet-frontend.js' ), true );
wp_enqueue_script( 'akismet-frontend' );
}
}
/**
* Add the form JavaScript when we detect that a supported form shortcode is being parsed.
*/
public static function load_form_js_via_filter( $return_value, $tag, $attr, $m ) {
if ( in_array( $tag, array( 'contact-form', 'gravityform', 'contact-form-7', 'formidable', 'fluentform' ) ) ) {
self::load_form_js();
}
return $return_value;
}
/**
* Was the last entry in the comment history created by Akismet?
*
* @param int $comment_id The ID of the comment.
* @return bool
*/
public static function last_comment_status_change_came_from_akismet( $comment_id ) {
$history = self::get_comment_history( $comment_id );
if ( empty( $history ) ) {
return false;
}
$most_recent_history_event = $history[0];
if ( ! isset( $most_recent_history_event['event'] ) ) {
return false;
}
$akismet_history_events = array(
'check-error',
'cron-retry-ham',
'cron-retry-spam',
'check-ham',
'check-spam',
'recheck-error',
'recheck-ham',
'recheck-spam',
'webhook-ham',
'webhook-spam',
);
if ( in_array( $most_recent_history_event['event'], $akismet_history_events ) ) {
return true;
}
return false;
}
}
readme.txt 0000644 00000013625 14744621672 0006566 0 ustar 00 === Akismet Anti-spam: Spam Protection ===
Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau, kbrownkd, bluefuton, akismetantispam
Tags: comments, spam, antispam, anti-spam, contact form
Requires at least: 5.8
Tested up to: 6.7
Stable tag: 5.3.3
License: GPLv2 or later
The best anti-spam protection to block spam comments and spam in a contact form. The most trusted antispam solution for WordPress and WooCommerce.
== Description ==
The best anti-spam protection to block spam comments and spam in a contact form. The most trusted antispam solution for WordPress and WooCommerce.
Akismet checks your comments and contact form submissions against our global database of spam to prevent your site from publishing malicious content. You can review the comment spam it catches on your blog's "Comments" admin screen.
Major features in Akismet include:
* Automatically checks all comments and filters out the ones that look like spam.
* Each comment has a status history, so you can easily see which comments were caught or cleared by Akismet and which were spammed or unspammed by a moderator.
* URLs are shown in the comment body to reveal hidden or misleading links.
* Moderators can see the number of approved comments for each user.
* A discard feature that outright blocks the worst spam, saving you disk space and speeding up your site.
PS: You'll be prompted to get an Akismet.com API key to use it, once activated. Keys are free for personal blogs; paid subscriptions are available for businesses and commercial sites.
== Installation ==
Upload the Akismet plugin to your blog, activate it, and then enter your Akismet.com API key.
1, 2, 3: You're done!
== Changelog ==
= 5.3.3 =
*Release Date - 10 July 2024*
* Make setup step clearer for new users.
* Remove the stats section from the configuration page if the site has been revoked from the key.
* Skip the Akismet comment check when the comment matches something in the disallowed list.
* Prompt users on legacy plans to contact Akismet support for upgrades.
= 5.3.2 =
*Release Date - 21 March 2024*
* Improve the empty state shown to new users when no spam has been caught yet.
* Update the message shown to users without a current subscription.
* Add foundations for future webhook support.
= 5.3.1 =
*Release Date - 17 January 2024*
* Make the plugin more resilient when asset files are missing (as seen in WordPress Playground).
* Add a link to the 'Account overview' page on akismet.com.
* Fix a minor error that occurs when another plugin removes all comment actions from the dashboard.
* Add the akismet_request_args filter to allow request args in Akismet API requests to be filtered.
* Fix a bug that causes some contact forms to include unnecessary data in the comment_content parameter.
= 5.3 =
*Release Date - 14 September 2023*
* Improve display of user notices.
* Add stylesheets for RTL languages.
* Remove initial disabled state from 'Save changes' button.
* Improve accessibility of API key entry form.
* Add new filter hooks for Fluent Forms.
* Fix issue with PHP 8.1 compatibility.
= 5.2 =
*Release Date - 21 June 2023*
* Visual refresh of Akismet stats.
* Improve PHP 8.1 compatibility.
* Improve appearance of plugin to match updated stats.
* Change minimum supported PHP version to 5.6 to match WordPress.
* Drop IE11 support and update minimum WordPress version to 5.8 (where IE11 support was removed from WP Core).
= 5.1 =
*Release Date - 20 March 2023*
* Removed unnecessary limit notices from admin page.
* Improved spam detection by including post taxonomies in the comment-check call.
* Removed API keys from stats iframes to avoid possible inadvertent exposure.
= 5.0.2 =
*Release Date - 1 December 2022*
* Improved compatibility with themes that hide or show UI elements based on mouse movements.
* Increased security of API keys by sending them in request bodies instead of subdomains.
= 5.0.1 =
*Release Date - 28 September 2022*
* Added an empty state for the Statistics section on the admin page.
* Fixed a bug that broke some admin page links when Jetpack plugins are active.
* Marked some event listeners as passive to improve performance in newer browsers.
* Disabled interaction observation on forms that post to other domains.
= 5.0 =
*Release Date - 26 July 2022*
* Added a new feature to catch spammers by observing how they interact with the page.
= 4.2.5 =
*Release Date - 11 July 2022*
* Fixed a bug that added unnecessary comment history entries after comment rechecks.
* Added a notice that displays when WP-Cron is disabled and might be affecting comment rechecks.
= 4.2.4 =
*Release Date - 20 May 2022*
* Improved translator instructions for comment history.
* Bumped the "Tested up to" tag to WP 6.0.
= 4.2.3 =
*Release Date - 25 April 2022*
* Improved compatibility with Fluent Forms
* Fixed missing translation domains
* Updated stats URL.
* Improved accessibility of elements on the config page.
= 4.2.2 =
*Release Date - 24 January 2022*
* Improved compatibility with Formidable Forms
* Fixed a bug that could cause issues when multiple contact forms appear on one page.
* Updated delete_comment and deleted_comment actions to pass two arguments to match WordPress core since 4.9.0.
* Added a filter that allows comment types to be excluded when counting users' approved comments.
= 4.2.1 =
*Release Date - 1 October 2021*
* Fixed a bug causing AMP validation to fail on certain pages with forms.
= 4.2 =
*Release Date - 30 September 2021*
* Added links to additional information on API usage notifications.
* Reduced the number of network requests required for a comment page when running Akismet.
* Improved compatibility with the most popular contact form plugins.
* Improved API usage buttons for clarity on what upgrade is needed.
For older changelog entries, please see the [additional changelog.txt file](https://plugins.svn.wordpress.org/akismet/trunk/changelog.txt) delivered with the plugin.
class.akismet-rest-api.php 0000644 00000042507 14744621672 0011565 0 ustar 00 WP_REST_Server::READABLE,
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'get_key' ),
), array(
'methods' => WP_REST_Server::EDITABLE,
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'set_key' ),
'args' => array(
'key' => array(
'required' => true,
'type' => 'string',
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
),
),
), array(
'methods' => WP_REST_Server::DELETABLE,
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'delete_key' ),
)
) );
register_rest_route( 'akismet/v1', '/settings/', array(
array(
'methods' => WP_REST_Server::READABLE,
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'get_settings' ),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'set_boolean_settings' ),
'args' => array(
'akismet_strictness' => array(
'required' => false,
'type' => 'boolean',
'description' => __( 'If true, Akismet will automatically discard the worst spam automatically rather than putting it in the spam folder.', 'akismet' ),
),
'akismet_show_user_comments_approved' => array(
'required' => false,
'type' => 'boolean',
'description' => __( 'If true, show the number of approved comments beside each comment author in the comments list page.', 'akismet' ),
),
),
)
) );
register_rest_route( 'akismet/v1', '/stats', array(
'methods' => WP_REST_Server::READABLE,
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'get_stats' ),
'args' => array(
'interval' => array(
'required' => false,
'type' => 'string',
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_interval' ),
'description' => __( 'The time period for which to retrieve stats. Options: 60-days, 6-months, all', 'akismet' ),
'default' => 'all',
),
),
) );
register_rest_route( 'akismet/v1', '/stats/(?P
[\w+])', array(
'args' => array(
'interval' => array(
'description' => __( 'The time period for which to retrieve stats. Options: 60-days, 6-months, all', 'akismet' ),
'type' => 'string',
),
),
array(
'methods' => WP_REST_Server::READABLE,
'permission_callback' => array( 'Akismet_REST_API', 'privileged_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'get_stats' ),
)
) );
register_rest_route( 'akismet/v1', '/alert', array(
array(
'methods' => WP_REST_Server::READABLE,
'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'get_alert' ),
'args' => array(
'key' => array(
'required' => false,
'type' => 'string',
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
),
),
),
array(
'methods' => WP_REST_Server::EDITABLE,
'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'set_alert' ),
'args' => array(
'key' => array(
'required' => false,
'type' => 'string',
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
),
),
),
array(
'methods' => WP_REST_Server::DELETABLE,
'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
'callback' => array( 'Akismet_REST_API', 'delete_alert' ),
'args' => array(
'key' => array(
'required' => false,
'type' => 'string',
'sanitize_callback' => array( 'Akismet_REST_API', 'sanitize_key' ),
'description' => __( 'A 12-character Akismet API key. Available at akismet.com/get/', 'akismet' ),
),
),
)
) );
register_rest_route(
'akismet/v1',
'/webhook',
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( 'Akismet_REST_API', 'receive_webhook' ),
'permission_callback' => array( 'Akismet_REST_API', 'remote_call_permission_callback' ),
)
);
}
/**
* Get the current Akismet API key.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function get_key( $request = null ) {
return rest_ensure_response( Akismet::get_api_key() );
}
/**
* Set the API key, if possible.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function set_key( $request ) {
if ( defined( 'WPCOM_API_KEY' ) ) {
return rest_ensure_response( new WP_Error( 'hardcoded_key', __( 'This site\'s API key is hardcoded and cannot be changed via the API.', 'akismet' ), array( 'status'=> 409 ) ) );
}
$new_api_key = $request->get_param( 'key' );
if ( ! self::key_is_valid( $new_api_key ) ) {
return rest_ensure_response( new WP_Error( 'invalid_key', __( 'The value provided is not a valid and registered API key.', 'akismet' ), array( 'status' => 400 ) ) );
}
update_option( 'wordpress_api_key', $new_api_key );
return self::get_key();
}
/**
* Unset the API key, if possible.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function delete_key( $request ) {
if ( defined( 'WPCOM_API_KEY' ) ) {
return rest_ensure_response( new WP_Error( 'hardcoded_key', __( 'This site\'s API key is hardcoded and cannot be deleted.', 'akismet' ), array( 'status'=> 409 ) ) );
}
delete_option( 'wordpress_api_key' );
return rest_ensure_response( true );
}
/**
* Get the Akismet settings.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function get_settings( $request = null ) {
return rest_ensure_response( array(
'akismet_strictness' => ( get_option( 'akismet_strictness', '1' ) === '1' ),
'akismet_show_user_comments_approved' => ( get_option( 'akismet_show_user_comments_approved', '1' ) === '1' ),
) );
}
/**
* Update the Akismet settings.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function set_boolean_settings( $request ) {
foreach ( array(
'akismet_strictness',
'akismet_show_user_comments_approved',
) as $setting_key ) {
$setting_value = $request->get_param( $setting_key );
if ( is_null( $setting_value ) ) {
// This setting was not specified.
continue;
}
// From 4.7+, WP core will ensure that these are always boolean
// values because they are registered with 'type' => 'boolean',
// but we need to do this ourselves for prior versions.
$setting_value = Akismet_REST_API::parse_boolean( $setting_value );
update_option( $setting_key, $setting_value ? '1' : '0' );
}
return self::get_settings();
}
/**
* Parse a numeric or string boolean value into a boolean.
*
* @param mixed $value The value to convert into a boolean.
* @return bool The converted value.
*/
public static function parse_boolean( $value ) {
switch ( $value ) {
case true:
case 'true':
case '1':
case 1:
return true;
case false:
case 'false':
case '0':
case 0:
return false;
default:
return (bool) $value;
}
}
/**
* Get the Akismet stats for a given time period.
*
* Possible `interval` values:
* - all
* - 60-days
* - 6-months
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function get_stats( $request ) {
$api_key = Akismet::get_api_key();
$interval = $request->get_param( 'interval' );
$stat_totals = array();
$request_args = array(
'blog' => get_option( 'home' ),
'key' => $api_key,
'from' => $interval,
);
$request_args = apply_filters( 'akismet_request_args', $request_args, 'get-stats' );
$response = Akismet::http_post( Akismet::build_query( $request_args ), 'get-stats' );
if ( ! empty( $response[1] ) ) {
$stat_totals[$interval] = json_decode( $response[1] );
}
return rest_ensure_response( $stat_totals );
}
/**
* Get the current alert code and message. Alert codes are used to notify the site owner
* if there's a problem, like a connection issue between their site and the Akismet API,
* invalid requests being sent, etc.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function get_alert( $request ) {
return rest_ensure_response( array(
'code' => get_option( 'akismet_alert_code' ),
'message' => get_option( 'akismet_alert_msg' ),
) );
}
/**
* Update the current alert code and message by triggering a call to the Akismet server.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function set_alert( $request ) {
delete_option( 'akismet_alert_code' );
delete_option( 'akismet_alert_msg' );
// Make a request so the most recent alert code and message are retrieved.
Akismet::verify_key( Akismet::get_api_key() );
return self::get_alert( $request );
}
/**
* Clear the current alert code and message.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function delete_alert( $request ) {
delete_option( 'akismet_alert_code' );
delete_option( 'akismet_alert_msg' );
return self::get_alert( $request );
}
private static function key_is_valid( $key ) {
$request_args = array(
'key' => $key,
'blog' => get_option( 'home' ),
);
$request_args = apply_filters( 'akismet_request_args', $request_args, 'verify-key' );
$response = Akismet::http_post( Akismet::build_query( $request_args ), 'verify-key' );
if ( $response[1] == 'valid' ) {
return true;
}
return false;
}
public static function privileged_permission_callback() {
return current_user_can( 'manage_options' );
}
/**
* For calls that Akismet.com makes to the site to clear outdated alert codes, use the API key for authorization.
*/
public static function remote_call_permission_callback( $request ) {
$local_key = Akismet::get_api_key();
return $local_key && ( strtolower( $request->get_param( 'key' ) ) === strtolower( $local_key ) );
}
public static function sanitize_interval( $interval, $request, $param ) {
$interval = trim( $interval );
$valid_intervals = array( '60-days', '6-months', 'all', );
if ( ! in_array( $interval, $valid_intervals ) ) {
$interval = 'all';
}
return $interval;
}
public static function sanitize_key( $key, $request, $param ) {
return trim( $key );
}
/**
* Process a webhook request from the Akismet servers.
*
* @param WP_REST_Request $request
* @return WP_Error|WP_REST_Response
*/
public static function receive_webhook( $request ) {
Akismet::log( array( 'Webhook request received', $request->get_body() ) );
/**
* The request body should look like this:
* array(
* 'key' => '1234567890abcd',
* 'endpoint' => '[comment-check|submit-ham|submit-spam]',
* 'comments' => array(
* array(
* 'guid' => '[...]',
* 'result' => '[true|false]',
* 'comment_author' => '[...]',
* [...]
* ),
* array(
* 'guid' => '[...]',
* [...],
* ),
* [...]
* )
* )
*
* Multiple comments can be included in each request, and the only truly required
* field for each is the guid, although it would be friendly to include also
* comment_post_ID, comment_parent, and comment_author_email, if possible to make
* searching easier.
*/
// The response will include statuses for the result of each comment that was supplied.
$response = array(
'comments' => array(),
);
$endpoint = $request->get_param( 'endpoint' );
switch ( $endpoint ) {
case 'comment-check':
$webhook_comments = $request->get_param( 'comments' );
if ( ! is_array( $webhook_comments ) ) {
return rest_ensure_response( new WP_Error( 'malformed_request', __( 'The \'comments\' parameter must be an array.', 'akismet' ), array( 'status' => 400 ) ) );
}
foreach ( $webhook_comments as $webhook_comment ) {
$guid = $webhook_comment['guid'];
if ( ! $guid ) {
// Without the GUID, we can't be sure that we're matching the right comment.
// We'll make it a rule that any comment without a GUID is ignored intentionally.
continue;
}
// Search on the fields that are indexed in the comments table, plus the GUID.
// The GUID is the only thing we really need to search on, but comment_meta
// is not indexed in a useful way if there are many many comments. This
// should help narrow it down first.
$queryable_fields = array(
'comment_post_ID' => 'post_id',
'comment_parent' => 'parent',
'comment_author_email' => 'author_email',
);
$query_args = array();
$query_args['status'] = 'any';
$query_args['meta_key'] = 'akismet_guid';
$query_args['meta_value'] = $guid;
foreach ( $queryable_fields as $queryable_field => $wp_comment_query_field ) {
if ( isset( $webhook_comment[ $queryable_field ] ) ) {
$query_args[ $wp_comment_query_field ] = $webhook_comment[ $queryable_field ];
}
}
$comments_query = new WP_Comment_Query( $query_args );
$comments = $comments_query->comments;
if ( ! $comments ) {
// Unexpected, although the comment could have been deleted since being submitted.
Akismet::log( 'Webhook failed: no matching comment found.' );
$response['comments'][ $guid ] = array( 'status' => 'error', 'message' => __( 'Could not find matching comment.', 'akismet' ) );
continue;
} if ( count( $comments ) > 1 ) {
// Two comments shouldn't be able to match the same GUID.
Akismet::log( 'Webhook failed: multiple matching comments found.', $comments );
$response['comments'][ $guid ] = array( 'status' => 'error', 'message' => __( 'Multiple comments matched request.', 'akismet' ) );
continue;
} else {
// We have one single match, as hoped for.
Akismet::log( 'Found matching comment.', $comments );
$current_status = wp_get_comment_status( $comments[0] );
$result = $webhook_comment['result'];
if ( 'true' == $result ) {
Akismet::log( 'Comment should be spam' );
// The comment should be classified as spam.
if ( 'spam' != $current_status ) {
// The comment is not classified as spam. If Akismet was the one to act on it, move it to spam.
if ( Akismet::last_comment_status_change_came_from_akismet( $comments[0]->comment_ID ) ) {
Akismet::log( 'Comment is not spam; marking as spam.' );
wp_spam_comment( $comments[0] );
Akismet::update_comment_history( $comments[0]->comment_ID, '', 'webhook-spam' );
} else {
Akismet::log( 'Comment is not spam, but it has already been manually handled by some other process.' );
Akismet::update_comment_history( $comments[0]->comment_ID, '', 'webhook-spam-noaction' );
}
}
} else if ( 'false' == $result ) {
Akismet::log( 'Comment should be ham' );
// The comment should be classified as ham.
if ( 'spam' == $current_status ) {
Akismet::log( 'Comment is spam.' );
// The comment is classified as spam. If Akismet was the one to label it as spam, unspam it.
if ( Akismet::last_comment_status_change_came_from_akismet( $comments[0]->comment_ID ) ) {
Akismet::log( 'Akismet marked it as spam; unspamming.' );
wp_unspam_comment( $comments[0] );
akismet::update_comment_history( $comments[0]->comment_ID, '', 'webhook-ham' );
} else {
Akismet::log( 'Comment is not spam, but it has already been manually handled by some other process.' );
Akismet::update_comment_history( $comments[0]->comment_ID, '', 'webhook-ham-noaction' );
}
}
}
$response['comments'][ $guid ] = array( 'status' => 'success' );
}
}
break;
case 'submit-ham':
case 'submit-spam':
// Nothing to do for submit-ham or submit-spam.
break;
default:
// Unsupported endpoint.
break;
}
/**
* Allow plugins to do things with a successfully processed webhook request, like logging.
*
* @since 5.3.2
*
* @param WP_REST_Request $request The REST request object.
*/
do_action( 'akismet_webhook_received', $request );
Akismet::log( 'Done processing webhook.' );
return rest_ensure_response( $response );
}
}
_inc/rtl/akismet-rtl.css 0000644 00000030313 14744621672 0011240 0 ustar 00 /* This file was automatically generated on Aug 25 2023 03:41:43 */
.wp-admin.jetpack_page_akismet-key-config, .wp-admin.settings_page_akismet-key-config {
background-color:#f3f6f8;
}
#submitted-on {
position: relative;
}
#the-comment-list .author .akismet-user-comment-count {
display: inline;
}
#the-comment-list .author a span {
text-decoration: none;
color: #999;
}
#the-comment-list .author a span.akismet-span-link {
text-decoration: inherit;
color: inherit;
}
#the-comment-list .akismet_remove_url {
margin-right: 3px;
color: #999;
padding: 2px 0 2px 3px;
}
#the-comment-list .akismet_remove_url:hover {
color: #A7301F;
font-weight: bold;
padding: 2px 0 2px 2px;
}
#dashboard_recent_comments .akismet-status {
display: none;
}
.akismet-status {
float: left;
}
.akismet-status a {
color: #AAA;
font-style: italic;
}
table.comments td.comment p a {
text-decoration: underline;
}
table.comments td.comment p a:after {
content: attr(href);
color: #aaa;
display: inline-block; /* Show the URL without the link's underline extending under it. */
padding: 0 1ex; /* Because it's inline block, we can't just use spaces in the content: attribute to separate it from the link text. */
}
.mshot-arrow {
width: 0;
height: 0;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-left: 10px solid #5C5C5C;
position: absolute;
right: -6px;
top: 91px;
}
.mshot-container {
background: #5C5C5C;
position: absolute;
top: -94px;
padding: 7px;
width: 450px;
height: 338px;
z-index: 20000;
-moz-border-radius: 6px;
border-radius: 6px;
-webkit-border-radius: 6px;
}
.akismet-mshot {
position: absolute;
z-index: 100;
}
.akismet-mshot .mshot-image {
margin: 0;
height: 338px;
width: 450px;
}
.checkforspam {
display: inline-block !important;
}
.checkforspam-spinner {
display: inline-block;
margin-top: 7px;
}
.akismet-right {
float: left;
}
.akismet-card .akismet-right {
margin: 1em 0;
}
.akismet-alert-text {
color: #dd3d36;
font-weight: bold;
font-size: 120%;
margin-top: .5rem;
}
.akismet-new-snapshot {
margin-top: 1em;
text-align: center;
background: #fff;
}
.akismet-new-snapshot h3 {
background: #f5f5f5;
color: #888;
font-size: 11px;
margin: 0;
}
.akismet-new-snapshot ul li {
color: #999;
font-size: 11px;
text-transform: uppercase;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
}
.akismet-new-snapshot__number {
display: block;
font-size: 32px;
font-weight: lighter;
line-height: 1.5em;
}
.akismet-settings th:first-child {
vertical-align: top;
padding-top: 15px;
}
.akismet-settings th.akismet-api-key {
vertical-align: middle;
padding-top: 0;
}
.akismet-settings span.akismet-note{
float: right;
padding-right: 23px;
font-size: 75%;
margin-top: -10px;
}
/**
* For the activation notice on the plugins page.
*/
#akismet_setup_prompt {
background: none;
border: none;
margin: 0;
padding: 0;
width: 100%;
}
.akismet_activate {
border: 1px solid #4F800D;
padding: 5px;
margin: 15px 0;
background: #83AF24;
background-image: -webkit-gradient(linear, 0% 0, 80% 100%, from(#83AF24), to(#4F800D));
background-image: -moz-linear-gradient(-80% 100% 120deg, #4F800D, #83AF24);
-moz-border-radius: 3px;
border-radius: 3px;
-webkit-border-radius: 3px;
position: relative;
overflow: hidden;
}
.akismet_activate .aa_a {
position: absolute;
top: -5px;
left: 10px;
font-size: 140px;
color: #769F33;
font-family: Georgia, "Times New Roman", Times, serif;
}
.akismet_activate .aa_button {
font-weight: bold;
border: 1px solid #029DD6;
border-top: 1px solid #06B9FD;
font-size: 15px;
text-align: center;
padding: 9px 0 8px 0;
color: #FFF;
background: #029DD6;
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
width: 100%;
cursor: pointer;
margin: 0;
}
.akismet_activate .aa_button:hover {
text-decoration: none !important;
border: 1px solid #029DD6;
border-bottom: 1px solid #00A8EF;
font-size: 15px;
text-align: center;
padding: 9px 0 8px 0;
color: #F0F8FB;
background: #0079B1;
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#0079B1), to(#0092BF));
background-image: -moz-linear-gradient(0% 100% 90deg, #0092BF, #0079B1);
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
}
.akismet_activate .aa_button_border {
border: 1px solid #006699;
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
background: #029DD6;
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
}
.akismet_activate .aa_button_container {
box-sizing: border-box;
display: inline-block;
background: #DEF1B8;
padding: 5px;
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
width: 266px;
}
.akismet_activate .aa_description {
position: absolute;
top: 22px;
right: 285px;
margin-right: 25px;
color: #E5F2B1;
font-size: 15px;
}
.akismet_activate .aa_description strong {
color: #FFF;
font-weight: normal;
}
@media (max-width: 550px) {
.akismet_activate .aa_a {
display: none;
}
.akismet_activate .aa_button_container {
width: 100%;
}
}
@media (max-width: 782px) {
.akismet_activate {
min-width: 0;
}
}
@media (max-width: 850px) {
#akismet_setup_prompt .aa_description {
display: none;
}
.akismet_activate {
min-width: 0;
}
}
.jetpack_page_akismet-key-config #wpcontent, .settings_page_akismet-key-config #wpcontent {
padding-right: 0;
}
.akismet-masthead {
background-color:#fff;
text-align:center;
box-shadow:0 1px 0 rgba(200,215,225,0.5),0 1px 2px #e9eff3
}
@media (max-width: 45rem) {
.akismet-masthead {
padding:0 1.25rem
}
}
.akismet-masthead__inside-container {
padding:.375rem 0;
margin:0 auto;
width:100%;
max-width:45rem;
text-align: right;
}
.akismet-masthead__logo-container {
padding:.3125rem 0 0
}
.akismet-masthead__logo-link {
display:inline-block;
outline:none;
vertical-align:middle
}
.akismet-masthead__logo-link:focus {
line-height:0;
box-shadow:0 0 0 2px #78dcfa
}
.akismet-masthead__logo-link+code {
margin:0 10px;
padding:5px 9px;
border-radius:2px;
background:#e6ecf1;
color:#647a88
}
.akismet-masthead__links {
display:-ms-flexbox;
display:flex;
-ms-flex-flow:row wrap;
flex-flow:row wrap;
-ms-flex:2 50%;
flex:2 50%;
-ms-flex-pack:end;
justify-content:flex-end;
margin:0
}
@media (max-width: 480px) {
.akismet-masthead__links {
padding-left:.625rem
}
}
.akismet-masthead__link-li {
margin:0;
padding:0
}
.akismet-masthead__link {
font-style:normal;
color:#0087be;
padding:.625rem;
display:inline-block
}
.akismet-masthead__link:visited {
color:#0087be
}
.akismet-masthead__link:active,.akismet-masthead__link:hover {
color:#00aadc
}
.akismet-masthead__link:hover {
text-decoration:underline
}
.akismet-masthead__link .dashicons {
display:none
}
@media (max-width: 480px) {
.akismet-masthead__link:hover,.akismet-masthead__link:active {
text-decoration:none
}
.akismet-masthead__link .dashicons {
display:block;
font-size:1.75rem
}
.akismet-masthead__link span+span {
display:none
}
}
.akismet-masthead__link-li:last-of-type .akismet-masthead__link {
padding-left:0
}
.akismet-lower {
margin: 0 auto;
text-align: right;
max-width: 45rem;
padding: 1.5rem;
}
.akismet-lower .notice {
margin-bottom: 2rem;
}
.akismet-card {
margin-top: 1rem;
margin-bottom: 0;
position: relative;
box-sizing: border-box;
background: white;
}
.akismet-card:after, .akismet-card .inside:after, .akismet-masthead__logo-container:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.akismet-card .inside {
padding: 1.5rem;
padding-top: 1rem;
}
.akismet-card .akismet-card-actions {
margin-top: 1rem;
}
.jetpack_page_akismet-key-config .update-nag, .settings_page_akismet-key-config .update-nag {
display: none;
}
.akismet-masthead .akismet-right {
line-height: 2.125rem;
font-size: 0.9rem;
}
.akismet-box {
box-sizing: border-box;
background: white;
border: 1px solid rgba(200, 215, 225, 0.5);
}
.akismet-box h2, .akismet-box h3 {
padding: 1.5rem 1.5rem .5rem 1.5rem;
margin: 0;
}
.akismet-box p {
padding: 0 1.5rem 1.5rem 1.5rem;
margin: 0;
}
.akismet-jetpack-email {
font-style: oblique;
}
.akismet-jetpack-gravatar {
padding: 0 1.5rem 0 0;
float: right;
margin-left: 1rem;
width: 54px;
height: 54px;
}
.akismet-box p:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.akismet-box .akismet-right {
padding-left: 1.5rem;
}
.akismet-boxes .akismet-box {
margin-bottom: 0;
padding: 0;
margin-top: -1px;
}
.akismet-boxes .akismet-box:last-child {
margin-bottom: 1.5rem;
}
.akismet-boxes .akismet-box:first-child {
margin-top: 1.5rem;
}
.akismet-box-header {
max-width: 700px;
margin: 0 auto 40px auto;
line-height: 1.5;
}
.akismet-box-header h2 {
margin: 1.5rem 10% 0;
font-size: 1.375rem;
font-weight: 700;
color: #000;
}
.akismet-box .centered {
text-align: center;
}
.akismet-box .akismet-toggles {
margin: 3rem 0;
}
.akismet-box .akismet-ak-connect, .akismet-box .toggle-jp-connect {
display: none;
}
.akismet-button, .akismet-button:hover, .akismet-button:visited {
background: white;
border-color: #c8d7e1;
border-style: solid;
border-width: 1px 1px 2px;
color: #2e4453;
cursor: pointer;
display: inline-block;
margin: 0;
outline: 0;
overflow: hidden;
font-size: 14px;
font-weight: 500;
text-overflow: ellipsis;
text-decoration: none;
vertical-align: top;
box-sizing: border-box;
font-size: 14px;
line-height: 21px;
border-radius: 4px;
padding: 7px 14px 9px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.akismet-button:hover {
border-color: #a8bece;
}
.akismet-button:active {
border-width: 2px 1px 1px;
}
.akismet-is-primary, .akismet-is-primary:hover, .akismet-is-primary:visited {
background: #00aadc;
border-color: #0087be;
color: white;
}
.akismet-is-primary:hover, .akismet-is-primary:focus {
border-color: #005082;
}
.akismet-is-primary:hover {
border-color: #005082;
}
.akismet-section-header {
position: relative;
margin: 0 auto 0.625rem auto;
padding: 1rem;
box-sizing: border-box;
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
background: #ffffff;
width: 100%;
padding-top: 0.6875rem;
padding-bottom: 0.6875rem;
display: flex;
}
.akismet-section-header__label {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
-ms-flex-positive: 1;
flex-grow: 1;
line-height: 1.75rem;
position: relative;
font-size: 0.875rem;
color: #4f748e;
}
.akismet-section-header__actions {
line-height: 1.75rem;
}
.akismet-setup-instructions {
text-align: center;
}
.akismet-setup-instructions form {
padding-bottom: 1.5rem;
}
div.error.akismet-usage-limit-alert {
padding: 25px 15px 25px 45px;
display: flex;
align-items: center;
}
#akismet-plugin-container .akismet-usage-limit-alert {
margin: 0 auto 0.625rem auto;
box-sizing: border-box;
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
border: none;
border-right: 4px solid #d63638;
}
.akismet-usage-limit-alert .akismet-usage-limit-logo {
width: 38px;
min-width: 38px;
height: 38px;
border-radius: 20px;
margin-left: 18px;
background: black;
position: relative;
}
.akismet-usage-limit-alert .akismet-usage-limit-logo img {
position: absolute;
width: 22px;
right: 8px;
top: 10px;
}
.akismet-usage-limit-alert .akismet-usage-limit-text {
flex-grow: 1;
margin-left: 18px;
}
.akismet-usage-limit-alert h3 {
margin: 0;
}
.akismet-usage-limit-alert .akismet-usage-limit-cta {
text-align: left;
}
#akismet-plugin-container .akismet-usage-limit-cta a {
color: #d63638;
}
@media (max-width: 550px) {
div.error.akismet-usage-limit-alert {
display: block;
}
.akismet-usage-limit-alert .akismet-usage-limit-logo,
.akismet-usage-limit-alert .akismet-usage-limit-text {
margin-bottom: 15px;
}
.akismet-usage-limit-alert .akismet-usage-limit-cta {
text-align: right;
}
} _inc/rtl/akismet-admin-rtl.css 0000644 00000017062 14744621672 0012334 0 ustar 00 /* This file was automatically generated on Nov 20 2023 03:10:42 */
#akismet-plugin-container {
background-color: var(--akismet-color-light-grey);
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen-Sans', 'Ubuntu', 'Cantarell', 'Helvetica Neue', sans-serif;
--akismet-color-charcoal: #272635;
--akismet-color-light-grey: #f6f7f7;
--akismet-color-mid-grey: #a7aaad;
--akismet-color-dark-grey: #646970;
--akismet-color-grey-80: #2c3338;
--akismet-color-grey-100: #101517;
--akismet-color-white: #fff;
--akismet-color-mid-green: #357b49;
--akismet-color-mid-red: #e82c3f;
--akismet-color-light-blue: #256eff;
--akismet-color-notice-light-green: #dbf0e1;
--akismet-color-notice-dark-green: #69bf82;
--akismet-color-notice-light-red: #ffdbde;
--akismet-color-notice-dark-red: #ff6676;
}
#akismet-plugin-container a {
color: var(--akismet-color-mid-green);
}
#akismet-plugin-container button:focus-visible,
#akismet-plugin-container input:focus-visible {
border: 0;
box-shadow: none;
outline: 2px solid var(--akismet-color-light-blue);
}
.akismet-masthead {
box-shadow: none;
}
.akismet-masthead__logo {
margin: 20px 0;
}
.akismet-section-header {
box-shadow: none;
margin-bottom: 0;
}
.akismet-section-header__label {
color: var(--akismet-color-charcoal);
font-weight: 600;
}
.akismet-button, .akismet-button:hover {
background-color: var(--akismet-color-mid-green);
border: 0;
color: #fff;
}
/* Need this specificity to override the existing header rule */
.akismet-new-snapshot h3.akismet-new-snapshot__header {
background: none;
font-size: 13px;
color: var(--akismet-color-charcoal);
text-align: right;
text-transform: none;
}
.akismet-new-snapshot .akismet-new-snapshot__number {
color: var(--akismet-color-charcoal);
letter-spacing: -1px;
text-align: right;
}
.akismet-new-snapshot li.akismet-new-snapshot__item {
color: var(--akismet-color-dark-grey);
font-size: 13px;
text-align: right;
text-transform: none;
}
.akismet-masthead__logo-link {
min-height: 50px;
}
.akismet-masthead__back-link-container {
margin-top: 16px;
margin-bottom: 2px;
}
/* Need this specificity to override the existing link rule */
#akismet-plugin-container a.akismet-masthead__back-link {
background-image: url(../img/arrow-left.svg);
background-position: right;
background-repeat: no-repeat;
background-size: 16px;
color: var(--akismet-color-charcoal);
font-weight: 400;
padding-right: 20px;
text-decoration: none;
}
#akismet-plugin-container a.akismet-masthead__back-link:hover {
text-decoration: underline;
}
.akismet-new-snapshot__item {
border-top: 1px solid var(--akismet-color-light-grey);
border-right: 1px solid var(--akismet-color-light-grey);
padding: 1em;
}
.akismet-new-snapshot li:first-child {
border-right: none;
}
.akismet-new-snapshot__list {
display: flex;
margin-bottom: 0;
}
.akismet-new-snapshot__item {
flex: 1 0 33.33%;
margin-bottom: 0;
padding-right: 1.5em;
padding-left: 1.5em;
}
.akismet-new-snapshot__chart {
padding: 1em;
}
.akismet-box {
border: 0;
}
.akismet-box,
.akismet-card {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06), 0 0 2px rgba(0, 0, 0, 0.16);
border-radius: 8px;
overflow: hidden;
}
.akismet-card {
margin: 32px auto 0 auto;
}
.akismet-lower {
padding-top: 0;
}
.akismet-lower .inside {
padding: 0;
}
.akismet-section-header__label {
margin: 0;
}
.akismet-settings__row {
border-bottom: 1px solid var(--akismet-color-light-grey);
display: block;
padding: 1em 1.5em;
}
.akismet-settings__row-input {
margin-right: auto;
}
.akismet-settings__row-title {
font-weight: 500;
font-size: 1em;
margin: 0;
margin-bottom: 1em;
}
.akismet-settings__row-description {
margin-top: 0.5em;
}
.akismet-card-actions {
display: flex;
justify-content: flex-end;
padding: 1em;
}
.akismet-card-actions__secondary-action {
align-self: center;
margin-left: auto;
}
.akismet-card-actions__secondary-action a[target="_blank"]::after {
background: url('../img/icon-external.svg') no-repeat;
background-size: contain;
content: "";
display: inline-block;
height: 16px;
margin-right: 5px;
vertical-align: middle;
width: 16px;
}
.akismet-settings__row label {
padding-bottom: 1em;
}
.akismet-settings__row-note {
font-size: 0.9em;
margin-top: 0.4em;
}
.akismet-settings__row input[type="checkbox"],
.akismet-settings__row input[type="radio"] {
accent-color: var(--akismet-color-mid-green);
box-shadow: none;
flex-shrink: 0;
margin: 2px 0 0 0;
}
.akismet-settings__row input[type="checkbox"] {
margin-top: 1px;
vertical-align: top;
-webkit-appearance: checkbox;
}
.akismet-settings__row input[type="radio"] {
-webkit-appearance: radio;
}
/* Fix up misbehaving wp-admin styles in Chrome (from forms and colors stylesheets) */
.akismet-settings__row input[type="checkbox"]:checked:before {
content: '';
}
.akismet-settings__row input[type="radio"]:checked:before {
background: none;
}
.akismet-settings__row input[type="checkbox"]:checked:hover,
.akismet-settings__row input[type="radio"]:checked:hover {
accent-color: var(--akismet-color-mid-green);
}
.akismet-button:disabled {
background-color: var(--akismet-color-mid-grey);
color: var(--akismet-color-white);
cursor: arrow;
}
.akismet-awaiting-stats,
.akismet-account {
padding: 0 1rem 1rem 1rem;
margin: 0;
}
.akismet-account {
padding-bottom: 0;
}
.akismet-account th {
font-weight: 500;
padding-left: 1em;
}
.akismet-account th, .akismet-account td {
padding-bottom: 1em;
}
.akismet-settings__row-input-label {
align-items: center;
display: flex;
}
.akismet-settings__row-label-text {
padding-right: 0.5em;
margin-top: 2px;
}
.akismet-alert {
border-right: 8px solid;
border-radius: 8px;
margin: 20px 0;
padding: 0.2em 1em;
}
.akismet-alert__heading {
font-size: 1em;
}
.akismet-alert.is-good {
background-color: var(--akismet-color-notice-light-green);
border-right-color: var(--akismet-color-notice-dark-green);
}
.akismet-alert.is-neutral {
background-color: var(--akismet-color-white);
border-right-color: var(--akismet-color-dark-grey);
}
.akismet-alert.is-bad {
background-color: var(--akismet-color-notice-light-red);
border-right-color: var(--akismet-color-notice-dark-red);
}
#akismet-plugin-container .akismet-alert.is-good a,
#akismet-plugin-container .akismet-alert.is-bad a {
/* For better contrast - green isn't great */
color: var(--akismet-color-grey-80);
}
/* Setup - API key input */
.akismet-enter-api-key-box {
margin: 1.5rem 0;
}
.akismet-enter-api-key-box__reveal {
background: none;
border: 0;
color: var(--akismet-color-mid-green);
cursor: pointer;
text-decoration: underline;
}
.akismet-enter-api-key-box__form-wrapper {
display: none;
margin-top: 1.5rem;
}
.akismet-enter-api-key-box__input-wrapper {
box-sizing: border-box;
display: flex;
flex-wrap: nowrap;
padding: 0 1.5rem;
width: 100%;
}
.akismet-enter-api-key-box__key-input {
flex-grow: 1;
margin-left: 1rem;
}
h3.akismet-enter-api-key-box__header {
padding-top: 0;
padding-bottom: 1em;
text-align: right;
}
@media screen and (max-width: 782px) {
.akismet-new-snapshot__list {
display: block;
}
.akismet-new-snapshot__number {
float: left;
font-size: 20px;
font-weight: 500;
margin-top: -16px;
}
.akismet-new-snapshot__header {
font-size: 14px;
font-weight: 500;
}
.akismet-new-snapshot__text {
font-size: 12px;
}
.akismet-settings__row input[type="checkbox"],
.akismet-settings__row input[type="radio"] {
height: 24px;
width: 24px;
}
.akismet-settings__row-label-text {
padding-right: 0.8em;
}
.akismet-settings__row input[type="checkbox"],
.akismet-settings__row input[type="radio"] {
margin-top: 0;
}
} _inc/akismet.js 0000644 00000031746 14744621672 0007477 0 ustar 00 jQuery( function ( $ ) {
var mshotRemovalTimer = null;
var mshotRetryTimer = null;
var mshotTries = 0;
var mshotRetryInterval = 1000;
var mshotEnabledLinkSelector = 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a';
var preloadedMshotURLs = [];
$('.akismet-status').each(function () {
var thisId = $(this).attr('commentid');
$(this).prependTo('#comment-' + thisId + ' .column-comment');
});
$('.akismet-user-comment-count').each(function () {
var thisId = $(this).attr('commentid');
$(this).insertAfter('#comment-' + thisId + ' .author strong:first').show();
});
akismet_enable_comment_author_url_removal();
$( '#the-comment-list' ).on( 'click', '.akismet_remove_url', function () {
var thisId = $(this).attr('commentid');
var data = {
action: 'comment_author_deurl',
_wpnonce: WPAkismet.comment_author_url_nonce,
id: thisId
};
$.ajax({
url: ajaxurl,
type: 'POST',
data: data,
beforeSend: function () {
// Removes "x" link
$("a[commentid='"+ thisId +"']").hide();
// Show temp status
$("#author_comment_url_"+ thisId).html( $( ' ' ).text( WPAkismet.strings['Removing...'] ) );
},
success: function (response) {
if (response) {
// Show status/undo link
$("#author_comment_url_"+ thisId)
.attr('cid', thisId)
.addClass('akismet_undo_link_removal')
.html(
$( ' ' ).text( WPAkismet.strings['URL removed'] )
)
.append( ' ' )
.append(
$( ' ' )
.text( WPAkismet.strings['(undo)'] )
.addClass( 'akismet-span-link' )
);
}
}
});
return false;
}).on( 'click', '.akismet_undo_link_removal', function () {
var thisId = $(this).attr('cid');
var thisUrl = $(this).attr('href');
var data = {
action: 'comment_author_reurl',
_wpnonce: WPAkismet.comment_author_url_nonce,
id: thisId,
url: thisUrl
};
$.ajax({
url: ajaxurl,
type: 'POST',
data: data,
beforeSend: function () {
// Show temp status
$("#author_comment_url_"+ thisId).html( $( ' ' ).text( WPAkismet.strings['Re-adding...'] ) );
},
success: function (response) {
if (response) {
// Add "x" link
$("a[commentid='"+ thisId +"']").show();
// Show link. Core strips leading http://, so let's do that too.
$("#author_comment_url_"+ thisId).removeClass('akismet_undo_link_removal').text( thisUrl.replace( /^http:\/\/(www\.)?/ig, '' ) );
}
}
});
return false;
});
// Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
if ( "enable_mshots" in WPAkismet && WPAkismet.enable_mshots ) {
$( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
clearTimeout( mshotRemovalTimer );
if ( $( '.akismet-mshot' ).length > 0 ) {
if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
// The preview is already showing for this link.
return;
}
else {
// A new link is being hovered, so remove the old preview.
$( '.akismet-mshot' ).remove();
}
}
clearTimeout( mshotRetryTimer );
var linkUrl = $( this ).attr( 'href' );
if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
// This preview image was already preloaded, so begin with a retry URL so the user doesn't see the placeholder image for the first second.
mshotTries = 2;
}
else {
mshotTries = 1;
}
var mShot = $( '' );
mShot.data( 'link', this );
mShot.data( 'url', linkUrl );
mShot.find( 'img' ).on( 'load', function () {
$( '.akismet-mshot' ).data( 'pending-request', false );
} );
var offset = $( this ).offset();
mShot.offset( {
left : Math.min( $( window ).width() - 475, offset.left + $( this ).width() + 10 ), // Keep it on the screen if the link is near the edge of the window.
top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
} );
$( 'body' ).append( mShot );
mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
} ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
mshotRemovalTimer = setTimeout( function () {
clearTimeout( mshotRetryTimer );
$( '.akismet-mshot' ).remove();
}, 200 );
} );
var preloadDelayTimer = null;
$( window ).on( 'scroll resize', function () {
clearTimeout( preloadDelayTimer );
preloadDelayTimer = setTimeout( preloadMshotsInViewport, 500 );
} );
preloadMshotsInViewport();
}
/**
* The way mShots works is if there was no screenshot already recently generated for the URL,
* it returns a "loading..." image for the first request. Then, some subsequent request will
* receive the actual screenshot, but it's unknown how long it will take. So, what we do here
* is continually re-request the mShot, waiting a second after every response until we get the
* actual screenshot.
*/
function retryMshotUntilLoaded() {
clearTimeout( mshotRetryTimer );
var imageWidth = $( '.akismet-mshot img' ).get(0).naturalWidth;
if ( imageWidth == 0 ) {
// It hasn't finished loading yet the first time. Check again shortly.
setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
}
else if ( imageWidth == 400 ) {
// It loaded the preview image.
if ( mshotTries == 20 ) {
// Give up if we've requested the mShot 20 times already.
return;
}
if ( ! $( '.akismet-mshot' ).data( 'pending-request' ) ) {
$( '.akismet-mshot' ).data( 'pending-request', true );
mshotTries++;
$( '.akismet-mshot .mshot-image' ).attr( 'src', akismet_mshot_url( $( '.akismet-mshot' ).data( 'url' ), mshotTries ) );
}
mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
}
else {
// All done.
}
}
function preloadMshotsInViewport() {
var windowWidth = $( window ).width();
var windowHeight = $( window ).height();
$( '#the-comment-list' ).find( mshotEnabledLinkSelector ).each( function ( index, element ) {
var linkUrl = $( this ).attr( 'href' );
// Don't attempt to preload an mshot for a single link twice.
if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
// The URL is already preloaded.
return true;
}
if ( typeof element.getBoundingClientRect !== 'function' ) {
// The browser is too old. Return false to stop this preloading entirely.
return false;
}
var rect = element.getBoundingClientRect();
if ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= windowHeight && rect.right <= windowWidth ) {
akismet_preload_mshot( linkUrl );
$( this ).data( 'akismet-mshot-preloaded', true );
}
} );
}
$( '.checkforspam.enable-on-load' ).on( 'click', function( e ) {
if ( $( this ).hasClass( 'ajax-disabled' ) ) {
// Akismet hasn't been configured yet. Allow the user to proceed to the button's link.
return;
}
e.preventDefault();
if ( $( this ).hasClass( 'button-disabled' ) ) {
window.location.href = $( this ).data( 'success-url' ).replace( '__recheck_count__', 0 ).replace( '__spam_count__', 0 );
return;
}
$('.checkforspam').addClass('button-disabled').addClass( 'checking' );
$('.checkforspam-spinner').addClass( 'spinner' ).addClass( 'is-active' );
akismet_check_for_spam(0, 100);
}).removeClass( 'button-disabled' );
var spam_count = 0;
var recheck_count = 0;
function akismet_check_for_spam(offset, limit) {
var check_for_spam_buttons = $( '.checkforspam' );
var nonce = check_for_spam_buttons.data( 'nonce' );
// We show the percentage complete down to one decimal point so even queues with 100k
// pending comments will show some progress pretty quickly.
var percentage_complete = Math.round( ( recheck_count / check_for_spam_buttons.data( 'pending-comment-count' ) ) * 1000 ) / 10;
// Update the progress counter on the "Check for Spam" button.
$( '.checkforspam' ).text( check_for_spam_buttons.data( 'progress-label' ).replace( '%1$s', percentage_complete ) );
$.post(
ajaxurl,
{
'action': 'akismet_recheck_queue',
'offset': offset,
'limit': limit,
'nonce': nonce
},
function(result) {
if ( 'error' in result ) {
// An error is only returned in the case of a missing nonce, so we don't need the actual error message.
window.location.href = check_for_spam_buttons.data( 'failure-url' );
return;
}
recheck_count += result.counts.processed;
spam_count += result.counts.spam;
if (result.counts.processed < limit) {
window.location.href = check_for_spam_buttons.data( 'success-url' ).replace( '__recheck_count__', recheck_count ).replace( '__spam_count__', spam_count );
}
else {
// Account for comments that were caught as spam and moved out of the queue.
akismet_check_for_spam(offset + limit - result.counts.spam, limit);
}
}
);
}
if ( "start_recheck" in WPAkismet && WPAkismet.start_recheck ) {
$( '.checkforspam' ).click();
}
if ( typeof MutationObserver !== 'undefined' ) {
// Dynamically add the "X" next the the author URL links when a comment is quick-edited.
var comment_list_container = document.getElementById( 'the-comment-list' );
if ( comment_list_container ) {
var observer = new MutationObserver( function ( mutations ) {
for ( var i = 0, _len = mutations.length; i < _len; i++ ) {
if ( mutations[i].addedNodes.length > 0 ) {
akismet_enable_comment_author_url_removal();
// Once we know that we'll have to check for new author links, skip the rest of the mutations.
break;
}
}
} );
observer.observe( comment_list_container, { attributes: true, childList: true, characterData: true } );
}
}
function akismet_enable_comment_author_url_removal() {
$( '#the-comment-list' )
.find( 'tr.comment, tr[id ^= "comment-"]' )
.find( '.column-author a[href^="http"]:first' ) // Ignore mailto: links, which would be the comment author's email.
.each(function () {
if ( $( this ).parent().find( '.akismet_remove_url' ).length > 0 ) {
return;
}
var linkHref = $(this).attr( 'href' );
// Ignore any links to the current domain, which are diagnostic tools, like the IP address link
// or any other links another plugin might add.
var currentHostParts = document.location.href.split( '/' );
var currentHost = currentHostParts[0] + '//' + currentHostParts[2] + '/';
if ( linkHref.indexOf( currentHost ) != 0 ) {
var thisCommentId = $(this).parents('tr:first').attr('id').split("-");
$(this)
.attr("id", "author_comment_url_"+ thisCommentId[1])
.after(
$( 'x ' )
.attr( 'commentid', thisCommentId[1] )
.attr( 'title', WPAkismet.strings['Remove this URL'] )
);
}
});
}
/**
* Generate an mShot URL if given a link URL.
*
* @param string linkUrl
* @param int retry If retrying a request, the number of the retry.
* @return string The mShot URL;
*/
function akismet_mshot_url( linkUrl, retry ) {
var mshotUrl = '//s0.wp.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
if ( retry > 1 ) {
mshotUrl += '&r=' + encodeURIComponent( retry );
}
mshotUrl += '&source=akismet';
return mshotUrl;
}
/**
* Begin loading an mShot preview of a link.
*
* @param string linkUrl
*/
function akismet_preload_mshot( linkUrl ) {
var img = new Image();
img.src = akismet_mshot_url( linkUrl );
preloadedMshotURLs.push( linkUrl );
}
$( '.akismet-could-be-primary' ).each( function () {
var form = $( this ).closest( 'form' );
form.data( 'initial-state', form.serialize() );
form.on( 'change keyup', function () {
var self = $( this );
var submit_button = self.find( '.akismet-could-be-primary' );
if ( self.serialize() != self.data( 'initial-state' ) ) {
submit_button.addClass( 'akismet-is-primary' );
}
else {
submit_button.removeClass( 'akismet-is-primary' );
}
} );
} );
/**
* Shows the Enter API key form
*/
$( '.akismet-enter-api-key-box__reveal' ).on( 'click', function ( e ) {
e.preventDefault();
var div = $( '.akismet-enter-api-key-box__form-wrapper' );
div.show( 500 );
div.find( 'input[name=key]' ).focus();
$( this ).hide();
} );
/**
* Hides the Connect with Jetpack form | Shows the Activate Akismet Account form
*/
$( 'a.toggle-ak-connect' ).on( 'click', function ( e ) {
e.preventDefault();
$( '.akismet-ak-connect' ).slideToggle('slow');
$( 'a.toggle-ak-connect' ).hide();
$( '.akismet-jp-connect' ).hide();
$( 'a.toggle-jp-connect' ).show();
} );
/**
* Shows the Connect with Jetpack form | Hides the Activate Akismet Account form
*/
$( 'a.toggle-jp-connect' ).on( 'click', function ( e ) {
e.preventDefault();
$( '.akismet-jp-connect' ).slideToggle('slow');
$( 'a.toggle-jp-connect' ).hide();
$( '.akismet-ak-connect' ).hide();
$( 'a.toggle-ak-connect' ).show();
} );
});
_inc/akismet.css 0000644 00000030230 14744621672 0007636 0 ustar 00 .wp-admin.jetpack_page_akismet-key-config, .wp-admin.settings_page_akismet-key-config {
background-color:#f3f6f8;
}
#submitted-on {
position: relative;
}
#the-comment-list .author .akismet-user-comment-count {
display: inline;
}
#the-comment-list .author a span {
text-decoration: none;
color: #999;
}
#the-comment-list .author a span.akismet-span-link {
text-decoration: inherit;
color: inherit;
}
#the-comment-list .akismet_remove_url {
margin-left: 3px;
color: #999;
padding: 2px 3px 2px 0;
}
#the-comment-list .akismet_remove_url:hover {
color: #A7301F;
font-weight: bold;
padding: 2px 2px 2px 0;
}
#dashboard_recent_comments .akismet-status {
display: none;
}
.akismet-status {
float: right;
}
.akismet-status a {
color: #AAA;
font-style: italic;
}
table.comments td.comment p a {
text-decoration: underline;
}
table.comments td.comment p a:after {
content: attr(href);
color: #aaa;
display: inline-block; /* Show the URL without the link's underline extending under it. */
padding: 0 1ex; /* Because it's inline block, we can't just use spaces in the content: attribute to separate it from the link text. */
}
.mshot-arrow {
width: 0;
height: 0;
border-top: 10px solid transparent;
border-bottom: 10px solid transparent;
border-right: 10px solid #5C5C5C;
position: absolute;
left: -6px;
top: 91px;
}
.mshot-container {
background: #5C5C5C;
position: absolute;
top: -94px;
padding: 7px;
width: 450px;
height: 338px;
z-index: 20000;
-moz-border-radius: 6px;
border-radius: 6px;
-webkit-border-radius: 6px;
}
.akismet-mshot {
position: absolute;
z-index: 100;
}
.akismet-mshot .mshot-image {
margin: 0;
height: 338px;
width: 450px;
}
.checkforspam {
display: inline-block !important;
}
.checkforspam-spinner {
display: inline-block;
margin-top: 7px;
}
.akismet-right {
float: right;
}
.akismet-card .akismet-right {
margin: 1em 0;
}
.akismet-alert-text {
color: #dd3d36;
font-weight: bold;
font-size: 120%;
margin-top: .5rem;
}
.akismet-new-snapshot {
margin-top: 1em;
text-align: center;
background: #fff;
}
.akismet-new-snapshot h3 {
background: #f5f5f5;
color: #888;
font-size: 11px;
margin: 0;
}
.akismet-new-snapshot ul li {
color: #999;
font-size: 11px;
text-transform: uppercase;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
}
.akismet-new-snapshot__number {
display: block;
font-size: 32px;
font-weight: lighter;
line-height: 1.5em;
}
.akismet-settings th:first-child {
vertical-align: top;
padding-top: 15px;
}
.akismet-settings th.akismet-api-key {
vertical-align: middle;
padding-top: 0;
}
.akismet-settings span.akismet-note{
float: left;
padding-left: 23px;
font-size: 75%;
margin-top: -10px;
}
/**
* For the activation notice on the plugins page.
*/
#akismet_setup_prompt {
background: none;
border: none;
margin: 0;
padding: 0;
width: 100%;
}
.akismet_activate {
border: 1px solid #4F800D;
padding: 5px;
margin: 15px 0;
background: #83AF24;
background-image: -webkit-gradient(linear, 0% 0, 80% 100%, from(#83AF24), to(#4F800D));
background-image: -moz-linear-gradient(80% 100% 120deg, #4F800D, #83AF24);
-moz-border-radius: 3px;
border-radius: 3px;
-webkit-border-radius: 3px;
position: relative;
overflow: hidden;
}
.akismet_activate .aa_a {
position: absolute;
top: -5px;
right: 10px;
font-size: 140px;
color: #769F33;
font-family: Georgia, "Times New Roman", Times, serif;
}
.akismet_activate .aa_button {
font-weight: bold;
border: 1px solid #029DD6;
border-top: 1px solid #06B9FD;
font-size: 15px;
text-align: center;
padding: 9px 0 8px 0;
color: #FFF;
background: #029DD6;
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
width: 100%;
cursor: pointer;
margin: 0;
}
.akismet_activate .aa_button:hover {
text-decoration: none !important;
border: 1px solid #029DD6;
border-bottom: 1px solid #00A8EF;
font-size: 15px;
text-align: center;
padding: 9px 0 8px 0;
color: #F0F8FB;
background: #0079B1;
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#0079B1), to(#0092BF));
background-image: -moz-linear-gradient(0% 100% 90deg, #0092BF, #0079B1);
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
}
.akismet_activate .aa_button_border {
border: 1px solid #006699;
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
background: #029DD6;
background-image: -webkit-gradient(linear, 0% 0, 0% 100%, from(#029DD6), to(#0079B1));
background-image: -moz-linear-gradient(0% 100% 90deg, #0079B1, #029DD6);
}
.akismet_activate .aa_button_container {
box-sizing: border-box;
display: inline-block;
background: #DEF1B8;
padding: 5px;
-moz-border-radius: 2px;
border-radius: 2px;
-webkit-border-radius: 2px;
width: 266px;
}
.akismet_activate .aa_description {
position: absolute;
top: 22px;
left: 285px;
margin-left: 25px;
color: #E5F2B1;
font-size: 15px;
}
.akismet_activate .aa_description strong {
color: #FFF;
font-weight: normal;
}
@media (max-width: 550px) {
.akismet_activate .aa_a {
display: none;
}
.akismet_activate .aa_button_container {
width: 100%;
}
}
@media (max-width: 782px) {
.akismet_activate {
min-width: 0;
}
}
@media (max-width: 850px) {
#akismet_setup_prompt .aa_description {
display: none;
}
.akismet_activate {
min-width: 0;
}
}
.jetpack_page_akismet-key-config #wpcontent, .settings_page_akismet-key-config #wpcontent {
padding-left: 0;
}
.akismet-masthead {
background-color:#fff;
text-align:center;
box-shadow:0 1px 0 rgba(200,215,225,0.5),0 1px 2px #e9eff3
}
@media (max-width: 45rem) {
.akismet-masthead {
padding:0 1.25rem
}
}
.akismet-masthead__inside-container {
padding:.375rem 0;
margin:0 auto;
width:100%;
max-width:45rem;
text-align: left;
}
.akismet-masthead__logo-container {
padding:.3125rem 0 0
}
.akismet-masthead__logo-link {
display:inline-block;
outline:none;
vertical-align:middle
}
.akismet-masthead__logo-link:focus {
line-height:0;
box-shadow:0 0 0 2px #78dcfa
}
.akismet-masthead__logo-link+code {
margin:0 10px;
padding:5px 9px;
border-radius:2px;
background:#e6ecf1;
color:#647a88
}
.akismet-masthead__links {
display:-ms-flexbox;
display:flex;
-ms-flex-flow:row wrap;
flex-flow:row wrap;
-ms-flex:2 50%;
flex:2 50%;
-ms-flex-pack:end;
justify-content:flex-end;
margin:0
}
@media (max-width: 480px) {
.akismet-masthead__links {
padding-right:.625rem
}
}
.akismet-masthead__link-li {
margin:0;
padding:0
}
.akismet-masthead__link {
font-style:normal;
color:#0087be;
padding:.625rem;
display:inline-block
}
.akismet-masthead__link:visited {
color:#0087be
}
.akismet-masthead__link:active,.akismet-masthead__link:hover {
color:#00aadc
}
.akismet-masthead__link:hover {
text-decoration:underline
}
.akismet-masthead__link .dashicons {
display:none
}
@media (max-width: 480px) {
.akismet-masthead__link:hover,.akismet-masthead__link:active {
text-decoration:none
}
.akismet-masthead__link .dashicons {
display:block;
font-size:1.75rem
}
.akismet-masthead__link span+span {
display:none
}
}
.akismet-masthead__link-li:last-of-type .akismet-masthead__link {
padding-right:0
}
.akismet-lower {
margin: 0 auto;
text-align: left;
max-width: 45rem;
padding: 1.5rem;
}
.akismet-lower .notice {
margin-bottom: 2rem;
}
.akismet-card {
margin-top: 1rem;
margin-bottom: 0;
position: relative;
box-sizing: border-box;
background: white;
}
.akismet-card:after, .akismet-card .inside:after, .akismet-masthead__logo-container:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.akismet-card .inside {
padding: 1.5rem;
padding-top: 1rem;
}
.akismet-card .akismet-card-actions {
margin-top: 1rem;
}
.jetpack_page_akismet-key-config .update-nag, .settings_page_akismet-key-config .update-nag {
display: none;
}
.akismet-masthead .akismet-right {
line-height: 2.125rem;
font-size: 0.9rem;
}
.akismet-box {
box-sizing: border-box;
background: white;
border: 1px solid rgba(200, 215, 225, 0.5);
}
.akismet-box h2, .akismet-box h3 {
padding: 1.5rem 1.5rem .5rem 1.5rem;
margin: 0;
}
.akismet-box p {
padding: 0 1.5rem 1.5rem 1.5rem;
margin: 0;
}
.akismet-jetpack-email {
font-style: oblique;
}
.akismet-jetpack-gravatar {
padding: 0 0 0 1.5rem;
float: left;
margin-right: 1rem;
width: 54px;
height: 54px;
}
.akismet-box p:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.akismet-box .akismet-right {
padding-right: 1.5rem;
}
.akismet-boxes .akismet-box {
margin-bottom: 0;
padding: 0;
margin-top: -1px;
}
.akismet-boxes .akismet-box:last-child {
margin-bottom: 1.5rem;
}
.akismet-boxes .akismet-box:first-child {
margin-top: 1.5rem;
}
.akismet-box-header {
max-width: 700px;
margin: 0 auto 40px auto;
line-height: 1.5;
}
.akismet-box-header h2 {
margin: 1.5rem 10% 0;
font-size: 1.375rem;
font-weight: 700;
color: #000;
}
.akismet-box .centered {
text-align: center;
}
.akismet-box .akismet-toggles {
margin: 3rem 0;
}
.akismet-box .akismet-ak-connect, .akismet-box .toggle-jp-connect {
display: none;
}
.akismet-button, .akismet-button:hover, .akismet-button:visited {
background: white;
border-color: #c8d7e1;
border-style: solid;
border-width: 1px 1px 2px;
color: #2e4453;
cursor: pointer;
display: inline-block;
margin: 0;
outline: 0;
overflow: hidden;
font-size: 14px;
font-weight: 500;
text-overflow: ellipsis;
text-decoration: none;
vertical-align: top;
box-sizing: border-box;
font-size: 14px;
line-height: 21px;
border-radius: 4px;
padding: 7px 14px 9px;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.akismet-button:hover {
border-color: #a8bece;
}
.akismet-button:active {
border-width: 2px 1px 1px;
}
.akismet-is-primary, .akismet-is-primary:hover, .akismet-is-primary:visited {
background: #00aadc;
border-color: #0087be;
color: white;
}
.akismet-is-primary:hover, .akismet-is-primary:focus {
border-color: #005082;
}
.akismet-is-primary:hover {
border-color: #005082;
}
.akismet-section-header {
position: relative;
margin: 0 auto 0.625rem auto;
padding: 1rem;
box-sizing: border-box;
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
background: #ffffff;
width: 100%;
padding-top: 0.6875rem;
padding-bottom: 0.6875rem;
display: flex;
}
.akismet-section-header__label {
display: -ms-flexbox;
display: flex;
-ms-flex-align: center;
align-items: center;
-ms-flex-positive: 1;
flex-grow: 1;
line-height: 1.75rem;
position: relative;
font-size: 0.875rem;
color: #4f748e;
}
.akismet-section-header__actions {
line-height: 1.75rem;
}
.akismet-setup-instructions {
text-align: center;
}
.akismet-setup-instructions form {
padding-bottom: 1.5rem;
}
div.error.akismet-usage-limit-alert {
padding: 25px 45px 25px 15px;
display: flex;
align-items: center;
}
#akismet-plugin-container .akismet-usage-limit-alert {
margin: 0 auto 0.625rem auto;
box-sizing: border-box;
box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
border: none;
border-left: 4px solid #d63638;
}
.akismet-usage-limit-alert .akismet-usage-limit-logo {
width: 38px;
min-width: 38px;
height: 38px;
border-radius: 20px;
margin-right: 18px;
background: black;
position: relative;
}
.akismet-usage-limit-alert .akismet-usage-limit-logo img {
position: absolute;
width: 22px;
left: 8px;
top: 10px;
}
.akismet-usage-limit-alert .akismet-usage-limit-text {
flex-grow: 1;
margin-right: 18px;
}
.akismet-usage-limit-alert h3 {
margin: 0;
}
.akismet-usage-limit-alert .akismet-usage-limit-cta {
border-color: none;
text-align: right;
}
#akismet-plugin-container .akismet-usage-limit-cta a {
color: #d63638;
}
@media (max-width: 550px) {
div.error.akismet-usage-limit-alert {
display: block;
}
.akismet-usage-limit-alert .akismet-usage-limit-logo,
.akismet-usage-limit-alert .akismet-usage-limit-text {
margin-bottom: 15px;
}
.akismet-usage-limit-alert .akismet-usage-limit-cta {
text-align: left;
}
} _inc/akismet-frontend.js 0000644 00000026174 14744621672 0011313 0 ustar 00 /**
* Observe how the user enters content into the comment form in order to determine whether it's a bot or not.
*
* Note that no actual input is being saved here, only counts and timings between events.
*/
( function() {
// Passive event listeners are guaranteed to never call e.preventDefault(),
// but they're not supported in all browsers. Use this feature detection
// to determine whether they're available for use.
var supportsPassive = false;
try {
var opts = Object.defineProperty( {}, 'passive', {
get : function() {
supportsPassive = true;
}
} );
window.addEventListener( 'testPassive', null, opts );
window.removeEventListener( 'testPassive', null, opts );
} catch ( e ) {}
function init() {
var input_begin = '';
var keydowns = {};
var lastKeyup = null;
var lastKeydown = null;
var keypresses = [];
var modifierKeys = [];
var correctionKeys = [];
var lastMouseup = null;
var lastMousedown = null;
var mouseclicks = [];
var mousemoveTimer = null;
var lastMousemoveX = null;
var lastMousemoveY = null;
var mousemoveStart = null;
var mousemoves = [];
var touchmoveCountTimer = null;
var touchmoveCount = 0;
var lastTouchEnd = null;
var lastTouchStart = null;
var touchEvents = [];
var scrollCountTimer = null;
var scrollCount = 0;
var correctionKeyCodes = [ 'Backspace', 'Delete', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Home', 'End', 'PageUp', 'PageDown' ];
var modifierKeyCodes = [ 'Shift', 'CapsLock' ];
var forms = document.querySelectorAll( 'form[method=post]' );
for ( var i = 0; i < forms.length; i++ ) {
var form = forms[i];
var formAction = form.getAttribute( 'action' );
// Ignore forms that POST directly to other domains; these could be things like payment forms.
if ( formAction ) {
// Check that the form is posting to an external URL, not a path.
if ( formAction.indexOf( 'http://' ) == 0 || formAction.indexOf( 'https://' ) == 0 ) {
if ( formAction.indexOf( 'http://' + window.location.hostname + '/' ) != 0 && formAction.indexOf( 'https://' + window.location.hostname + '/' ) != 0 ) {
continue;
}
}
}
form.addEventListener( 'submit', function () {
var ak_bkp = prepare_timestamp_array_for_request( keypresses );
var ak_bmc = prepare_timestamp_array_for_request( mouseclicks );
var ak_bte = prepare_timestamp_array_for_request( touchEvents );
var ak_bmm = prepare_timestamp_array_for_request( mousemoves );
var input_fields = {
// When did the user begin entering any input?
'bib': input_begin,
// When was the form submitted?
'bfs': Date.now(),
// How many keypresses did they make?
'bkpc': keypresses.length,
// How quickly did they press a sample of keys, and how long between them?
'bkp': ak_bkp,
// How quickly did they click the mouse, and how long between clicks?
'bmc': ak_bmc,
// How many mouseclicks did they make?
'bmcc': mouseclicks.length,
// When did they press modifier keys (like Shift or Capslock)?
'bmk': modifierKeys.join( ';' ),
// When did they correct themselves? e.g., press Backspace, or use the arrow keys to move the cursor back
'bck': correctionKeys.join( ';' ),
// How many times did they move the mouse?
'bmmc': mousemoves.length,
// How many times did they move around using a touchscreen?
'btmc': touchmoveCount,
// How many times did they scroll?
'bsc': scrollCount,
// How quickly did they perform touch events, and how long between them?
'bte': ak_bte,
// How many touch events were there?
'btec' : touchEvents.length,
// How quickly did they move the mouse, and how long between moves?
'bmm' : ak_bmm
};
var akismet_field_prefix = 'ak_';
if ( this.getElementsByClassName ) {
// Check to see if we've used an alternate field name prefix. We store this as an attribute of the container around some of the Akismet fields.
var possible_akismet_containers = this.getElementsByClassName( 'akismet-fields-container' );
for ( var containerIndex = 0; containerIndex < possible_akismet_containers.length; containerIndex++ ) {
var container = possible_akismet_containers.item( containerIndex );
if ( container.getAttribute( 'data-prefix' ) ) {
akismet_field_prefix = container.getAttribute( 'data-prefix' );
break;
}
}
}
for ( var field_name in input_fields ) {
var field = document.createElement( 'input' );
field.setAttribute( 'type', 'hidden' );
field.setAttribute( 'name', akismet_field_prefix + field_name );
field.setAttribute( 'value', input_fields[ field_name ] );
this.appendChild( field );
}
}, supportsPassive ? { passive: true } : false );
form.addEventListener( 'keydown', function ( e ) {
// If you hold a key down, some browsers send multiple keydown events in a row.
// Ignore any keydown events for a key that hasn't come back up yet.
if ( e.key in keydowns ) {
return;
}
var keydownTime = ( new Date() ).getTime();
keydowns[ e.key ] = [ keydownTime ];
if ( ! input_begin ) {
input_begin = keydownTime;
}
// In some situations, we don't want to record an interval since the last keypress -- for example,
// on the first keypress, or on a keypress after focus has changed to another element. Normally,
// we want to record the time between the last keyup and this keydown. But if they press a
// key while already pressing a key, we want to record the time between the two keydowns.
var lastKeyEvent = Math.max( lastKeydown, lastKeyup );
if ( lastKeyEvent ) {
keydowns[ e.key ].push( keydownTime - lastKeyEvent );
}
lastKeydown = keydownTime;
}, supportsPassive ? { passive: true } : false );
form.addEventListener( 'keyup', function ( e ) {
if ( ! ( e.key in keydowns ) ) {
// This key was pressed before this script was loaded, or a mouseclick happened during the keypress, or...
return;
}
var keyupTime = ( new Date() ).getTime();
if ( 'TEXTAREA' === e.target.nodeName || 'INPUT' === e.target.nodeName ) {
if ( -1 !== modifierKeyCodes.indexOf( e.key ) ) {
modifierKeys.push( keypresses.length - 1 );
} else if ( -1 !== correctionKeyCodes.indexOf( e.key ) ) {
correctionKeys.push( keypresses.length - 1 );
} else {
// ^ Don't record timings for keys like Shift or backspace, since they
// typically get held down for longer than regular typing.
var keydownTime = keydowns[ e.key ][0];
var keypress = [];
// Keypress duration.
keypress.push( keyupTime - keydownTime );
// Amount of time between this keypress and the previous keypress.
if ( keydowns[ e.key ].length > 1 ) {
keypress.push( keydowns[ e.key ][1] );
}
keypresses.push( keypress );
}
}
delete keydowns[ e.key ];
lastKeyup = keyupTime;
}, supportsPassive ? { passive: true } : false );
form.addEventListener( "focusin", function ( e ) {
lastKeydown = null;
lastKeyup = null;
keydowns = {};
}, supportsPassive ? { passive: true } : false );
form.addEventListener( "focusout", function ( e ) {
lastKeydown = null;
lastKeyup = null;
keydowns = {};
}, supportsPassive ? { passive: true } : false );
}
document.addEventListener( 'mousedown', function ( e ) {
lastMousedown = ( new Date() ).getTime();
}, supportsPassive ? { passive: true } : false );
document.addEventListener( 'mouseup', function ( e ) {
if ( ! lastMousedown ) {
// If the mousedown happened before this script was loaded, but the mouseup happened after...
return;
}
var now = ( new Date() ).getTime();
var mouseclick = [];
mouseclick.push( now - lastMousedown );
if ( lastMouseup ) {
mouseclick.push( lastMousedown - lastMouseup );
}
mouseclicks.push( mouseclick );
lastMouseup = now;
// If the mouse has been clicked, don't record this time as an interval between keypresses.
lastKeydown = null;
lastKeyup = null;
keydowns = {};
}, supportsPassive ? { passive: true } : false );
document.addEventListener( 'mousemove', function ( e ) {
if ( mousemoveTimer ) {
clearTimeout( mousemoveTimer );
mousemoveTimer = null;
}
else {
mousemoveStart = ( new Date() ).getTime();
lastMousemoveX = e.offsetX;
lastMousemoveY = e.offsetY;
}
mousemoveTimer = setTimeout( function ( theEvent, originalMousemoveStart ) {
var now = ( new Date() ).getTime() - 500; // To account for the timer delay.
var mousemove = [];
mousemove.push( now - originalMousemoveStart );
mousemove.push(
Math.round(
Math.sqrt(
Math.pow( theEvent.offsetX - lastMousemoveX, 2 ) +
Math.pow( theEvent.offsetY - lastMousemoveY, 2 )
)
)
);
if ( mousemove[1] > 0 ) {
// If there was no measurable distance, then it wasn't really a move.
mousemoves.push( mousemove );
}
mousemoveStart = null;
mousemoveTimer = null;
}, 500, e, mousemoveStart );
}, supportsPassive ? { passive: true } : false );
document.addEventListener( 'touchmove', function ( e ) {
if ( touchmoveCountTimer ) {
clearTimeout( touchmoveCountTimer );
}
touchmoveCountTimer = setTimeout( function () {
touchmoveCount++;
}, 500 );
}, supportsPassive ? { passive: true } : false );
document.addEventListener( 'touchstart', function ( e ) {
lastTouchStart = ( new Date() ).getTime();
}, supportsPassive ? { passive: true } : false );
document.addEventListener( 'touchend', function ( e ) {
if ( ! lastTouchStart ) {
// If the touchstart happened before this script was loaded, but the touchend happened after...
return;
}
var now = ( new Date() ).getTime();
var touchEvent = [];
touchEvent.push( now - lastTouchStart );
if ( lastTouchEnd ) {
touchEvent.push( lastTouchStart - lastTouchEnd );
}
touchEvents.push( touchEvent );
lastTouchEnd = now;
// Don't record this time as an interval between keypresses.
lastKeydown = null;
lastKeyup = null;
keydowns = {};
}, supportsPassive ? { passive: true } : false );
document.addEventListener( 'scroll', function ( e ) {
if ( scrollCountTimer ) {
clearTimeout( scrollCountTimer );
}
scrollCountTimer = setTimeout( function () {
scrollCount++;
}, 500 );
}, supportsPassive ? { passive: true } : false );
}
/**
* For the timestamp data that is collected, don't send more than `limit` data points in the request.
* Choose a random slice and send those.
*/
function prepare_timestamp_array_for_request( a, limit ) {
if ( ! limit ) {
limit = 100;
}
var rv = '';
if ( a.length > 0 ) {
var random_starting_point = Math.max( 0, Math.floor( Math.random() * a.length - limit ) );
for ( var i = 0; i < limit && i < a.length; i++ ) {
rv += a[ random_starting_point + i ][0];
if ( a[ random_starting_point + i ].length >= 2 ) {
rv += "," + a[ random_starting_point + i ][1];
}
rv += ";";
}
}
return rv;
}
if ( document.readyState !== 'loading' ) {
init();
} else {
document.addEventListener( 'DOMContentLoaded', init );
}
})(); _inc/img/arrow-left.svg 0000644 00000000307 14744621672 0011050 0 ustar 00