Commit c00d24d9 authored by Simon's avatar Simon

release 1.29.2

parent da914cda
......@@ -20,9 +20,9 @@
## Production
- build CSS & JS assets - `C:\web\dev.biuro\ npm run build`
- build new image `docker build -t biuro/web:1.29.1 .` (update version number)
- build new image `docker build -t biuro/web:1.29.2 .` (update version number)
- login to biuro docker account `docker login --username=biuro --password=9Ndtjd2vKsLvGuFOeFq1KdJs`
- push image to docker repository - `docker push biuro/web:1.29.1`
- push image to docker repository - `docker push biuro/web:1.29.2`
## Production
- update biuro/web image version in .env file (staging or www)
......
var ak_js = document.getElementById( "ak_js" );
if ( ! ak_js ) {
ak_js = document.createElement( 'input' );
ak_js.setAttribute( 'id', 'ak_js' );
ak_js.setAttribute( 'name', 'ak_js' );
ak_js.setAttribute( 'type', 'hidden' );
}
else {
ak_js.parentNode.removeChild( ak_js );
}
ak_js.setAttribute( 'value', ( new Date() ).getTime() );
var commentForm = document.getElementById( 'commentform' );
if ( commentForm ) {
commentForm.appendChild( ak_js );
}
else {
var replyRowContainer = document.getElementById( 'replyrow' );
if ( replyRowContainer ) {
var children = replyRowContainer.getElementsByTagName( 'td' );
if ( children.length > 0 ) {
children[0].appendChild( ak_js );
}
}
}
\ No newline at end of file
......@@ -6,7 +6,7 @@
Plugin Name: Akismet Anti-Spam
Plugin URI: https://akismet.com/
Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.
Version: 4.1.12
Version: 4.2.1
Author: Automattic
Author URI: https://automattic.com/wordpress-plugins/
License: GPLv2 or later
......@@ -37,8 +37,8 @@ if ( !function_exists( 'add_action' ) ) {
exit;
}
define( 'AKISMET_VERSION', '4.1.12' );
define( 'AKISMET__MINIMUM_WP_VERSION', '4.0' );
define( 'AKISMET_VERSION', '4.2.1' );
define( 'AKISMET__MINIMUM_WP_VERSION', '5.0' );
define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'AKISMET_DELETE_LIMIT', 100000 );
......
......@@ -897,6 +897,7 @@ class Akismet_Admin {
'usage_limit' => get_option( 'akismet_alert_usage_limit' ),
'upgrade_plan' => get_option( 'akismet_alert_upgrade_plan' ),
'upgrade_url' => get_option( 'akismet_alert_upgrade_url' ),
'upgrade_type' => get_option( 'akismet_alert_upgrade_type' ),
);
}
......@@ -1038,7 +1039,7 @@ class Akismet_Admin {
}
$alert_code = get_option( 'akismet_alert_code' );
if ( isset( Akismet::$LIMIT_NOTICES[ $alert_code ] ) ) {
if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
$notices[] = self::get_usage_limit_alert_data();
}
......@@ -1080,10 +1081,9 @@ class Akismet_Admin {
Akismet::verify_key( Akismet::get_api_key() ); //verify that the key is still in alert state
$alert_code = get_option( 'akismet_alert_code' );
if ( isset( Akismet::$LIMIT_NOTICES[ $alert_code ] ) ) {
if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
self::display_usage_limit_alert();
}
elseif ( $alert_code > 0 ) {
} elseif ( $alert_code > 0 ) {
self::display_alert();
}
}
......
......@@ -99,7 +99,29 @@ class Akismet_Widget extends WP_Widget {
?>
<div class="a-stats">
<a href="https://akismet.com" target="_blank" rel="noopener" title=""><?php printf( _n( '<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>', '<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>', $count , 'akismet'), number_format_i18n( $count ) ); ?></a>
<a href="https://akismet.com" target="_blank" rel="noopener" title="">
<?php
echo wp_kses(
sprintf(
/* translators: The placeholder is the number of pieces of spam blocked by Akismet. */
_n(
'<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>',
'<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>',
$count,
'akismet'
),
number_format_i18n( $count )
),
array(
'strong' => array(
'class' => true,
),
)
);
?>
</a>
</div>
<?php
......
......@@ -5,7 +5,7 @@ class Akismet {
const API_PORT = 80;
const MAX_DELAY_BEFORE_MODERATION_EMAIL = 86400; // One day in seconds
public static $LIMIT_NOTICES = array(
public static $limit_notices = array(
10501 => 'FIRST_MONTH_OVER_LIMIT',
10502 => 'SECOND_MONTH_OVER_LIMIT',
10504 => 'THIRD_MONTH_APPROACHING_LIMIT',
......@@ -41,11 +41,7 @@ class Akismet {
add_action( 'akismet_schedule_cron_recheck', array( 'Akismet', 'cron_recheck' ) );
add_action( 'comment_form', array( 'Akismet', 'add_comment_nonce' ), 1 );
add_action( 'admin_head-edit-comments.php', array( 'Akismet', 'load_form_js' ) );
add_action( 'comment_form', array( 'Akismet', 'load_form_js' ) );
add_action( 'comment_form', array( 'Akismet', 'inject_ak_js' ) );
add_filter( 'script_loader_tag', array( 'Akismet', 'set_form_js_async' ), 10, 3 );
add_action( 'comment_form', array( 'Akismet', 'output_custom_form_fields' ) );
add_filter( 'comment_moderation_recipients', array( 'Akismet', 'disable_moderation_emails_if_unreachable' ), 1000, 2 );
add_filter( 'pre_comment_approved', array( 'Akismet', 'last_comment_status' ), 10, 2 );
......@@ -57,6 +53,17 @@ class Akismet {
// Jetpack compatibility
add_filter( 'jetpack_options_whitelist', array( 'Akismet', 'add_to_jetpack_options_whitelist' ) );
add_filter( 'jetpack_contact_form_html', array( 'Akismet', 'inject_custom_form_fields' ) );
add_filter( 'jetpack_contact_form_akismet_values', array( 'Akismet', 'prepare_custom_form_values' ) );
// Gravity Forms
add_filter( 'gform_get_form_filter', array( 'Akismet', 'inject_custom_form_fields' ) );
add_filter( 'gform_akismet_fields', array( 'Akismet', 'prepare_custom_form_values' ) );
// Contact Form 7
add_filter( 'wpcf7_form_elements', array( 'Akismet', 'append_custom_form_fields' ) );
add_filter( 'wpcf7_akismet_parameters', array( 'Akismet', 'prepare_custom_form_values' ) );
add_action( 'update_option_wordpress_api_key', array( 'Akismet', 'updated_option' ), 10, 2 );
add_action( 'add_option_wordpress_api_key', array( 'Akismet', 'added_option' ), 10, 2 );
......@@ -1132,6 +1139,7 @@ class Akismet {
if ( ! empty( self::$prevent_moderation_email_for_these_comments ) && ! empty( $emails ) ) {
$comment = get_comment( $comment_id );
if ( $comment ) {
foreach ( self::$prevent_moderation_email_for_these_comments as $possible_match ) {
if ( self::comments_match( $possible_match, $comment ) ) {
update_comment_meta( $comment_id, 'akismet_delayed_moderation_email', true );
......@@ -1139,6 +1147,7 @@ class Akismet {
}
}
}
}
return $emails;
}
......@@ -1275,20 +1284,20 @@ class Akismet {
'usage-limit',
'upgrade-plan',
'upgrade-url',
'upgrade-type',
);
foreach( $alert_header_names as $alert_header_name ) {
foreach ( $alert_header_names as $alert_header_name ) {
$value = null;
if ( isset( $response[0][$alert_header_prefix . $alert_header_name] ) ) {
$value = $response[0][$alert_header_prefix . $alert_header_name];
if ( isset( $response[0][ $alert_header_prefix . $alert_header_name ] ) ) {
$value = $response[0][ $alert_header_prefix . $alert_header_name ];
}
$option_name = $alert_option_prefix . str_replace( '-', '_', $alert_header_name );
if ( $value != get_option( $option_name ) ) {
if ( ! $value ) {
delete_option( $option_name );
}
else {
} else {
update_option( $option_name, $value );
}
}
......@@ -1296,34 +1305,76 @@ class Akismet {
}
public static function load_form_js() {
if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
return;
/* deprecated */
}
if ( ! self::get_api_key() ) {
return;
public static function set_form_js_async( $tag, $handle, $src ) {
/* deprecated */
return $tag;
}
public static function get_akismet_form_fields() {
$fields = '';
$prefix = 'ak_';
// Contact Form 7 uses _wpcf7 as a prefix to know which fields to exclude from comment_content.
if ( 'wpcf7_form_elements' === current_filter() ) {
$prefix = '_wpcf7_ak_';
}
wp_register_script( 'akismet-form', plugin_dir_url( __FILE__ ) . '_inc/form.js', array(), AKISMET_VERSION, true );
wp_enqueue_script( 'akismet-form' );
$fields .= '<p style="display: none !important;">';
$fields .= '<label>&#916;<textarea name="' . $prefix . 'hp_textarea" cols="45" rows="8" maxlength="100"></textarea></label>';
if ( ! function_exists( 'amp_is_request' ) || ! amp_is_request() ) {
$fields .= '<input type="hidden" id="ak_js" name="' . $prefix . 'js" value="' . mt_rand( 0, 250 ) . '"/>';
$fields .= '<script>document.getElementById( "ak_js" ).setAttribute( "value", ( new Date() ).getTime() );</script>';
}
$fields .= '</p>';
return $fields;
}
public static function output_custom_form_fields( $post_id ) {
// phpcs:ignore WordPress.Security.EscapeOutput
echo self::get_akismet_form_fields();
}
public static function inject_custom_form_fields( $html ) {
$html = str_replace( '</form>', self::get_akismet_form_fields() . '</form>', $html );
return $html;
}
public static function append_custom_form_fields( $html ) {
$html .= self::get_akismet_form_fields();
return $html;
}
/**
* Mark form.js as deferred. Because nothing depends on it, it can run at any time
* after it's loaded, and the browser won't have to wait for it to load to continue
* parsing the rest of the page.
* Ensure that any Akismet-added form fields are included in the comment-check call.
*
* @param array $form
* @return array $form
*/
public static function set_form_js_async( $tag, $handle, $src ) {
if ( 'akismet-form' !== $handle ) {
return $tag;
public static function prepare_custom_form_values( $form ) {
$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_';
}
return preg_replace( '/^<script /i', '<script defer ', $tag );
// phpcs:ignore WordPress.Security.NonceVerification.Missing
foreach ( $_POST as $key => $val ) {
if ( 0 === strpos( $key, $prefix ) ) {
$form[ 'POST_ak_' . substr( $key, strlen( $prefix ) ) ] = $val;
}
}
public static function inject_ak_js( $post_id ) {
echo '<input type="hidden" id="ak_js" name="ak_js" value="' . mt_rand( 0, 250 ) . '"/>';
echo '<textarea name="ak_hp_textarea" cols="45" rows="8" maxlength="100" style="display: none !important;"></textarea>';
return $form;
}
private static function bail_on_activation( $message, $deactivate = true ) {
......
=== Akismet Spam Protection ===
Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau
Tags: comments, spam, antispam, anti-spam, contact form, anti spam, comment moderation, comment spam, contact form spam, spam comments
Requires at least: 4.6
Requires at least: 5.0
Tested up to: 5.8
Stable tag: 4.1.12
Stable tag: 4.2.1
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.
......@@ -30,6 +30,19 @@ Upload the Akismet plugin to your blog, activate it, and then enter your Akismet
== Changelog ==
= 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.
= 4.1.12 =
*Release Date - 3 September 2021*
......
<?php
//phpcs:disable VariableAnalysis
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
?>
<div id="akismet-plugin-container">
<div class="akismet-masthead">
<div class="akismet-masthead__inside-container">
......@@ -53,7 +59,7 @@
</div>
<?php endif;?>
<?php if ( $akismet_user ):?>
<?php if ( $akismet_user ) : ?>
<div class="akismet-card">
<div class="akismet-section-header">
<div class="akismet-section-header__label">
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -158,6 +158,7 @@ add_action('site-reviews/review/created', function ($review, $command) {
if (!function_exists('rocket_clean_post')) {
return;
}
rocket_clean_post($command->post_id); // The page the review was submitted on
foreach ($command->assigned_posts as $postId) {
if ($postId != $command->post_id) {
rocket_clean_post($postId);
......
......@@ -205,6 +205,26 @@ return [
'tooltip' => _x('The avatars are generated from the email address of the reviewer using <a href="https://gravatar.com">Gravatar</a>.', 'admin-text', 'site-reviews'),
'type' => 'yes_no',
],
'settings.reviews.avatars_fallback' => [
'class' => 'regular-text',
'default' => 'mystery',
'depends_on' => [
'settings.reviews.avatars' => 'yes',
],
'label' => _x('Fallback Avatar', 'admin-text', 'site-reviews'),
'options' => [
'identicon' => _x('Identicon (geometric patterns)', 'admin-text', 'site-reviews'),
'initials' => _x('Initials (initials of reviewer\'s name)', 'admin-text', 'site-reviews'),
'monsterid' => _x('Monster (monsters with generated faces)', 'admin-text', 'site-reviews'),
'mystery' => _x('Mystery (silhouetted outline of a person)', 'admin-text', 'site-reviews'),
'pixels' => _x('Pixel Avatars (locally generated)', 'admin-text', 'site-reviews'),
'retro' => _x('Retro (8-bit arcade-style pixelated faces)', 'admin-text', 'site-reviews'),
'robohash' => _x('Robohash (robots with generated faces)', 'admin-text', 'site-reviews'),
'wavatar' => _x('Wavatar (faces with generated features)', 'admin-text', 'site-reviews'),
],
'tooltip' => _x('This image is displayed when there is no avatar.', 'admin-text', 'site-reviews'),
'type' => 'select',
],
'settings.reviews.avatars_regenerate' => [
'default' => 'no',
'depends_on' => [
......
......@@ -64,7 +64,6 @@ class SiteReviewsFormBlock extends Block
$shortcode = glsr(Shortcode::class);
if ('edit' == filter_input(INPUT_GET, 'context')) {
$this->filterFormFields();
$this->filterRatingField();
$this->filterSubmitButton();
if (!$this->hasVisibleFields($shortcode, $attributes)) {
$this->filterInterpolation();
......@@ -102,22 +101,6 @@ class SiteReviewsFormBlock extends Block
});
}
/**
* @return void
*/
protected function filterRatingField()
{
add_filter('site-reviews/rendered/field', function ($html, $type, $args) {
if (Str::contains('glsr-star-rating', $args['class'])) {
$stars = '<span class="glsr-stars">';
$stars.= str_repeat('<span class="glsr-star glsr-star-empty" aria-hidden="true"></span>', (int) glsr()->constant('MAX_RATING', Rating::class));
$stars.= '</span>';
$html = preg_replace('/(.*)(<select.*)(<\/select>)(.*)/u', '$1'.$stars.'$4', $html);
}
return $html;
}, 10, 3);
}
/**
* @return void
*/
......
......@@ -145,11 +145,11 @@ class CreateReview implements Contract
if (!empty($this->avatar)) {
return $this->avatar;
}
$userField = empty($this->email)
? get_current_user_id()
: $this->email;
$userField = glsr()->filterString('avatar/id_or_email', $userField, $this->toArray());
return glsr(Avatar::class)->generate($userField);
$review = new Review($this->toArray(), false); // don't init!
if (empty($this->email)) {
$review->set('author_id', get_current_user_id());
}
return glsr(Avatar::class)->generate($review);
}
/**
......
......@@ -18,19 +18,25 @@ class SummaryParameters
'assigned_posts' => [
'default' => [],
'description' => _x('Limit result set to reviews assigned to specific posts of any public post type.', 'admin-text', 'site-reviews'),
'items' => ['type' => 'integer'],
'items' => [
'type' => ['integer', 'string'],
],
'type' => 'array',
],
'assigned_terms' => [
'default' => [],
'description' => sprintf(_x('Limit result set to reviews assigned to specific terms in the %s taxonomy.', 'admin-text', 'site-reviews'), glsr()->taxonomy),
'items' => ['type' => 'integer'],
'items' => [
'type' => ['integer', 'string'],
],
'type' => 'array',
],
'assigned_users' => [
'default' => [],
'description' => _x('Limit result set to reviews assigned to specific users.', 'admin-text', 'site-reviews'),
'items' => ['type' => 'integer'],
'items' => [
'type' => ['integer', 'string'],
],
'type' => 'array',
],
'before' => [
......@@ -89,13 +95,17 @@ class SummaryParameters
'user__in' => [
'default' => [],
'description' => _x('Limit result set to reviews authored by specific users.', 'admin-text', 'site-reviews'),
'items' => ['type' => 'integer'],
'items' => [
'type' => ['integer', 'string'],
],
'type' => 'array',
],
'user__not_in' => [
'default' => [],
'description' => _x('Ensure result set excludes reviews authored by specific users.', 'admin-text', 'site-reviews'),
'items' => ['type' => 'integer'],
'items' => [
'type' => ['integer', 'string'],
],
'type' => 'array',
],
];
......
......@@ -3,6 +3,7 @@
namespace GeminiLabs\SiteReviews\Controllers\ListTableColumns;
use GeminiLabs\SiteReviews\Database\Query;
use GeminiLabs\SiteReviews\Helpers\Arr;
class ColumnFilterAssignedPost extends ColumnFilter
{
......@@ -51,6 +52,7 @@ class ColumnFilterAssignedPost extends ColumnFilter
$title = sprintf('%s (ID: %s)', $title, $id);
}
natcasesort($options);
$options = Arr::prepend($options, _x('No assigned post', 'admin-text', 'site-reviews'), '-1');
return $options;
}
......
......@@ -4,6 +4,7 @@ namespace GeminiLabs\SiteReviews\Controllers\ListTableColumns;
use GeminiLabs\SiteReviews\Database;
use GeminiLabs\SiteReviews\Database\Query;
use GeminiLabs\SiteReviews\Helpers\Arr;
class ColumnFilterAssignedUser extends ColumnFilter
{
......@@ -37,7 +38,9 @@ class ColumnFilterAssignedUser extends ColumnFilter
if (empty($userIds)) {
return [];
}
return glsr(Database::class)->users(['include' => $userIds]);
$options = glsr(Database::class)->users(['include' => $userIds]);
$options = Arr::prepend($options, _x('No assigned user', 'admin-text', 'site-reviews'), '-1');
return $options;
}
/**
......
......@@ -2,6 +2,8 @@
namespace GeminiLabs\SiteReviews\Controllers\ListTableColumns;
use GeminiLabs\SiteReviews\Helpers\Arr;
class ColumnFilterCategory extends ColumnFilter
{
/**
......@@ -37,12 +39,17 @@ class ColumnFilterCategory extends ColumnFilter
*/
protected function options()
{
return get_terms([
$options = get_terms([
'count' => false,
'fields' => 'id=>name',
'hide_empty' => true,
'taxonomy' => glsr()->taxonomy,
]);
if (is_wp_error($options)) {
return [];
}
$options = Arr::prepend($options, _x('No category', 'admin-text', 'site-reviews'), '-1');
return $options;
}
/**
......
......@@ -311,10 +311,13 @@ class ListTableController extends Controller
$query->set('orderby', 'meta_value');
}
if ($termId = filter_input(INPUT_GET, 'assigned_term', FILTER_SANITIZE_NUMBER_INT)) {
$query->set('tax_query', [[
'taxonomy' => glsr()->taxonomy,
'terms' => $termId,
]]);
$taxQuery = ['taxonomy' => glsr()->taxonomy];
if (-1 === Cast::toInt($termId)) {
$taxQuery['operator'] = 'NOT EXISTS';
} else {
$taxQuery['terms'] = $termId;
}
$query->set('tax_query', [$taxQuery]);
}
}
......@@ -399,12 +402,21 @@ class ListTableController extends Controller
if (in_array($key, ['assigned_post', 'assigned_user'])) {
global $wpdb;
$assignedTable = glsr(Query::class)->table($key.'s');
if (-1 === Cast::toInt($value)) {
$ids = $wpdb->get_col("
SELECT DISTINCT r.review_id
FROM {$table} r
LEFT JOIN {$assignedTable} at ON at.rating_id = r.ID
WHERE at.{$mapped[$key]}_id IS NULL
");
} else {
$ids = $wpdb->get_col("
SELECT DISTINCT r.review_id
FROM {$table} r
INNER JOIN {$assignedTable} at ON at.rating_id = r.ID
WHERE at.{$mapped[$key]}_id = '{$value}'
");
}
$where .= sprintf(" AND {$wpdb->posts}.ID IN (%s) ", implode(',', $ids));
} else {
$where .= " AND {$table}.{$key} = '{$value}' ";
......
......@@ -102,7 +102,7 @@ class PublicController extends Controller
*/
public function renderModal()
{
if (glsr()->retrieve('use_modal', true)) {
if (glsr()->retrieve('use_modal', false)) {
glsr()->render('views/partials/modal');
}
}
......
......@@ -21,7 +21,7 @@ class TaxonomyManager
}
/**
* @param int[]|string $termIds
* @param array|string $termIds
* @return array
*/
public function normalizeIds($termIds)
......
This diff is collapsed.
......@@ -52,6 +52,7 @@ class SiteReviewsSummaryShortcode extends Shortcode
{
$args = $this->args;
$className = Helper::buildClassName(['summary', $tag, 'tag'], 'Modules\Html\Tags');
$className = glsr()->filterString('summary/tag/'.$tag, $className, $this);
$field = class_exists($className)
? glsr($className, compact('tag', 'args'))->handleFor('summary', null, $this->ratings)
: null;
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Plugin Name: Site Reviews
* Plugin URI: https://wordpress.org/plugins/site-reviews
* Description: Receive and display reviews on your website
* Version: 5.15.0
* Version: 5.16.0
* Author: Paul Ryley
* Author URI: https://geminilabs.io
* License: GPL2
......
This diff is collapsed.
......@@ -4,6 +4,7 @@
<div class="is-fullwidth">
<div class="glsr-flex-row">
<div class="glsr-column">
<?php include trailingslashit(__DIR__).'whatsnew/v516.php'; ?>
<?php include trailingslashit(__DIR__).'whatsnew/v515.php'; ?>
<?php include trailingslashit(__DIR__).'whatsnew/v514.php'; ?>
<?php include trailingslashit(__DIR__).'whatsnew/v513.php'; ?>
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment