Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/cf7-message-filter/cf7-message-filter.php
+++ b/cf7-message-filter/cf7-message-filter.php
@@ -9,7 +9,7 @@
* Plugin Name: Message Filter for Contact Form 7
* Plugin URI: https://github.com/kofimokome/cf7-message-filter
* Description: Filters messages submitted from contact form 7 if it has words or email marked as spam by the user
- * Version: 1.6.3.2
+ * Version: 1.6.3.3
* Author: Kofi Mokome
* Author URI: https://www.kofimokome.stream
* License: GPL-2.0+
@@ -22,7 +22,7 @@
namespace km_message_filter;
use KMEnv;
-use WordPressTools;
+use WPTools;
defined( 'ABSPATH' ) or die( 'Giving To Cesar What Belongs To Caesar' );
if ( function_exists( 'kmcf7ms_fs' ) ) {
kmcf7ms_fs()->set_basename( false, __FILE__ );
@@ -148,7 +148,7 @@
delete_option( 'kmcfmf_weekly_stats' );
delete_option( 'kmcfmf_weekend' );
}
- $wordpress_tools = new WordPressTools(__FILE__);
+ $wordpress_tools = new WPTools(__FILE__);
$wordpress_tools->migration_manager->runMigrations();
$message_filter = new KMCFMessageFilter();
$message_filter->run();
@@ -171,7 +171,7 @@
function KMCF7Uninstall() {
global $wpdb;
if ( get_option( 'kmcfmf_message_delete_data', 'off' ) == 'on' ) {
- $instance = WordPressTools::getInstance( __FILE__ );
+ $instance = WPTools::getInstance( __FILE__ );
$instance->migration_manager->dropAll();
//query the wp options table and delete all options that start with kmcfmf_
$pattern = 'kmcfmf_%';
--- a/cf7-message-filter/core/KMCFMessageFilter.php
+++ b/cf7-message-filter/core/KMCFMessageFilter.php
@@ -12,7 +12,7 @@
public function __construct() {
// do something here
- $this->version = '1.6.3.2';
+ $this->version = '1.6.3.3';
$this->blocked = get_option( "kmcfmf_messages_blocked_today_tmp", 0 );
self::$instance = $this;
}
@@ -174,7 +174,7 @@
$menu_page = new KMMenuPage( array(
'page_title' => 'CF7 Form Filter',
'menu_title' => $menu_title,
- 'capability' => 'read',
+ 'capability' => 'manage_options',
'menu_slug' => 'kmcf7-message-filter',
'icon_url' => 'dashicons-filter',
'position' => 100,
--- a/cf7-message-filter/freemius/includes/class-freemius.php
+++ b/cf7-message-filter/freemius/includes/class-freemius.php
@@ -24000,13 +24000,15 @@
// Start trial button.
$button = ' ' . sprintf(
- '<a style="margin-left: 10px; vertical-align: super;" href="%s"><button class="button button-primary">%s ➜</button></a>',
+ '<div><a class="button button-primary" href="%s">%s ➜</a></div>',
$trial_url,
$this->get_text_x_inline( 'Start free trial', 'call to action', 'start-free-trial' )
);
+ $message_text = $this->apply_filters( 'trial_promotion_message', "{$message} {$cc_string}" );
+
$this->_admin_notices->add_sticky(
- $this->apply_filters( 'trial_promotion_message', "{$message} {$cc_string} {$button}" ),
+ "<div class="fs-trial-message-container"><div>{$message_text}</div> {$button}</div>",
'trial_promotion',
'',
'promotion'
@@ -25476,7 +25478,7 @@
$img_dir = WP_FS__DIR_IMG;
// Locate the main assets folder.
- if ( 1 < count( $fs_active_plugins->plugins ) ) {
+ if ( ! empty( $fs_active_plugins->plugins ) ) {
$plugin_or_theme_img_dir = ( $this->is_plugin() ? WP_PLUGIN_DIR : get_theme_root( get_stylesheet() ) );
foreach ( $fs_active_plugins->plugins as $sdk_path => &$data ) {
--- a/cf7-message-filter/freemius/includes/class-fs-plugin-updater.php
+++ b/cf7-message-filter/freemius/includes/class-fs-plugin-updater.php
@@ -542,24 +542,8 @@
global $wp_current_filter;
- $current_plugin_version = $this->_fs->get_plugin_version();
-
- if ( ! empty( $wp_current_filter ) && 'upgrader_process_complete' === $wp_current_filter[0] ) {
- if (
- is_null( $this->_update_details ) ||
- ( is_object( $this->_update_details ) && $this->_update_details->new_version !== $current_plugin_version )
- ) {
- /**
- * After an update, clear the stored update details and reparse the plugin's main file in order to get
- * the updated version's information and prevent the previous update information from showing up on the
- * updates page.
- *
- * @author Leo Fajardo (@leorw)
- * @since 2.3.1
- */
- $this->_update_details = null;
- $current_plugin_version = $this->_fs->get_plugin_version( true );
- }
+ if ( ! empty( $wp_current_filter ) && in_array( 'upgrader_process_complete', $wp_current_filter ) ) {
+ return $transient_data;
}
if ( ! isset( $this->_update_details ) ) {
@@ -568,7 +552,7 @@
false,
fs_request_get_bool( 'force-check' ),
FS_Plugin_Updater::UPDATES_CHECK_CACHE_EXPIRATION,
- $current_plugin_version
+ $this->_fs->get_plugin_version()
);
$this->_update_details = false;
--- a/cf7-message-filter/freemius/includes/entities/class-fs-plugin-plan.php
+++ b/cf7-message-filter/freemius/includes/entities/class-fs-plugin-plan.php
@@ -13,7 +13,6 @@
/**
* Class FS_Plugin_Plan
*
- * @property FS_Pricing[] $pricing
*/
class FS_Plugin_Plan extends FS_Entity {
--- a/cf7-message-filter/freemius/includes/entities/class-fs-site.php
+++ b/cf7-message-filter/freemius/includes/entities/class-fs-site.php
@@ -10,16 +10,16 @@
exit;
}
- /**
- * @property int $blog_id
- */
- #[AllowDynamicProperties]
class FS_Site extends FS_Scope_Entity {
/**
* @var number
*/
public $site_id;
/**
+ * @var int
+ */
+ public $blog_id;
+ /**
* @var number
*/
public $plugin_id;
--- a/cf7-message-filter/freemius/includes/entities/class-fs-user.php
+++ b/cf7-message-filter/freemius/includes/entities/class-fs-user.php
@@ -48,6 +48,19 @@
parent::__construct( $user );
}
+ /**
+ * This method removes the deprecated 'is_beta' property from the serialized data.
+ * Should clean up the serialized data to avoid PHP 8.2 warning on next execution.
+ *
+ * @return void
+ */
+ function __wakeup() {
+ if ( property_exists( $this, 'is_beta' ) ) {
+ // If we enter here, and we are running PHP 8.2, we already had the warning. But we sanitize data for next execution.
+ unset( $this->is_beta );
+ }
+ }
+
function get_name() {
return trim( ucfirst( trim( is_string( $this->first ) ? $this->first : '' ) ) . ' ' . ucfirst( trim( is_string( $this->last ) ? $this->last : '' ) ) );
}
--- a/cf7-message-filter/freemius/includes/managers/class-fs-admin-menu-manager.php
+++ b/cf7-message-filter/freemius/includes/managers/class-fs-admin-menu-manager.php
@@ -699,16 +699,36 @@
$menu = $this->find_main_submenu();
}
+ $menu_slug = $menu['menu'][2];
$parent_slug = isset( $menu['parent_slug'] ) ?
- $menu['parent_slug'] :
- 'admin.php';
+ $menu['parent_slug'] :
+ 'admin.php';
- return admin_url(
- $parent_slug .
- ( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .
- 'page=' .
- $menu['menu'][2]
- );
+ if ( fs_apply_filter( $this->_module_unique_affix, 'enable_cpt_advanced_menu_logic', false ) ) {
+ $parent_slug = 'admin.php';
+
+ /**
+ * This line and the `if` block below it are based on the `menu_page_url()` function of WordPress.
+ *
+ * @author Leo Fajardo (@leorw)
+ * @since 2.10.2
+ */
+ global $_parent_pages;
+
+ if ( ! empty( $_parent_pages[ $menu_slug ] ) ) {
+ $_parent_slug = $_parent_pages[ $menu_slug ];
+ $parent_slug = isset( $_parent_pages[ $_parent_slug ] ) ?
+ $parent_slug :
+ $menu['parent_slug'];
+ }
+ }
+
+ return admin_url(
+ $parent_slug .
+ ( false === strpos( $parent_slug, '?' ) ? '?' : '&' ) .
+ 'page=' .
+ $menu_slug
+ );
}
/**
--- a/cf7-message-filter/freemius/includes/managers/class-fs-admin-notice-manager.php
+++ b/cf7-message-filter/freemius/includes/managers/class-fs-admin-notice-manager.php
@@ -194,8 +194,14 @@
* @since 1.0.7
*/
static function _add_sticky_dismiss_javascript() {
+ $sticky_admin_notice_js_template_name = 'sticky-admin-notice-js.php';
+
+ if ( ! file_exists( fs_get_template_path( $sticky_admin_notice_js_template_name ) ) ) {
+ return;
+ }
+
$params = array();
- fs_require_once_template( 'sticky-admin-notice-js.php', $params );
+ fs_require_once_template( $sticky_admin_notice_js_template_name, $params );
}
private static $_added_sticky_javascript = false;
--- a/cf7-message-filter/freemius/start.php
+++ b/cf7-message-filter/freemius/start.php
@@ -15,7 +15,7 @@
*
* @var string
*/
- $this_sdk_version = '2.10.1';
+ $this_sdk_version = '2.11.0';
#region SDK Selection Logic --------------------------------------------------------------------
--- a/cf7-message-filter/lib/requires.php
+++ b/cf7-message-filter/lib/requires.php
@@ -9,7 +9,7 @@
$plugin_path = plugin_dir_path( __FILE__ );
$files = [
- $plugin_path . 'wordpress_tools/WordPressTools.php', //
+ $plugin_path . 'wordpress_tools/WPTools.php', //
$plugin_path . 'emoji_detector/Emoji.php', //
];
--- a/cf7-message-filter/lib/wordpress_tools/KMBuilder.php
+++ b/cf7-message-filter/lib/wordpress_tools/KMBuilder.php
@@ -182,8 +182,7 @@
$query .= $additions;
$data = $this->getResults( $query );
}
-// echo( $query );
- // reset query variables;
+ // reset query variables;
$this->where = '';
$this->orderBys = [];
$this->groupBys = [];
@@ -203,10 +202,11 @@
public function where( string $field, string $comparison, $value, $add_table_name = true ): KMBuilder {
$table_name = $add_table_name ? $this->table_name . '.' : '';
if ( strlen( $this->where ) == 0 ) {
-
+ $value = $this->escapeValue( $value );
if ( ! is_numeric( $value ) ) {
$value = "'" . $value . "'";
}
+
$this->where = " WHERE " . $table_name . $field . " " . $comparison . " " . $value;
return $this;
@@ -221,16 +221,48 @@
*/
public function andWhere( string $field, string $comparison, $value ): KMBuilder {
$table_name = $this->table_name;
+ $value = $this->escapeValue( $value );
+
if ( ! is_numeric( $value ) ) {
$value = "'" . $value . "'";
}
+
$this->where .= " AND " . $table_name . '.' . $field . " " . $comparison . " " . $value;
+
return $this;
}
/**
* @author kofimokome
+ * @since 1.6.3.3
+ */
+ private function escapeValue( $value ): string {
+ // Check if the value starts with %
+ $starts_with_percent = strpos( $value, '%' ) === 0;
+ // Check if the value ends with %
+ $ends_with_percent = strrpos( $value, '%' ) === ( strlen( $value ) - 1 );
+
+ // Remove % from the start and end of the value
+ $trimmed_value = trim( $value, '%' );
+
+ // Escape the trimmed value
+ $escaped_value = esc_sql( $trimmed_value );
+
+ // Add % back to the start and/or end if they were originally present
+ if ( $starts_with_percent ) {
+ $escaped_value = '%' . $escaped_value;
+ }
+ if ( $ends_with_percent ) {
+ $escaped_value .= '%';
+ }
+
+ return $escaped_value;
+ }
+
+
+ /**
+ * @author kofimokome
* @since 1.0.0
*/
public function getResults( $query ) {
@@ -300,11 +332,14 @@
*/
public function orWhere( string $field, string $comparison, $value ): KMBuilder {
$table_name = $this->table_name;
+ $value = $this->escapeValue( $value );
if ( ! is_numeric( $value ) ) {
$value = "'" . $value . "'";
}
+
$this->where .= " OR " . $table_name . '.' . $field . " " . $comparison . " " . $value;
+
return $this;
}
@@ -313,9 +348,12 @@
* @since 1.0.0
*/
public function whereJoin( string $field, string $comparison, $value, $table ): KMBuilder {
+ $value = $this->escapeValue( $value );
+
if ( ! is_numeric( $value ) ) {
$value = "'" . $value . "'";
}
+
$this->where = " WHERE " . $table . '.' . $field . " " . $comparison . " " . $value;
return $this;
@@ -326,9 +364,12 @@
* @since 1.0.0
*/
public function andWhereJoin( string $field, string $comparison, $value, $table ): KMBuilder {
+ $value = $this->escapeValue( $value );
+
if ( ! is_numeric( $value ) ) {
$value = "'" . $value . "'";
}
+
$this->where .= " AND " . $table . '.' . $field . " " . $comparison . " " . $value;
return $this;
@@ -339,11 +380,14 @@
* @since 1.0.0
*/
public function orWhereJoin( string $field, string $comparison, $value, $table ): KMBuilder {
+ $value = $this->escapeValue( $value );
if ( ! is_numeric( $value ) ) {
$value = "'" . $value . "'";
}
+
$this->where .= " OR " . $table . '.' . $field . " " . $comparison . " " . $value;
+
return $this;
}
@@ -450,7 +494,7 @@
$fields['created_at'] = gmdate( "Y-m-d H:i" );
$fields['updated_at'] = gmdate( "Y-m-d H:i" );
}
- $fields['id'] = NULL;
+ $fields['id'] = null;
$result = $wpdb->insert( $table_name, $fields );
} else { // we are updating
if ( $this->model->hasTimeStamps() ) {
--- a/cf7-message-filter/lib/wordpress_tools/WPTools.php
+++ b/cf7-message-filter/lib/wordpress_tools/WPTools.php
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * @author kofimokome
+ */
+
+require_once 'KMEnv.php';
+require_once 'KMRouteManager.php';
+require_once 'KMMigrationManager.php';
+require_once 'KMBlueprint.php';
+require_once 'KMBuilder.php';
+require_once 'KMMenuPage.php';
+require_once 'KMSubMenuPage.php';
+require_once 'KMSetting.php';
+require_once 'KMColumn.php';
+require_once 'KMModel.php';
+require_once 'KMMigration.php';
+require_once 'KMRoute.php';
+require_once 'KMValidator.php';
+require_once 'lib/plural/Plural.php';
+
+
+if ( ! class_exists('WPTools') ) {
+ class WPTools {
+ public $env;
+ public $route_manager;
+ public $migration_manager;
+ private $plugin_basename;
+ private $context;
+ private static $instances = [];
+
+
+ public function __construct( string $context ) {
+ $this->env = ( new KMEnv( $context ) )->getEnv();
+ $this->route_manager = new KMRouteManager( $context );
+ $this->plugin_basename = plugin_basename( $context );
+ $this->context = $context;
+ $this->migration_manager = new KMMigrationManager( $this->getPluginDir(), $context );
+ self::$instances[ explode( '/', $this->plugin_basename )[0] ] = $this;
+
+ }
+
+ /**
+ * @author kofimokome
+ */
+ public static function getInstance( string $context ): WPTools {
+ $plugin_basename = plugin_basename( $context );
+ $plugin = explode( '/', $plugin_basename )[0];
+
+ if ( ! isset( self::$instances[ $plugin ] ) ) {
+ throw new Exception( 'WPTools instance not found' );
+ }
+
+ return self::$instances[ $plugin ];
+ }
+
+ /**
+ * @author kofimokome
+ */
+ public function routes(): KMRoute {
+ $route = new KMRoute( $this->route_manager );
+
+ return $route;
+ }
+
+ /**
+ * @author kofimokome
+ */
+ public function renderView( string $view, $echo = true ) {
+ return $this->route_manager->renderView( $view, $echo );
+ }
+
+ /**
+ * @author kofimokome
+ */
+ public function viewPath( string $view ) {
+ return $this->route_manager->viewPath( $view );
+ }
+
+ /**
+ * @author kofimokome
+ */
+ public function route( string $name, array $params = [] ): string {
+ return $this->route_manager->route( $name, $params );
+ }
+
+
+ /**
+ * @throws Exception
+ * @author kofimokome
+ */
+ public function getPluginDir() {
+
+ $chars = explode( '/', $this->plugin_basename );
+ if ( sizeof( $chars ) > 0 ) {
+ $plugin_basename = $chars[0];
+
+ return WP_PLUGIN_DIR . '/' . $plugin_basename;
+ }
+
+ throw new Exception( 'Could not get plugin directory' );
+ }
+
+ /**
+ * @author kofimokome
+ */
+ public function getPluginURL(): string {
+ return rtrim( plugin_dir_url( $this->context ), '/' );
+ }
+
+ public function env() {
+ return ( new KMEnv( $this->context ) )->getEnv();
+ }
+ }
+
+}
--- a/cf7-message-filter/lib/wordpress_tools/WordPressTools.php
+++ b/cf7-message-filter/lib/wordpress_tools/WordPressTools.php
@@ -1,116 +0,0 @@
-<?php
-
-/**
- * @author kofimokome
- */
-
-require_once 'KMEnv.php';
-require_once 'KMRouteManager.php';
-require_once 'KMMigrationManager.php';
-require_once 'KMBlueprint.php';
-require_once 'KMBuilder.php';
-require_once 'KMMenuPage.php';
-require_once 'KMSubMenuPage.php';
-require_once 'KMSetting.php';
-require_once 'KMColumn.php';
-require_once 'KMModel.php';
-require_once 'KMMigration.php';
-require_once 'KMRoute.php';
-require_once 'KMValidator.php';
-require_once 'lib/plural/Plural.php';
-
-
-if ( ! class_exists( 'WordPressTools' ) ) {
- class WordPressTools {
- public $env;
- public $route_manager;
- public $migration_manager;
- private $plugin_basename;
- private $context;
- private static $instances = [];
-
-
- public function __construct( string $context ) {
- $this->env = ( new KMEnv( $context ) )->getEnv();
- $this->route_manager = new KMRouteManager( $context );
- $this->plugin_basename = plugin_basename( $context );
- $this->context = $context;
- $this->migration_manager = new KMMigrationManager( $this->getPluginDir(), $context );
- self::$instances[ explode( '/', $this->plugin_basename )[0] ] = $this;
-
- }
-
- /**
- * @author kofimokome
- */
- public static function getInstance( string $context ): WordPressTools {
- $plugin_basename = plugin_basename( $context );
- $plugin = explode( '/', $plugin_basename )[0];
-
- if ( ! isset( self::$instances[ $plugin ] ) ) {
- throw new Exception( 'WordPressTools instance not found' );
- }
-
- return self::$instances[ $plugin ];
- }
-
- /**
- * @author kofimokome
- */
- public function routes(): KMRoute {
- $route = new KMRoute( $this->route_manager );
-
- return $route;
- }
-
- /**
- * @author kofimokome
- */
- public function renderView( string $view, $echo = true ) {
- return $this->route_manager->renderView( $view, $echo );
- }
-
- /**
- * @author kofimokome
- */
- public function viewPath( string $view ) {
- return $this->route_manager->viewPath( $view );
- }
-
- /**
- * @author kofimokome
- */
- public function route( string $name, array $params = [] ): string {
- return $this->route_manager->route( $name, $params );
- }
-
-
- /**
- * @throws Exception
- * @author kofimokome
- */
- public function getPluginDir() {
-
- $chars = explode( '/', $this->plugin_basename );
- if ( sizeof( $chars ) > 0 ) {
- $plugin_basename = $chars[0];
-
- return WP_PLUGIN_DIR . '/' . $plugin_basename;
- }
-
- throw new Exception( 'Could not get plugin directory' );
- }
-
- /**
- * @author kofimokome
- */
- public function getPluginURL(): string {
- return rtrim( plugin_dir_url( $this->context ), '/' );
- }
-
- public function env() {
- return ( new KMEnv( $this->context ) )->getEnv();
- }
- }
-
-}
--- a/cf7-message-filter/modules/dashboard/DashboardModule.php
+++ b/cf7-message-filter/modules/dashboard/DashboardModule.php
@@ -3,7 +3,7 @@
namespace km_message_filter;
use KMSubMenuPage;
-use WordPressTools;
+use WPTools;
class DashboardModule extends Module {
private $blocked;
@@ -48,7 +48,7 @@
* Displays content on dashboard sub menu page
*/
function dashboardPageContent() {
- $instance = WordPressTools::getInstance( __FILE__ );
+ $instance = WPTools::getInstance( __FILE__ );
$instance->renderView( 'dashboard.index' );
}
--- a/cf7-message-filter/modules/messages/MessagesModule.php
+++ b/cf7-message-filter/modules/messages/MessagesModule.php
@@ -4,9 +4,9 @@
use KMSubMenuPage;
use KMValidator;
-use WordPressTools;
use WPCF7_ContactForm;
use WPCF7_Submission;
+use WPTools;
class MessagesModule extends Module {
private static $instance;
@@ -18,7 +18,7 @@
$this->transferOldData();
// $this->module = 'packages';
self::$instance = $this;
- $this->wp_tools = WordPressTools::getInstance( __FILE__ );
+ $this->wp_tools = WPTools::getInstance( __FILE__ );
}
/**
@@ -203,6 +203,9 @@
*/
public function serverMessages() {
try {
+ if ( ! current_user_can( 'manage_options' ) ) {
+ throw new Exception( __( 'You do not have permission to perform this action', KMCFMF_TEXT_DOMAIN ) );
+ }
$nonce = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'kmcfmf_can_get_blocked_messages' ) ) {
throw new Exception( __( 'Invalid nonce', KMCFMF_TEXT_DOMAIN ) );
@@ -213,8 +216,8 @@
$draw = isset( $_REQUEST['draw'] ) ? intval( sanitize_text_field( wp_unslash( $_REQUEST['draw'] ) ) ) : '';
$length = isset( $_REQUEST['length'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['length'] ) ) : '';
$start = isset( $_REQUEST['start'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['start'] ) ) : '';
- $search = isset( $_REQUEST['search'] ) ? rest_sanitize_array( wp_unslash( $_REQUEST['search'] ) ) : '';
- $search_value = sanitize_text_field( wp_unslash( $search['value'] ) );
+ $search = isset( $_REQUEST['search'] ) ? rest_sanitize_array( wp_unslash( $_REQUEST['search'] ) ) : [];
+ $search_value = sanitize_text_field( wp_unslash( $search[0] ) );
$search_value = trim( $search_value );
$current_page = ( $start / $length ) + 1;
$results = Message::where( 'message', 'LIKE', "%{$search_value}%" )->orderBy( 'id', 'desc' )->paginate( $length, $current_page );
@@ -232,7 +235,7 @@
$messages = array();
// todo: Investigate why this function returns two different results for some contact forms on the frontend and here
- $rows = $this->getRows2( $form_id, $contact_form );
+ $rows = $this->getColumns2( $form_id, $contact_form );
foreach ( $results as $result ) {
$decoded_message = json_decode( $result->message );
@@ -280,7 +283,7 @@
* New version of getRows()
* @since 1.4.0
*/
- public function getRows2( $form_id, $contact_form ) {
+ public function getColumns2( $form_id, $contact_form ) {
$rows = array();
switch ( $contact_form ) {
case 'cf7':
@@ -493,7 +496,7 @@
$result = $submission->get_result();
// $contact_form->submit();
if ( $result['status'] != 'mail_sent' ) {
- wp_send_json_error( __( $result, KMCFMF_TEXT_DOMAIN ), 400 );
+ wp_send_json_error( $result, KMCFMF_TEXT_DOMAIN, 400 );
}
$message_id = intval( $message_id );
$message = Message::find( $message_id );
@@ -550,6 +553,75 @@
}
/**
+ * @since v1.6.3.3
+ * @author: kofimokome
+ */
+ public function downloadCSV() {
+ $validator = KMValidator::make(
+ array(
+ 'form_id' => 'required',
+ 'contact_form' => 'required',
+ '_wpnonce' => 'required'
+ ),
+ $_REQUEST
+ );
+ if ( current_user_can( 'manage_options' ) ) {
+ if ( $validated_data = $validator->validate() ) {
+ $nonce = sanitize_text_field( wp_unslash( $validated_data['_wpnonce'] ) );
+ if ( wp_verify_nonce( $nonce, 'kmcfmf_can_download_csv' ) ) {
+
+ $form_id = sanitize_text_field( $validated_data['form_id'] );
+ $contact_form = sanitize_text_field( $validated_data['contact_form'] );
+ $columns = $this->getColumns2( $form_id, $contact_form );
+ $columns[] = 'date-blocked';
+ $messages = Message::where( 'contact_form', '=', $contact_form );
+
+ if ( $form_id != 'all' ) {
+ $messages = $messages->andWhere( 'form_id', '=', $form_id );
+ }
+
+ $messages = $messages->orderBy( 'id', 'desc' )->get();
+
+ $filename = 'blocked_messages_' . date( 'Y-m-d' ) . '.csv';
+ $fp = fopen( 'php://output', 'w' );
+ header( 'Content-type: application/csv' );
+ header( 'Content-Disposition: attachment; filename=' . $filename );
+ fputcsv( $fp, $columns );
+ foreach ( $messages as $message ) {
+ $decoded_message = json_decode( $message->message );
+
+ $row = [];
+ if ( $form_id == 'all' ) {
+ $row[] = $this->getFormName( $message->form_id, $message->contact_form );
+ }
+ foreach ( $columns as $column ) {
+ if ( $column == 'date-blocked' ) {
+ $row[] = $message->created_at;
+ } else {
+ if ( property_exists( $decoded_message, $column ) ) {
+ $row[] = esc_html( self::decodeUnicodeVars( $decoded_message->$column ) );
+ } else {
+ $row[] = " ";
+ }
+ }
+ }
+ fputcsv( $fp, $row );
+ }
+ fclose( $fp );
+ exit();
+ } else {
+ wp_send_json_error( __( "Invalid nonce", KMCFMF_TEXT_DOMAIN ), 400 );
+ }
+ } else {
+ wp_send_json_error( __( "You do not have permission to perform this action", KMCFMF_TEXT_DOMAIN ), 400 );
+ }
+ } else {
+ throw new Exception( __( 'You do not have permission to perform this action', KMCFMF_TEXT_DOMAIN ) );
+ }
+ wp_die();
+ }
+
+ /**
* @since v1.3.4
*/
protected
@@ -562,6 +634,7 @@
protected
function addActions() {
parent::addActions();
+ add_action( 'wp_ajax_kmcf7_download_csv', [ $this, 'downloadCSV' ] );
add_action( 'wp_ajax_kmcf7_messages', [ $this, 'serverMessages' ] );
add_action( 'wp_ajax_kmcf7_delete_message', [ $this, 'deleteMessage' ] );
add_action( 'wp_ajax_kmcf7_resubmit_message', [ $this, 'resubmitMessage' ] );
--- a/cf7-message-filter/modules/settings/SettingsModule.php
+++ b/cf7-message-filter/modules/settings/SettingsModule.php
@@ -4,7 +4,7 @@
use KMSetting;
use KMSubMenuPage;
-use WordPressTools;
+use WPTools;
class SettingsModule extends Module {
private $is_free;
@@ -15,7 +15,7 @@
$this->is_free = ( ! kmcf7ms_fs()->is_premium() || ! kmcf7ms_fs()->is_plan_or_trial( 'pro' ) );
$this->addSettings();
$this->checkWildcardInSettingFields();
- $this->wp_tools = WordPressTools::getInstance( __FILE__ );
+ $this->wp_tools = WPTools::getInstance( __FILE__ );
$is_using_old_tag_ui = get_option( 'kmcfmf_use_old_tag_ui', 'deleted' );
--- a/cf7-message-filter/views/messages/list.php
+++ b/cf7-message-filter/views/messages/list.php
@@ -43,7 +43,7 @@
</form>
</div>-->
<?php
-$rows = MessagesModule::getInstance()->getRows2( $form_id, $selected_contact_form );
+$form_columns = MessagesModule::getInstance()->getColumns2( $form_id, $selected_contact_form );
?>
<form action="" class="form-inline mb-4 mt-4">
@@ -72,6 +72,7 @@
<div class="alert alert-info">
<?php _e( "Hint: Press and hold <kbd>CMD</kbd> or <kbd>CRTL</kbd> while clicking on any cell to select it", KMCFMF_TEXT_DOMAIN ) ?>
</div>
+
<button class="btn btn-danger btn-sm km-delete-btn" style="display: none" onclick="showDeleteModal()">
<?php _e( "Delete selected", KMCFMF_TEXT_DOMAIN ) ?>
</button>
@@ -80,24 +81,28 @@
</button>-->
</div>
<div class="mb-3">
- <b><?php _e( "Visible Columns", KMCFMF_TEXT_DOMAIN ) ?>: <a href="#" id="toggle-visible-columns-container">Show/Hide</a>
+ <b><?php _e( "Visible Columns", KMCFMF_TEXT_DOMAIN ) ?>: <a href="#"
+ id="toggle-visible-columns-container">Show/Hide</a>
<div id="visible-columns-container" class="mt-2">
<input id="input-ID" name="ID" type="checkbox" value="2" class="table-column"
checked/> <span class="mr-2">ID</span>
- <?php foreach ( $rows as $index => $row ):if ( strlen( trim( $row ) ) > 0 ): ?>
- <input id="input-<?php echo $row ?>" name="<?php echo $row ?>" type="checkbox"
+ <?php foreach ( $form_columns as $index => $form_column ):if ( strlen( trim( $form_column ) ) > 0 ): ?>
+ <input id="input-<?php echo $form_column ?>" name="<?php echo $form_column ?>" type="checkbox"
value="<?php echo $index + 3 ?>" class="table-column"
- checked/> <span class="mr-2"> <?php echo $row ?></span>
+ checked/> <span class="mr-2"> <?php echo $form_column ?></span>
<?php endif; endforeach; ?>
</div>
</div>
-<table id="km-table" class="kmcfmf_table table table-striped" style="overflow-x: scroll">
+<button class="btn btn-primary mb-3" onclick="showDownloadModal()">
+ <?php _e( "Download CSV", KMCFMF_TEXT_DOMAIN ) ?>
+</button>
+<table id="km-table" class="kmcfmf_table table table-striped" style="overflow-x: scroll;">
<thead>
<tr>
<th></th>
<th><?php _e( "Actions", KMCFMF_TEXT_DOMAIN ) ?></th>
<th><b>ID</b></th>
- <?php foreach ( $rows as $row ): ?>
+ <?php foreach ( $form_columns as $row ): ?>
<th>
<b><?php echo $row ?></b>
</th>
@@ -132,8 +137,11 @@
const GET_MESSAGES_NONCE = "<?php echo wp_create_nonce( 'kmcfmf_can_get_blocked_messages' )?>";
const DELETE_MESSAGE_NONCE = "<?php echo wp_create_nonce( 'kmcfmf_can_delete_messages' )?>";
const RESUBMIT_MESSAGE_NONCE = "<?php echo wp_create_nonce( 'kmcfmf_can_resubmit_messages' )?>";
+ const DOWNLOAD_MESSAGE_NONCE = "<?php echo wp_create_nonce( 'kmcfmf_can_download_csv' )?>";
const forms = <?php echo wp_json_encode( $forms )?>;
const all_registered_form_placeholder = "<?php _e( "All Registered Forms", KMCFMF_TEXT_DOMAIN )?>"
+ const selected_contact_form = '<?php echo $selected_contact_form?>'
+ const form_id = '<?php echo $form_id?>'
console.log(forms['cf7']);
jQuery(function ($) {
$(document).ready(function () {
@@ -186,10 +194,10 @@
}],
buttons: [
// 'colvis',
- {
+ /* {
extend: 'csv',
text: 'Download CSV'
- },
+ },*/
],
lengthMenu: [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
select: true
@@ -380,6 +388,65 @@
}
})
}
+
+ function showDownloadModal() {
+
+ let formData = new FormData();
+ formData.append("action", 'kmcf7_download_csv');
+ formData.append("form_id", form_id);
+ formData.append("contact_form", selected_contact_form);
+ bootstrapSwal().fire({
+ title: 'Download CSV',
+ text: '<?php _e( "CSV Download could take a long time depending on the number of blocked messages", KMCFMF_TEXT_DOMAIN ) ?>',
+ icon: 'info',
+ showCancelButton: true,
+ confirmButtonText: '<?php _e( "Yes, download", KMCFMF_TEXT_DOMAIN )?>',
+ showLoaderOnConfirm: true,
+ preConfirm: (login) => {
+ return fetch("<?php echo $ajax_url?>" + "?_wpnonce=" + DOWNLOAD_MESSAGE_NONCE, {
+ method: 'POST',
+ body: formData
+ })
+ .then(async response => {
+ if (!response.ok) {
+ const e = await response.text();
+ let message = "Something went wrong";
+ try {
+ const response_json = JSON.parse(e)
+ if (response_json.data)
+ message = response_json.data.message ?? response_json.data.toString()
+ } catch (e) {
+ // Silence is golden
+ }
+ throw new Error(message)
+ } else
+ return response.blob()
+ })
+ .catch(error => {
+ Swal.showValidationMessage(
+ `Request failed: ${error}`
+ )
+ })
+ },
+ allowOutsideClick: () => !Swal.isLoading()
+ }).then((result) => {
+ if (result.isConfirmed && result.value) {
+ const url = window.URL.createObjectURL(result.value);
+ const a = document.createElement('a');
+ a.style.display = 'none';
+ a.href = url;
+ a.download = 'blocked_messages.csv';
+ document.body.appendChild(a);
+ a.click();
+ window.URL.revokeObjectURL(url);
+ Swal.fire({
+ title: `Download CSV`,
+ icon: 'success',
+ text: '<?php _e( "CSV generated successfully", KMCFMF_TEXT_DOMAIN )?>',
+ })
+ }
+ })
+ }
</script>
--- a/cf7-message-filter/views/messages/message.php
+++ b/cf7-message-filter/views/messages/message.php
@@ -23,7 +23,7 @@
$contact_form = $message_object->contact_form;
$message = json_decode( $message_object->message );
$messages_module = MessagesModule::getInstance();
- $rows = $messages_module->getRows2( $form_id, $contact_form );
+ $rows = $messages_module->getColumns2( $form_id, $contact_form );
?>
<table class="kmcfmf_table table table-striped" style="overflow-x: scroll">
<thead>
--- a/cf7-message-filter/views/settings/debug.php
+++ b/cf7-message-filter/views/settings/debug.php
@@ -23,6 +23,7 @@
'is_contact_form_7_filter_enabled' => get_option( 'kmcfmf_enable_contact_form_7_toggle' ) == 'on' ? 'Yes' : "No",
'is_spam_filter_enabled' => get_option( 'kmcfmf_email_filter_toggle' ) == 'on' ? 'Yes' : "No",
'is_message_filter_enabled' => get_option( 'kmcfmf_message_filter_toggle' ) == 'on' ? 'Yes' : "No",
+ 'is_email_filter_enabled' => get_option( 'kmcfmf_email_filter_toggle' ) == 'on' ? 'Yes' : "No",
'is_wp_forms_filter_enabled' => get_option( 'kmcfmf_enable_wp_forms_toggle' ) == 'on' ? 'Yes' : "No",
'is_sync_allowed' => $can_sync ? 'Yes' : 'No',
--- a/cf7-message-filter/views/settings/settings.php
+++ b/cf7-message-filter/views/settings/settings.php
@@ -2,7 +2,7 @@
namespace km_message_filter;
-use WordPressTools;
+use WPTools;
$ajax_url = admin_url( "admin-ajax.php" );
$words = get_option( 'kmcfmf_restricted_words', '' );
$words = sizeof( explode( ',', $words ) );
@@ -213,7 +213,7 @@
style="display:none; position:absolute; z-index: 9; left:0;top:0; width: 100%; height: 100%; align-content: center; align-items: center; justify-content: center; background: rgba(0,0,0,0.2)">
<div style="background: white; width: 500px; height:500px; overflow-y:auto; position: relative; padding-left: 10px; padding-right: 10px;">
<?php
-WordPressTools::getInstance( __FILE__ )->renderView( 'settings.filters', true );
+WPTools::getInstance( __FILE__ )->renderView( 'settings.filters', true );
?>
</div>
</div>