first commit

This commit is contained in:
User A0264400
2026-04-01 23:20:16 +03:00
commit a766acdc90
23071 changed files with 4933189 additions and 0 deletions

View File

@@ -0,0 +1,288 @@
<?php
namespace WPForms\Lite\Admin;
use WP_Error;
use WPForms\Helpers\PluginSilentUpgrader;
/**
* WPForms Connect.
*
* WPForms Connect is our service that makes it easy for non-techy users to
* upgrade to WPForms Pro without having to manually install WPForms Pro plugin.
*
* @since 1.5.5
*/
class Connect {
/**
* WPForms Pro plugin basename.
*
* @since 1.8.4
*
* @var string
*/
const PRO_PLUGIN = 'wpforms/wpforms.php';
/**
* Constructor.
*
* @since 1.5.5
*/
public function __construct() {
$this->hooks();
}
/**
* Hooks.
*
* @since 1.5.5
*/
public function hooks() {
add_action( 'wpforms_settings_enqueue', [ $this, 'settings_enqueues' ] );
add_action( 'wp_ajax_wpforms_connect_url', [ $this, 'generate_url' ] );
add_action( 'wp_ajax_nopriv_wpforms_connect_process', [ $this, 'process' ] );
}
/**
* Settings page enqueues.
*
* @since 1.5.5
*/
public function settings_enqueues() {
$min = wpforms_get_min_suffix();
wp_enqueue_script(
'wpforms-connect',
WPFORMS_PLUGIN_URL . "assets/lite/js/admin/connect{$min}.js",
[ 'jquery' ],
WPFORMS_VERSION,
true
);
}
/**
* Generate and return WPForms Connect URL.
*
* @since 1.5.5
*/
public function generate_url() {
// Run a security check.
check_ajax_referer( 'wpforms-admin', 'nonce' );
// Check for permissions.
if ( ! current_user_can( 'install_plugins' ) ) {
wp_send_json_error( [ 'message' => esc_html__( 'You are not allowed to install plugins.', 'wpforms-lite' ) ] );
}
$current_plugin = plugin_basename( WPFORMS_PLUGIN_FILE );
$is_pro = wpforms()->is_pro();
// Local development environment.
if ( $current_plugin === self::PRO_PLUGIN && ! $is_pro ) {
wp_send_json_error( [ 'message' => esc_html__( 'There must be a non-developer Lite version installed to upgrade.', 'wpforms-lite' ) ] );
}
$key = ! empty( $_POST['key'] ) ? sanitize_text_field( wp_unslash( $_POST['key'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
// Empty license key.
if ( empty( $key ) ) {
wp_send_json_error( [ 'message' => esc_html__( 'Please enter your license key to connect.', 'wpforms-lite' ) ] );
}
// Whether it is the pro version.
if ( $is_pro ) {
wp_send_json_error( [ 'message' => esc_html__( 'Only the Lite version can be upgraded.', 'wpforms-lite' ) ] );
}
// Verify pro version is not installed.
$active = activate_plugin( self::PRO_PLUGIN, false, false, true );
if ( ! is_wp_error( $active ) ) {
// Deactivate Lite.
deactivate_plugins( $current_plugin );
// phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName
do_action( 'wpforms_plugin_deactivated', $current_plugin );
wp_send_json_success(
[
'message' => esc_html__( 'WPForms Pro is installed but not activated.', 'wpforms-lite' ),
'reload' => true,
]
);
}
// Generate URL.
$oth = hash( 'sha512', wp_rand() );
$hashed_oth = hash_hmac( 'sha512', $oth, wp_salt() );
update_option( 'wpforms_connect_token', $oth );
update_option( 'wpforms_connect', $key );
$version = WPFORMS_VERSION;
$endpoint = admin_url( 'admin-ajax.php' );
$redirect = admin_url( 'admin.php?page=wpforms-settings' );
$url = add_query_arg(
[
'key' => $key,
'oth' => $hashed_oth,
'endpoint' => $endpoint,
'version' => $version,
'siteurl' => admin_url(),
'homeurl' => site_url(),
'redirect' => rawurldecode( base64_encode( $redirect ) ), // phpcs:ignore
'v' => 2,
],
'https://upgrade.wpforms.com'
);
wp_send_json_success(
[
'url' => $url,
'back_url' => add_query_arg(
[
'action' => 'wpforms_connect',
'oth' => $hashed_oth,
],
$endpoint
),
]
);
}
/**
* Process WPForms Connect.
*
* @since 1.5.5
*/
public function process() { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh, WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
$error = esc_html__( 'There was an error while installing an upgrade. Please download the plugin from wpforms.com and install it manually.', 'wpforms-lite' );
// Verify params present (oth & download link).
$post_oth = ! empty( $_REQUEST['oth'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['oth'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
$post_url = ! empty( $_REQUEST['file'] ) ? esc_url_raw( wp_unslash( $_REQUEST['file'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
if ( empty( $post_oth ) || empty( $post_url ) ) {
wp_send_json_error( $error );
}
// Verify oth.
$oth = get_option( 'wpforms_connect_token' );
if ( empty( $oth ) ) {
wp_send_json_error( $error );
}
if ( hash_hmac( 'sha512', $oth, wp_salt() ) !== $post_oth ) {
wp_send_json_error( $error );
}
// Delete so cannot replay.
delete_option( 'wpforms_connect_token' );
// Set the current screen to avoid undefined notices.
set_current_screen( 'wpforms_page_wpforms-settings' );
// Prepare variables.
$url = esc_url_raw(
add_query_arg(
[ 'page' => 'wpforms-settings' ],
admin_url( 'admin.php' )
)
);
// Verify pro not activated.
if ( wpforms()->is_pro() ) {
wp_send_json_success( esc_html__( 'Plugin installed & activated.', 'wpforms-lite' ) );
}
// Verify pro not installed.
$active = activate_plugin( self::PRO_PLUGIN, $url, false, true );
if ( ! is_wp_error( $active ) ) {
$plugin = plugin_basename( WPFORMS_PLUGIN_FILE );
deactivate_plugins( $plugin );
// phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName
do_action( 'wpforms_plugin_deactivated', $plugin );
wp_send_json_success( esc_html__( 'Plugin installed & activated.', 'wpforms-lite' ) );
}
$creds = request_filesystem_credentials( $url, '', false, false );
// Check for file system permissions.
if ( $creds === false || ! WP_Filesystem( $creds ) ) {
wp_send_json_error(
esc_html__( 'There was an error while installing an upgrade. Please check file system permissions and try again. Also, you can download the plugin from wpforms.com and install it manually.', 'wpforms-lite' )
);
}
/*
* We do not need any extra credentials if we have gotten this far, so let's install the plugin.
*/
// Do not allow WordPress to search/download translations, as this will break JS output.
remove_action( 'upgrader_process_complete', [ 'Language_Pack_Upgrader', 'async_upgrade' ], 20 );
// Create the plugin upgrader with our custom skin.
$installer = new PluginSilentUpgrader( new ConnectSkin() );
// Error check.
if ( ! method_exists( $installer, 'install' ) ) {
wp_send_json_error( $error );
}
// Check license key.
$key = get_option( 'wpforms_connect', false );
if ( empty( $key ) ) {
wp_send_json_error(
new WP_Error(
'403',
esc_html__( 'No key provided.', 'wpforms-lite' )
)
);
}
$installer->install( $post_url ); // phpcs:ignore
// Flush the cache and return the newly installed plugin basename.
wp_cache_flush();
$plugin_basename = $installer->plugin_info();
if ( $plugin_basename ) {
// Deactivate the lite version first.
$plugin = plugin_basename( WPFORMS_PLUGIN_FILE );
deactivate_plugins( $plugin );
// phpcs:ignore WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName
do_action( 'wpforms_plugin_deactivated', $plugin );
// Activate the plugin silently.
$activated = activate_plugin( $plugin_basename, '', false, true );
if ( ! is_wp_error( $activated ) ) {
add_option( 'wpforms_install', 1 );
wp_send_json_success( esc_html__( 'Plugin installed & activated.', 'wpforms-lite' ) );
} else {
// Reactivate the lite plugin if pro activation failed.
activate_plugin( plugin_basename( WPFORMS_PLUGIN_FILE ), '', false, true );
wp_send_json_error( esc_html__( 'Pro version installed but needs to be activated on the Plugins page inside your WordPress admin.', 'wpforms-lite' ) );
}
}
wp_send_json_error( $error );
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace WPForms\Lite\Admin;
use WP_Ajax_Upgrader_Skin;
use WP_Error; // phpcs:ignore WPForms.PHP.UseStatement.UnusedUseStatement
/**
* WPForms Connect Skin.
*
* WPForms Connect is our service that makes it easy for non-techy users to
* upgrade to WPForms Pro without having to manually install WPForms Pro plugin.
*
* @since 1.5.5
* @since 1.5.6.1 Extend PluginSilentUpgraderSkin and clean up the class.
* @since 1.9.5 Extend WP_Ajax_Upgrader_Skin class.
*/
class ConnectSkin extends WP_Ajax_Upgrader_Skin {
/**
* Instead of outputting HTML for errors, json_encode the errors and send them
* back to the Ajax script for processing.
*
* @since 1.5.5
*
* @param string|WP_Error $errors Errors.
* @param mixed ...$args Optional text replacements.
*/
public function error( $errors, ...$args ) {
if ( ! empty( $errors ) ) {
wp_send_json_error( esc_html__( 'There was an error installing WPForms Pro. Please try again.', 'wpforms-lite' ) );
}
}
}

View File

@@ -0,0 +1,583 @@
<?php
namespace WPForms\Lite\Admin;
use WPForms\Admin\Blocks\Links;
use WPForms\Admin\Dashboard\Widget;
/**
* Dashboard Widget shows a chart and the form entries stats in WP Dashboard.
*
* @since 1.5.0
*/
class DashboardWidget extends Widget {
/**
* Widget settings.
*
* @since 1.5.0
*
* @var array
*/
public $settings;
/**
* Init class.
*
* @since 1.5.5
*/
public function init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName
/**
* Allow disabling the widget.
*
* @since 1.5.1
*
* @param bool $load Should the widget be loaded?
*/
if ( ! apply_filters( 'wpforms_admin_dashboardwidget', true ) ) {
return;
}
// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
add_action( 'wpforms_process_complete', [ static::class, 'clear_widget_cache' ] );
add_action( 'admin_init', [ $this, 'admin_init' ] );
}
/**
* Admin init class.
*
* @since 1.8.3
*/
public function admin_init() { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
// This widget should be displayed for certain high-level users only.
if ( ! wpforms_current_user_can( 'view_forms' ) ) {
return;
}
add_action( 'wpforms_create_form', [ static::class, 'clear_widget_cache' ] );
add_action( 'wpforms_save_form', [ static::class, 'clear_widget_cache' ] );
add_action( 'wpforms_delete_form', [ static::class, 'clear_widget_cache' ] );
/**
* Clear cache after Lite plugin deactivation.
*
* Also triggered when the user upgrades the plugin to the Pro version.
* After activation of the Pro version, the cache will be cleared.
*/
add_action( 'deactivate_wpforms-lite/wpforms.php', [ static::class, 'clear_widget_cache' ] );
if ( ! $this->is_dashboard_page() && ! $this->is_dashboard_widget_ajax_request() ) {
return;
}
$this->settings();
$this->hooks();
}
/**
* Filterable widget settings.
*
* @since 1.5.0
*/
public function settings() {
// phpcs:disable WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName
$this->settings = [
// Number of forms to display in the forms' list before the "Show More" button appears.
'forms_list_number_to_display' => apply_filters( 'wpforms_dash_widget_forms_list_number_to_display', 5 ),
// Allow results caching to reduce a DB load.
'allow_data_caching' => apply_filters( 'wpforms_dash_widget_allow_data_caching', true ),
// Transient lifetime in seconds. Defaults to the end of a current day.
'transient_lifetime' => apply_filters( 'wpforms_dash_widget_transient_lifetime', strtotime( 'tomorrow' ) - time() ),
// Determine if the forms with no entries should appear in a forms' list.
// Once switched, the effect applies after cache expiration.
'display_forms_list_empty_entries' => apply_filters( 'wpforms_dash_widget_display_forms_list_empty_entries', true ),
];
// phpcs:enable WPForms.Comments.PHPDocHooks.RequiredHookDocumentation, WPForms.PHP.ValidateHooks.InvalidHookName
}
/**
* Widget hooks.
*
* @since 1.5.0
*/
public function hooks() {
$widget_slug = static::SLUG;
add_action( 'admin_enqueue_scripts', [ $this, 'widget_scripts' ] );
add_action( 'wp_dashboard_setup', [ $this, 'widget_register' ] );
add_action( 'admin_init', [ $this, 'hide_widget' ] );
add_action( "wp_ajax_wpforms_{$widget_slug}_save_widget_meta", [ $this, 'save_widget_meta_ajax' ] );
}
/**
* Load widget-specific scripts.
*
* @since 1.5.0
*
* @param string $hook_suffix The current admin page.
*/
public function widget_scripts( $hook_suffix ) {
if ( $hook_suffix !== 'index.php' ) {
return;
}
$min = wpforms_get_min_suffix();
wp_enqueue_style(
'wpforms-dashboard-widget',
WPFORMS_PLUGIN_URL . "assets/css/dashboard-widget{$min}.css",
[],
WPFORMS_VERSION
);
wp_enqueue_script(
'wpforms-chart',
WPFORMS_PLUGIN_URL . 'assets/lib/chart.min.js',
[ 'moment' ],
'4.5.1',
true
);
wp_enqueue_script(
'wpforms-dashboard-widget',
WPFORMS_PLUGIN_URL . "assets/lite/js/admin/dashboard-widget{$min}.js",
[ 'jquery', 'wpforms-chart' ],
WPFORMS_VERSION,
true
);
wp_localize_script(
'wpforms-dashboard-widget',
'wpforms_dashboard_widget',
[
'nonce' => wp_create_nonce( 'wpforms_' . static::SLUG . '_nonce' ),
'slug' => static::SLUG,
'show_more_html' => esc_html__( 'Show More', 'wpforms-lite' ) . '<span class="dashicons dashicons-arrow-down"></span>',
'show_less_html' => esc_html__( 'Show Less', 'wpforms-lite' ) . '<span class="dashicons dashicons-arrow-up"></span>',
'i18n' => [
'entries' => esc_html__( 'Entries', 'wpforms-lite' ),
],
// Adapter for Chart.js to use Moment.js for date formatting.
'adapter_path' => WPFORMS_PLUGIN_URL . 'assets/lib/chartjs-adapter-moment.min.js?ver=1.0.1',
]
);
}
/**
* Register the widget.
*
* @since 1.5.0
*/
public function widget_register() {
global $wp_meta_boxes;
$widget_key = 'wpforms_reports_widget_lite';
wp_add_dashboard_widget(
$widget_key,
esc_html__( 'WPForms', 'wpforms-lite' ),
[ $this, 'widget_content' ]
);
// Attempt to place the widget at the top.
$normal_dashboard = $wp_meta_boxes['dashboard']['normal']['core'];
$widget_instance = [ $widget_key => $normal_dashboard[ $widget_key ] ];
unset( $normal_dashboard[ $widget_key ] );
$sorted_dashboard = array_merge( $widget_instance, $normal_dashboard );
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$wp_meta_boxes['dashboard']['normal']['core'] = $sorted_dashboard;
}
/**
* Load widget content.
*
* @since 1.5.0
*/
public function widget_content() {
$forms = wpforms()->obj( 'form' )->get( '', [ 'fields' => 'ids' ] );
$hide_graph = (bool) $this->widget_meta( 'get', 'hide_graph' );
$no_graph_class = $hide_graph ? 'wpforms-dash-widget-no-graph' : '';
echo '<div class="wpforms-dash-widget wpforms-lite ' . esc_attr( $no_graph_class ) . '">';
if ( empty( $forms ) ) {
$this->widget_content_no_forms_html();
} else {
$this->widget_content_html( $hide_graph );
}
Links::render(
[
'docs' => [
'medium' => 'dashboard-widget',
'content' => 'docs',
],
]
);
$plugin = $this->get_recommended_plugin();
$hide_recommended = $this->widget_meta( 'get', 'hide_recommended_block' );
if (
! empty( $plugin ) &&
! empty( $forms ) &&
! $hide_recommended
) {
$this->recommended_plugin_block_html( $plugin );
}
echo '</div><!-- .wpforms-dash-widget -->';
}
/**
* Widget content HTML if a user has no forms.
*
* @since 1.5.0
*/
public function widget_content_no_forms_html() {
$create_form_url = add_query_arg( 'page', 'wpforms-builder', admin_url( 'admin.php' ) );
$learn_more_url = 'https://wpforms.com/docs/creating-first-form/?utm_source=WordPress&utm_medium=link&utm_campaign=liteplugin&utm_content=dashboardwidget';
?>
<div class="wpforms-dash-widget-block wpforms-dash-widget-block-no-forms">
<img class="wpforms-dash-widget-block-sullie-logo" src="<?php echo esc_url( WPFORMS_PLUGIN_URL . 'assets/images/sullie.png' ); ?>" alt="<?php esc_attr_e( 'Sullie the WPForms mascot', 'wpforms-lite' ); ?>">
<h2><?php esc_html_e( 'Create Your First Form to Start Collecting Leads', 'wpforms-lite' ); ?></h2>
<p><?php esc_html_e( 'You can use WPForms to build contact forms, surveys, payment forms, and more with just a few clicks.', 'wpforms-lite' ); ?></p>
<?php if ( wpforms_current_user_can( 'create_forms' ) ) : ?>
<a href="<?php echo esc_url( $create_form_url ); ?>" class="button button-primary">
<?php esc_html_e( 'Create Your Form', 'wpforms-lite' ); ?>
</a>
<?php endif; ?>
<a href="<?php echo esc_url( $learn_more_url ); ?>" class="button" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Learn More', 'wpforms-lite' ); ?>
</a>
</div>
<?php
}
/**
* Widget content HTML.
*
* @since 1.5.0
* @since 1.7.4 Added hide graph parameter.
*
* @param bool $hide_graph Whether the graph is hidden.
*/
public function widget_content_html( $hide_graph = false ) {
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
/**
* Filters the content before the Dashboard Widget Chart block container (for Lite).
*
* @since 1.7.4
*
* @param string $chart_block_before Chart block before markup.
*/
echo apply_filters( 'wpforms_lite_admin_dashboard_widget_content_html_chart_block_before', '' );
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
if ( ! $hide_graph ) :
?>
<div class="wpforms-dash-widget-chart-block-container">
<div class="wpforms-dash-widget-block wpforms-dash-widget-chart-block">
<canvas id="wpforms-dash-widget-chart" width="400" height="300"></canvas>
</div>
<div class="wpforms-dash-widget-block-upgrade">
<div class="wpforms-dash-widget-modal">
<a href="#" class="wpforms-dash-widget-dismiss-chart-upgrade">
<span class="dashicons dashicons-no-alt"></span>
</a>
<h2><?php esc_html_e( 'View all Form Entries inside the WordPress Dashboard', 'wpforms-lite' ); ?></h2>
<p><?php esc_html_e( 'Form entries reports are not available.', 'wpforms-lite' ); ?>
<?php esc_html_e( 'Form entries are not stored in Lite.', 'wpforms-lite' ); ?>
<?php esc_html_e( 'Upgrade to Pro and get access to the reports.', 'wpforms-lite' ); ?></p>
<p>
<a href="<?php echo esc_url( wpforms_admin_upgrade_link( 'dashboard-widget', 'upgrade-to-pro' ) ); ?>" class="wpforms-dash-widget-upgrade-btn" target="_blank" rel="noopener noreferrer">
<?php esc_html_e( 'Upgrade to WPForms Pro', 'wpforms-lite' ); ?>
</a>
</p>
</div>
</div>
</div>
<?php endif; ?>
<div class="wpforms-dash-widget-block wpforms-dash-widget-block-title">
<h3><?php esc_html_e( 'Total Entries by Form', 'wpforms-lite' ); ?></h3>
<div class="wpforms-dash-widget-settings">
<?php
$this->timespan_select_html( 0, false );
$this->widget_settings_html( false );
?>
</div>
</div>
<div id="wpforms-dash-widget-forms-list-block" class="wpforms-dash-widget-block wpforms-dash-widget-forms-list-block">
<?php $this->forms_list_block(); ?>
</div>
<?php
}
/**
* Forms list block.
*
* @since 1.5.0
*/
public function forms_list_block() {
$forms = $this->get_entries_count_by_form();
if ( empty( $forms ) ) {
$this->forms_list_block_empty_html();
} else {
$this->forms_list_block_html( $forms );
}
}
/**
* Empty forms list block HTML.
*
* @since 1.5.0
*/
public function forms_list_block_empty_html() {
?>
<p class="wpforms-error wpforms-error-no-data-forms-list">
<?php esc_html_e( 'No entries were submitted yet.', 'wpforms-lite' ); ?>
</p>
<?php
}
/**
* Forms list block HTML.
*
* @since 1.5.0
*
* @param array $forms Forms to display in the list.
*/
public function forms_list_block_html( $forms ) {
// Number of forms to display in the forms' list before the "Show More" button appears.
$show_forms = $this->settings['forms_list_number_to_display'];
?>
<table id="wpforms-dash-widget-forms-list-table" cellspacing="0">
<?php foreach ( array_values( $forms ) as $key => $form ) : ?>
<tr <?php echo $key >= $show_forms ? 'class="wpforms-dash-widget-forms-list-hidden-el"' : ''; ?> data-form-id="<?php echo absint( $form['form_id'] ); ?>">
<td><span class="wpforms-dash-widget-form-title"><?php echo esc_html( $form['title'] ); ?></span></td>
<td><?php echo absint( $form['count'] ); ?></td>
</tr>
<?php endforeach; ?>
</table>
<?php if ( count( $forms ) > $show_forms ) : ?>
<button type="button" id="wpforms-dash-widget-forms-more" class="wpforms-dash-widget-forms-more" title="<?php esc_html_e( 'Show all forms', 'wpforms-lite' ); ?>">
<?php esc_html_e( 'Show More', 'wpforms-lite' ); ?> <span class="dashicons dashicons-arrow-down"></span>
</button>
<?php endif; ?>
<?php
}
/**
* Recommended plugin block HTML.
*
* @since 1.5.0
* @since 1.7.3 Added plugin parameter.
*
* @param array $plugin Plugin data.
*/
public function recommended_plugin_block_html( $plugin = [] ) {
if ( ! $plugin ) {
return;
}
$install_url = wp_nonce_url(
self_admin_url( 'update.php?action=install-plugin&plugin=' . rawurlencode( $plugin['slug'] ) ),
'install-plugin_' . $plugin['slug']
);
?>
<div class="wpforms-dash-widget-block wpforms-dash-widget-recommended-plugin-block">
<span class="wpforms-dash-widget-recommended-plugin">
<span class="recommended"><?php esc_html_e( 'Recommended Plugin:', 'wpforms-lite' ); ?></span>
<strong><?php echo esc_html( $plugin['name'] ); ?></strong>
<span class="sep">-</span>
<span class="action-links">
<?php if ( wpforms_can_install( 'plugin' ) ) { ?>
<a href="<?php echo esc_url( $install_url ); ?>"><?php esc_html_e( 'Install', 'wpforms-lite' ); ?></a>
<span class="sep sep-vertical">&vert;</span>
<?php } ?>
<a href="<?php echo esc_url( $plugin['more'] ); ?>?utm_source=wpformsplugin&utm_medium=link&utm_campaign=wpformsdashboardwidget"><?php esc_html_e( 'Learn More', 'wpforms-lite' ); ?></a>
</span>
</span>
<button type="button" class="wpforms-dash-widget-dismiss-icon" title="<?php esc_html_e( 'Dismiss', 'wpforms-lite' ); ?>" data-field="hide_recommended_block">
<span class="dashicons dashicons-no-alt"></span>
</button>
</div>
<?php
}
/**
* The welcome block HTML.
*
* @since 1.8.7
* @deprecated 1.9.7
*/
public function welcome_block_html() {
return '';
}
/**
* Get entries count grouped by form.
* Main point of entry to fetch form entry count data from DB.
* Cache the result.
*
* @since 1.5.0
*
* @return array
*/
public function get_entries_count_by_form(): array {
// Allow results caching to reduce a DB load.
$allow_caching = $this->settings['allow_data_caching'];
$transient_name = 'wpforms_dash_widget_lite_entries_by_form';
if ( $allow_caching ) {
$cache = get_transient( $transient_name );
/**
* Filters the cache to clear or alter its data.
*
* @since 1.5.0
*
* @param mixed $cache The cache content.
*/
$cache = apply_filters( 'wpforms_dash_widget_lite_cached_data', $cache ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
}
// is_array() detects cached empty searches.
if ( $allow_caching && is_array( $cache ) ) {
return $cache;
}
$forms = wpforms()->obj( 'form' )->get( '', [ 'fields' => 'ids' ] );
if ( empty( $forms ) || ! is_array( $forms ) ) {
return [];
}
$result = [];
foreach ( $forms as $form_id ) {
$count = absint( get_post_meta( $form_id, 'wpforms_entries_count', true ) );
if ( empty( $count ) && empty( $this->settings['display_forms_list_empty_entries'] ) ) {
continue;
}
$result[ $form_id ] = [
'form_id' => $form_id,
'count' => $count,
'title' => get_the_title( $form_id ),
];
}
if ( ! empty( $result ) ) {
// Sort forms by entries count (desc).
uasort(
$result,
static function ( $a, $b ) {
return ( $a['count'] > $b['count'] ) ? -1 : 1;
}
);
}
if ( $allow_caching ) {
// Transient lifetime in seconds. Defaults to the end of a current day.
$transient_lifetime = $this->settings['transient_lifetime'];
set_transient( $transient_name, $result, $transient_lifetime );
}
return $result;
}
/**
* Hide dashboard widget.
* Use dashboard screen options to make it visible again.
*
* @since 1.5.0
*/
public function hide_widget() {
if ( ! is_admin() || ! is_user_logged_in() ) {
return;
}
if ( ! isset( $_GET['wpforms-nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['wpforms-nonce'] ) ), 'wpforms_hide_dash_widget' ) ) {
return;
}
if ( ! isset( $_GET['wpforms-widget'] ) || $_GET['wpforms-widget'] !== 'hide' ) {
return;
}
$user_id = get_current_user_id();
$metaboxhidden = get_user_meta( $user_id, 'metaboxhidden_dashboard', true );
if ( ! is_array( $metaboxhidden ) ) {
update_user_meta( $user_id, 'metaboxhidden_dashboard', [ 'wpforms_reports_widget_lite' ] );
}
if ( is_array( $metaboxhidden ) && ! in_array( 'wpforms_reports_widget_lite', $metaboxhidden, true ) ) {
$metaboxhidden[] = 'wpforms_reports_widget_lite';
update_user_meta( $user_id, 'metaboxhidden_dashboard', $metaboxhidden );
}
$redirect_url = remove_query_arg( [ 'wpforms-widget', 'wpforms-nonce' ] );
wp_safe_redirect( $redirect_url );
exit();
}
/**
* Clear dashboard widget cached data.
*
* @since 1.5.2
*/
public static function clear_widget_cache() {
delete_transient( 'wpforms_dash_widget_lite_entries_by_form' );
}
}

View File

@@ -0,0 +1,181 @@
<?php
namespace WPForms\Lite\Admin\Education\Admin;
use WP_List_Table;
use WPForms\Admin\Education\EducationInterface;
use WPForms\Lite\Integrations\LiteConnect\LiteConnect;
use WPForms\Lite\Integrations\LiteConnect\Integration as LiteConnectIntegration;
/**
* Admin/DidYouKnow Education feature.
*
* @since 1.7.4
*/
class DidYouKnow implements EducationInterface {
/**
* Indicate if current Education feature is allowed to load.
*
* @since 1.7.4
*
* @return bool
*/
public function allow_load() {
// Load only on the `All Forms` admin page.
return wpforms_is_admin_page( 'overview' );
}
/**
* Init.
*
* @since 1.7.4
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
// Define hooks.
$this->hooks();
}
/**
* Hooks.
*
* @since 1.7.4
*/
private function hooks() {
add_action( 'wpforms_admin_overview_after_rows', [ $this, 'display' ] );
}
/**
* Messages.
*
* @since 1.7.4
*
* @return array
*/
private function messages() {
return [
[
'slug' => 'lite-connect',
'is_allowed' => LiteConnect::is_allowed(),
'cont_class' => LiteConnect::is_enabled() ? 'wpforms-education-lite-connect-setting wpforms-hidden' : 'wpforms-education-lite-connect-setting',
'title' => esc_html__( 'Entries are not stored in WPForms Lite', 'wpforms-lite' ),
'desc' => esc_html__( 'Entries are available through email notifications. If you enable Entry Backups, you can restore them once you upgrade to WPForms Pro.', 'wpforms-lite' ),
'more_title' => esc_html__( 'Enable Entry Backups', 'wpforms-lite' ),
'more_link' => admin_url( 'admin.php?page=wpforms-settings' ),
'icon' => '<svg fill="#fff" viewBox="0 0 20 14"><path d="M16.78 6.1a3 3 0 0 0-4.47-3.56A4.97 4.97 0 0 0 3 5v.28A4.48 4.48 0 0 0 4.5 14H16a4 4 0 0 0 4-4c0-1.9-1.38-3.53-3.22-3.9Zm-4.37 2-.35.34A.75.75 0 0 1 11 8.4l-1-1.07v3.91c0 .44-.34.75-.75.75h-.5a.72.72 0 0 1-.75-.75v-3.9L6.97 8.4a.75.75 0 0 1-1.06.03l-.35-.35c-.31-.3-.31-.78 0-1.06l2.9-2.9a.74.74 0 0 1 1.04 0l2.9 2.9c.32.28.32.75 0 1.06Z"/></svg>',
'item' => 1,
'enabled' => [
'cont_class' => LiteConnect::is_enabled() ? 'wpforms-education-lite-connect-enabled-info' : 'wpforms-education-lite-connect-enabled-info wpforms-hidden',
'title' => esc_html__( 'Entries Backups Are Enabled', 'wpforms-lite' ),
'more_title' => esc_html__( 'Restore Form Entries', 'wpforms-lite' ),
'more_link' => wpforms_admin_upgrade_link( 'forms-overview', 'restore-entries' ),
'more_class' => 'wpforms-is-enabled',
'desc' => $this->get_lite_connect_entries_since_info(),
],
],
];
}
/**
* Random message.
*
* @since 1.7.4
*/
private function message_rnd() {
$messages = $this->messages();
return $messages[ array_rand( $messages ) ];
}
/**
* Display message.
*
* @since 1.7.4
*
* @param WP_List_Table $wp_list_table Instance of WP_List_Table.
*/
public function display( $wp_list_table ) {
$dismissed = get_user_meta( get_current_user_id(), 'wpforms_dismissed', true );
// Do not display the message if it was dismissed.
if ( ! empty( $dismissed['edu-admin-did-you-know-overview'] ) ) {
return;
}
$message = $this->message_rnd();
// Display the message only if it is allowed.
if ( isset( $message['is_allowed'] ) && empty( $message['is_allowed'] ) ) {
return;
}
echo wpforms_render( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'education/admin/did-you-know',
[
'slug' => ! empty( $message['slug'] ) ? $message['slug'] : '',
'cols' => $wp_list_table->get_column_count(),
'icon' => ! empty( $message['icon'] ) ? $message['icon'] : '',
'title' => ! empty( $message['title'] ) ? $message['title'] : esc_html__( 'Did You Know?', 'wpforms-lite' ),
'desc' => ! empty( $message['desc'] ) ? $message['desc'] : '',
'more_title' => ! empty( $message['more_title'] ) ? $message['more_title'] : esc_html__( 'Learn More', 'wpforms-lite' ),
'more_link' => ! empty( $message['more_link'] ) ? $message['more_link'] : '',
'more_class' => ! empty( $message['more_class'] ) ? $message['more_class'] : '',
'cont_class' => ! empty( $message['cont_class'] ) ? $message['cont_class'] : '',
'enabled_title' => ! empty( $message['enabled']['title'] ) ? $message['enabled']['title'] : esc_html__( 'Did You Know?', 'wpforms-lite' ),
'enabled_desc' => ! empty( $message['enabled']['desc'] ) ? $message['enabled']['desc'] : '',
'enabled_more_title' => ! empty( $message['enabled']['more_title'] ) ? $message['enabled']['more_title'] : esc_html__( 'Learn More', 'wpforms-lite' ),
'enabled_more_link' => ! empty( $message['enabled']['more_link'] ) ? $message['enabled']['more_link'] : '',
'enabled_more_class' => ! empty( $message['enabled']['more_class'] ) ? $message['enabled']['more_class'] : '',
'enabled_cont_class' => ! empty( $message['enabled']['cont_class'] ) ? $message['enabled']['cont_class'] : '',
],
true
);
}
/**
* Generate Lite Connect entries information.
*
* @since 1.7.4
*
* @return string
*/
private function get_lite_connect_entries_since_info() {
$entries_count = LiteConnectIntegration::get_new_entries_count();
$enabled_since = LiteConnectIntegration::get_enabled_since();
$string = sprintf(
esc_html( /* translators: %d - backed up entries count. */
_n(
'%d entry backed up',
'%d entries backed up',
$entries_count,
'wpforms-lite'
)
),
absint( $entries_count )
);
if ( ! empty( $enabled_since ) ) {
$string .= ' ';
$string .= esc_html(
sprintf( /* translators: %1$s - time when Lite Connect was enabled. */
__( 'since %1$s', 'wpforms-lite' ),
wpforms_date_format( $enabled_since, '', true )
)
);
}
return $string;
}
}

View File

@@ -0,0 +1,72 @@
<?php
namespace WPForms\Lite\Admin\Education\Admin;
use \WPForms\Admin\Education;
/**
* Admin/NoticeBar Education feature for Lite.
*
* @since 1.6.6
*/
class NoticeBar implements Education\EducationInterface {
/**
* Indicate if current Education feature is allowed to load.
*
* @since 1.6.6
*
* @return bool
*/
public function allow_load() {
return wpforms_is_admin_page();
}
/**
* Init.
*
* @since 1.6.6
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
// Define hooks.
$this->hooks();
}
/**
* Hooks.
*
* @since 1.6.6
*/
public function hooks() {
add_action( 'wpforms_admin_header_before', [ $this, 'display' ] );
}
/**
* Notice bar display message.
*
* @since 1.6.6
*/
public function display() {
$dismissed = get_user_meta( get_current_user_id(), 'wpforms_dismissed', true );
if ( ! empty( $dismissed['edu-admin-notice-bar'] ) ) {
return;
}
echo wpforms_render( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'education/admin/notice-bar',
[
'upgrade_link' => wpforms_admin_upgrade_link( 'notice-bar', 'Upgrade to WPForms Pro' ),
],
true
);
}
}

View File

@@ -0,0 +1,86 @@
<?php
namespace WPForms\Lite\Admin\Education\Builder;
use WPForms_Builder_Panel_Settings;
use WPForms\Admin\Education\EducationInterface;
/**
* Confirmations Education feature.
*
* @since 1.6.9
*/
class Confirmations implements EducationInterface {
/**
* Indicate if current Education feature is allowed to load.
*
* @since 1.6.9
*
* @return bool
*/
public function allow_load() {
return wpforms_is_admin_page( 'builder' );
}
/**
* Init.
*
* @since 1.6.9
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
$this->hooks();
}
/**
* Load hooks.
*
* @since 1.6.9
*/
private function hooks() {
add_action( 'wpforms_lite_form_settings_confirmations_single_after', [ $this, 'entry_preview_settings' ], 10, 2 );
}
/**
* Add education settings located in confirmation inside the message block.
*
* @since 1.6.9
*
* @param WPForms_Builder_Panel_Settings $settings Builder panel settings.
* @param int $field_id Field ID.
*/
public function entry_preview_settings( $settings, $field_id ) {
wpforms_panel_field(
'toggle',
'confirmations',
'message_entry_preview',
$settings->form_data,
esc_html__( 'Show entry preview after confirmation', 'wpforms-lite' ),
[
'input_id' => 'wpforms-panel-field-confirmations-message_entry_preview-' . wpforms_validate_field_id( $field_id ),
'input_class' => 'wpforms-panel-field-confirmations-message_entry_preview education-modal',
'parent' => 'settings',
'subsection' => wpforms_validate_field_id( $field_id ),
'pro_badge' => true,
'data' => [
'action' => 'upgrade',
'name' => esc_html__( 'Show Entry Preview', 'wpforms-lite' ),
'utm-content' => 'Show Entry Preview',
'licence' => 'pro',
],
'attrs' => [
'disabled' => 'disabled',
],
'value' => false,
]
);
}
}

View File

@@ -0,0 +1,107 @@
<?php
namespace WPForms\Lite\Admin\Education\Builder;
use \WPForms\Admin\Education\EducationInterface;
/**
* Builder/DidYouKnow Education feature.
*
* @since 1.6.6
*/
class DidYouKnow implements EducationInterface {
/**
* Indicate if current Education feature is allowed to load.
*
* @since 1.6.6
*
* @return bool
*/
public function allow_load() {
return wpforms_is_admin_page( 'builder' );
}
/**
* Init.
*
* @since 1.6.6
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
// Define hooks.
$this->hooks();
}
/**
* Hooks.
*
* @since 1.6.6
*/
public function hooks() {
add_action( 'wpforms_builder_settings_notifications_after', [ $this, 'notifications' ] );
add_action( 'wpforms_builder_settings_confirmations_after', [ $this, 'confirmations' ] );
}
/**
* Display on the Notifications panel.
*
* @since 1.6.6
*/
public function notifications() {
$this->display(
'notifications',
[ 'desc' => esc_html__( 'You can have multiple notifications with conditional logic.', 'wpforms-lite' ) ]
);
}
/**
* Display on the Confirmations panel.
*
* @since 1.6.6
*/
public function confirmations() {
$this->display(
'confirmations',
[ 'desc' => esc_html__( 'You can have multiple confirmations with conditional logic.', 'wpforms-lite' ) ]
);
}
/**
* Display message.
*
* @since 1.6.6
*
* @param string $section Form builder section/area (slug).
* @param array $settings Notice settings array.
*/
private function display( $section, $settings ) {
$dismissed = get_user_meta( get_current_user_id(), 'wpforms_dismissed', true );
// Check if not dismissed.
if ( ! empty( $dismissed[ 'edu-builder-did-you-know-' . $section ] ) ) {
return;
}
echo wpforms_render( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'education/builder/did-you-know',
[
'desc' => $settings['desc'],
'more' => ! empty( $settings['more'] ) ? $settings['more'] : '',
'link' => wpforms_admin_upgrade_link( 'Form Builder DYK', ucfirst( $section ) ),
'section' => $section,
],
true
);
}
}

View File

@@ -0,0 +1,217 @@
<?php
namespace WPForms\Lite\Admin\Education\Builder;
use WPForms\Admin\Education;
use WPForms\Helpers\Form;
/**
* Builder/Fields Education for Lite.
*
* @since 1.6.6
*/
class Fields extends Education\Builder\Fields {
/**
* Hooks.
*
* @since 1.6.6
*/
public function hooks() {
add_filter( 'wpforms_builder_fields_buttons', [ $this, 'add_fields' ], 500 );
add_filter( 'wpforms_builder_field_button_attributes', [ $this, 'fields_attributes' ], 100, 2 );
add_action( 'wpforms_field_options_after_advanced-options', [ $this, 'field_conditional_logic' ] );
add_action( 'wpforms_builder_panel_fields_panel_content_title_after', [ $this, 'form_preview_notice' ] );
}
/**
* Add fields.
*
* @since 1.6.6
*
* @param array|mixed $fields Form fields.
*
* @return array
*/
public function add_fields( $fields ) {
$fields = (array) $fields;
foreach ( $fields as $group => $group_data ) {
$edu_fields = $this->fields->get_by_group( $group );
$edu_fields = $this->fields->set_values( $edu_fields, 'class', 'education-modal', 'empty' );
foreach ( $edu_fields as $edu_field ) {
// Skip if in the current group already exist field of this type.
if ( ! empty( wp_list_filter( $group_data, [ 'type' => $edu_field['type'] ] ) ) ) {
continue;
}
$addon = ! empty( $edu_field['addon'] ) ? $this->addons->get_addon( $edu_field['addon'] ) : [];
if ( ! empty( $addon ) ) {
$edu_field['license'] = $addon['license_level'] ?? '';
}
$fields[ $group ]['fields'][] = $edu_field;
}
}
return $fields;
}
/**
* Display a conditional logic settings section for fields inside the form builder.
*
* @since 1.6.6
*
* @param array $field Field data.
*/
public function field_conditional_logic( array $field ): void {
// Certain fields don't support conditional logic.
if ( in_array( $field['type'], [ 'pagebreak', 'divider', 'hidden' ], true ) ) {
return;
}
?>
<div class="wpforms-field-option-group wpforms-field-option-group-conditionals">
<a href="#"
class="wpforms-field-option-group-toggle education-modal"
data-name="<?php esc_attr_e( 'Smart Conditional Logic', 'wpforms-lite' ); ?>"
data-utm-content="Smart Conditional Logic">
<?php esc_html_e( 'Smart Logic', 'wpforms-lite' ); ?>
</a>
</div>
<?php
}
/**
* Adjust attributes on field buttons.
*
* @since 1.6.6
*
* @param array|mixed $atts Button attributes.
* @param array $field Button properties.
*
* @return array Attributes array.
*/
public function fields_attributes( $atts, $field ) {
$atts = (array) $atts;
$atts['data']['utm-content'] = ! empty( $field['name_en'] ) ? $field['name_en'] : '';
if ( ! empty( $field['class'] ) && $field['class'] === 'education-modal' ) {
$atts['class'][] = 'wpforms-not-available';
}
if ( empty( $field['addon'] ) ) {
return $atts;
}
$addon = $this->addons->get_addon( $field['addon'] );
if ( empty( $addon ) ) {
return $atts;
}
if ( ! empty( $addon['video'] ) ) {
$atts['data']['video'] = $addon['video'];
}
if ( ! empty( $field['license'] ) ) {
$atts['data']['license'] = $field['license'];
}
return $atts;
}
/**
* The form preview Pro fields notice.
*
* @since 1.9.4
*
* @param array $form_data Form data.
*
* @noinspection HtmlUnknownTarget
*/
public function form_preview_notice( array $form_data ): void {
$dismissed = get_user_meta( get_current_user_id(), 'wpforms_dismissed', true );
$pro_fields = Form::get_form_pro_fields( $form_data );
$is_quiz_enabled = ! empty( $form_data['settings']['quiz']['enabled'] );
// Check whether the notice is dismissed OR the form doesn't contain Pro fields.
if (
! empty( $dismissed['edu-pro-fields-form-preview-notice'] ) ||
( empty( $pro_fields ) && ! $is_quiz_enabled )
) {
return;
}
if ( $is_quiz_enabled ) {
$this->print_quiz_notice();
return;
}
$content = sprintf(
wp_kses( /* translators: %s - WPForms.com announcement page URL. */
__( 'They will not be present in the published form. <a href="%1$s" target="_blank" rel="noopener noreferrer">Upgrade now</a> to unlock these features.', 'wpforms-lite' ),
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
wpforms_admin_upgrade_link( 'Builder - Settings', 'AI Form - Pro Fields in Lite notice' )
);
$this->print_form_preview_notice(
[
'class' => 'wpforms-alert-warning',
'title' => esc_html__( 'Your Form Contains Pro Fields', 'wpforms-lite' ),
'content' => $content,
'dismiss_section' => 'pro-fields-form-preview-notice',
]
);
}
/**
* Print the Quiz addon notice.
*
* @since 1.9.9
*
* @noinspection HtmlUnknownTarget
*/
private function print_quiz_notice(): void {
$content = sprintf(
wp_kses( /* translators: %s - Upgrade license page URL. */
__( 'Quiz functionality will not be present in the published form. <a href="%1$s" target="_blank" rel="noopener noreferrer">Upgrade now</a> to unlock the Quiz Addon.', 'wpforms-lite' ),
[
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
wpforms_admin_upgrade_link( 'Builder - Settings', 'AI Form - Quiz addon in Lite notice' )
);
$this->print_form_preview_notice(
[
'class' => 'wpforms-alert-warning',
'title' => esc_html__( 'Your Form Uses the Quiz Addon', 'wpforms-lite' ),
'content' => $content,
'dismiss_section' => 'quiz-form-preview-notice',
]
);
}
}

View File

@@ -0,0 +1,135 @@
<?php
namespace WPForms\Lite\Admin\Education\Builder;
use WPForms\Admin\Education\EducationInterface;
use WPForms_Builder_Panel_Settings;
/**
* Notifications Education feature.
*
* @since 1.7.7
*/
class Notifications implements EducationInterface {
/**
* Init.
*
* @since 1.7.7
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
$this->hooks();
}
/**
* Indicate if current Education feature is allowed to load.
*
* @since 1.7.7
*
* @return bool
*/
public function allow_load() {
return wpforms_is_admin_page( 'builder' );
}
/**
* Load hooks.
*
* @since 1.7.7
*/
private function hooks() {
add_action( 'wpforms_lite_form_settings_notifications_block_content_after', [ $this, 'advanced_section' ], 10, 2 );
}
/**
* Output Notification Advanced section.
*
* @since 1.7.7
*
* @param WPForms_Builder_Panel_Settings $settings Builder panel settings.
* @param int $id Notification id.
*/
public function advanced_section( $settings, $id ) {
/**
* Filter the "Advanced" content.
*
* @since 1.8.5
*
* @param string $content The content.
* @param WPForms_Builder_Panel_Settings $settings Builder panel settings.
* @param int $id Notification id.
*/
$content = apply_filters( 'wpforms_lite_admin_education_builder_notifications_advanced_settings_content', '', $settings, $id );
$content .= wpforms_panel_field(
'toggle',
'notifications',
'file_upload_attachment_enable',
$settings->form_data,
esc_html__( 'Enable File Upload Attachments', 'wpforms-lite' ),
[
'input_class' => 'notifications_enable_file_upload_attachment_toggle education-modal',
'parent' => 'settings',
'subsection' => $id,
'pro_badge' => true,
'data' => [
'action' => 'upgrade',
'name' => esc_html__( 'File Upload Attachments', 'wpforms-lite' ),
'utm-content' => 'File Upload Attachments',
'licence' => 'pro',
],
'attrs' => [
'disabled' => 'disabled',
],
'value' => false,
],
false
);
$content .= wpforms_panel_field(
'toggle',
'notifications',
'entry_csv_attachment_enable',
$settings->form_data,
esc_html__( 'Enable Entry CSV Attachment', 'wpforms-lite' ),
[
'input_class' => 'notifications_enable_entry_csv_attachment_toggle education-modal',
'parent' => 'settings',
'subsection' => $id,
'pro_badge' => true,
'data' => [
'action' => 'upgrade',
'name' => esc_html__( 'Entry CSV Attachment', 'wpforms-lite' ),
'utm-content' => 'Entry CSV Attachment',
'licence' => 'pro',
],
'attrs' => [
'disabled' => 'disabled',
],
'value' => false,
],
false
);
// Wrap advanced settings to the unfoldable group.
wpforms_panel_fields_group(
$content,
[
'borders' => [ 'top' ],
'class' => 'wpforms-builder-notifications-advanced opened',
'default' => 'opened',
'group' => 'settings_notifications_advanced',
'title' => esc_html__( 'Advanced', 'wpforms-lite' ),
'unfoldable' => true,
]
);
}
}

View File

@@ -0,0 +1,53 @@
<?php
namespace WPForms\Lite\Admin\Education;
/**
* Education core for Lite.
*
* @since 1.6.6
*/
class Core extends \WPForms\Admin\Education\Core {
/**
* Hooks.
*
* @since 1.6.6
*/
protected function hooks() {
parent::hooks();
add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
}
/**
* Load enqueues.
*
* @since 1.6.6
*/
public function enqueues() {
parent::enqueues();
$min = wpforms_get_min_suffix();
wp_enqueue_script(
'wpforms-lite-admin-education-core',
WPFORMS_PLUGIN_URL . "assets/lite/js/admin/education/core{$min}.js",
[ 'wpforms-admin-education-core' ],
WPFORMS_VERSION,
false
);
// Builder Education styles.
if ( wpforms_is_admin_page( 'builder' ) ) {
wp_enqueue_style(
'wpforms-lite-admin-education-builder',
WPFORMS_PLUGIN_URL . "assets/lite/css/builder-education{$min}.css",
[],
WPFORMS_VERSION
);
}
}
}

View File

@@ -0,0 +1,469 @@
<?php
namespace WPForms\Lite\Admin\Education;
use WPForms\Admin\Education;
use WPForms\Integrations\LiteConnect\API;
use WPForms\Lite\Integrations\LiteConnect\LiteConnect as LiteConnectClass;
use WPForms\Lite\Integrations\LiteConnect\Integration as LiteConnectIntegration;
/**
* Admin/Settings/LiteConnect Education feature for Lite.
*
* @since 1.7.4
*/
class LiteConnect implements Education\EducationInterface {
/**
* Indicate if Lite Connect entry backup is enabled.
*
* @since 1.7.4
*
* @var int
*/
private $is_enabled;
/**
* Indicate if current Education feature is allowed to load.
*
* @since 1.7.4
*
* @return bool
*/
public function allow_load() {
// Do not load if Lite Connect integration is not allowed.
if ( ! LiteConnectClass::is_allowed() ) {
return false;
}
// Do not load if user doesn't have permissions to update settings.
if ( ! wpforms_current_user_can( wpforms_get_capability_manage_options() ) ) {
return false;
}
// Load only in certain cases.
return wp_doing_ajax() ||
wpforms_is_admin_page( 'builder' ) ||
wpforms_is_admin_page( 'settings' ) ||
wpforms_is_admin_page( 'overview' ) ||
wpforms_is_admin_page( 'entries' ) ||
$this->is_dashboard() ||
$this->is_embed_page();
}
/**
* Init.
*
* @since 1.7.4
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
$this->is_enabled = LiteConnectClass::is_enabled() ? 1 : 0;
// Define hooks.
$this->hooks();
}
/**
* Hooks.
*
* @since 1.7.4
*/
private function hooks() {
add_action( 'admin_footer', [ $this, 'modal_template' ], 10, 2 );
add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
// Ajax action.
add_action( 'wp_ajax_wpforms_update_lite_connect_enabled_setting', [ $this, 'ajax_update_lite_connect_enabled_setting' ] );
add_action( 'wp_ajax_wpforms_lite_connect_finalize', [ $this, 'ajax_lite_connect_finalize' ] );
// Content filters.
add_filter( 'wpforms_lite_admin_dashboard_widget_content_html_chart_block_before', [ $this, 'dashboard_widget_before_content' ] );
add_filter( 'wpforms_builder_output_before_toolbar', [ $this, 'top_bar_content' ] );
add_filter( 'wpforms_admin_challenge_embed_template_congrats_popup_footer', [ $this, 'challenge_popup_footer_content' ] );
}
/**
* Check whether it is the Dashboard admin page.
*
* @since 1.7.4
*
* @return bool
*/
private function is_dashboard() {
global $pagenow;
return $pagenow === 'index.php';
}
/**
* Check whether it is the form embedding admin page (Edit Post or Edit Page).
*
* @since 1.7.4
*
* @return bool
*/
private function is_embed_page() {
if ( function_exists( 'get_current_screen' ) ) {
return wpforms()->obj( 'challenge' )->is_form_embed_page();
}
global $pagenow;
return in_array( $pagenow, [ 'edit.php', 'post.php', 'post-new.php' ], true );
}
/**
* Load enqueues.
*
* @since 1.7.4
*/
public function enqueues() {
$min = wpforms_get_min_suffix();
// On the Dashboard and form embedding pages we should load additional scripts and styles.
if ( $this->is_dashboard() || $this->is_embed_page() ) {
$this->dashboard_enqueues();
}
wp_enqueue_script(
'wpforms-lite-admin-education-lite-connect',
WPFORMS_PLUGIN_URL . "assets/lite/js/admin/education/lite-connect{$min}.js",
[ 'jquery', 'wp-util' ],
WPFORMS_VERSION,
true
);
wp_localize_script(
'wpforms-lite-admin-education-lite-connect',
'wpforms_education_lite_connect',
$this->get_js_strings()
);
}
/**
* Dashboard enqueues.
*
* @since 1.7.4
*/
private function dashboard_enqueues() {
$min = wpforms_get_min_suffix();
// jQuery.Confirm Reloaded.
wp_enqueue_script(
'jquery-confirm',
WPFORMS_PLUGIN_URL . 'assets/lib/jquery.confirm/jquery-confirm.min.js',
[ 'jquery' ],
'1.0.0',
true
);
// jQuery.Confirm Reloaded.
wp_enqueue_style(
'jquery-confirm',
WPFORMS_PLUGIN_URL . 'assets/lib/jquery.confirm/jquery-confirm.min.css',
[],
'1.0.0'
);
// FontAwesome.
wp_enqueue_style(
'wpforms-font-awesome',
WPFORMS_PLUGIN_URL . 'assets/lib/font-awesome/css/all.min.css',
null,
'7.0.1'
);
// FontAwesome v4 compatibility shims.
wp_enqueue_style(
'wpforms-font-awesome-v4-shim',
WPFORMS_PLUGIN_URL . 'assets/lib/font-awesome/css/v4-shims.min.css',
null,
'4.7.0'
);
// Dashboard Education styles.
wp_enqueue_style(
'wpforms-lite-admin-education-lite-connect',
WPFORMS_PLUGIN_URL . "assets/lite/css/dashboard-education{$min}.css",
[],
WPFORMS_VERSION
);
}
/**
* Confirmation modal template.
*
* @since 1.7.4
*/
public function modal_template() {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo wpforms_render( 'education/lite-connect-modal' );
if ( wpforms_is_admin_page( 'builder' ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo wpforms_render( 'education/builder/lite-connect/ai-modal' );
}
}
/**
* Get localize strings.
*
* @since 1.7.4
*
* @return array
*/
private function get_js_strings() {
return [
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'wpforms-lite-connect-toggle' ),
'is_enabled' => $this->is_enabled,
'enable_modal' => [
'confirm' => esc_html__( 'Enable Entry Backups', 'wpforms-lite' ),
'cancel' => esc_html__( 'No Thanks', 'wpforms-lite' ),
],
'enable_ai' => [
'confirm' => esc_html__( 'Enable AI Features', 'wpforms-lite' ),
'enabled_title' => esc_html__( 'AI Features Enabled', 'wpforms-lite' ),
],
'disable_modal' => [
'title' => esc_html__( 'Are you sure?', 'wpforms-lite' ),
'content' => esc_html__( 'If you disable Lite Connect, you will no longer be able to restore your entries when you upgrade to WPForms Pro.', 'wpforms-lite' ),
'confirm' => esc_html__( 'Disable Entry Backups', 'wpforms-lite' ),
'cancel' => esc_html__( 'Cancel', 'wpforms-lite' ),
],
'update_result' => [
'enabled_title' => esc_html__( 'Entry Backups Enabled', 'wpforms-lite' ),
'enabled' => esc_html__( 'Awesome! If you decide to upgrade to WPForms Pro, you can restore your entries and will have instant access to reports.', 'wpforms-lite' ),
'disabled_title' => esc_html__( 'Entry Backups Disabled', 'wpforms-lite' ),
'disabled' => esc_html__( 'Form Entry Backups were successfully disabled.', 'wpforms-lite' ),
'error_title' => esc_html__( 'Error', 'wpforms-lite' ),
'error' => esc_html__( 'Unfortunately, the error occurs while updating Form Entry Backups setting. Please try again later.', 'wpforms-lite' ),
'close' => esc_html__( 'Close', 'wpforms-lite' ),
],
];
}
/**
* Generate Lite Connect entries information.
*
* @since 1.7.4
*
* @return string
*/
private function get_lite_connect_entries_since_info() {
$entries_count = LiteConnectIntegration::get_new_entries_count();
$enabled_since = LiteConnectIntegration::get_enabled_since();
$string = sprintf(
esc_html( /* translators: %d - backed up entries count. */
_n(
'%d entry backed up',
'%d entries backed up',
$entries_count,
'wpforms-lite'
)
),
absint( $entries_count )
);
if ( ! empty( $enabled_since ) ) {
$string .= ' ' . sprintf(
/* translators: %s - time when Lite Connect was enabled. */
esc_html__( 'since %s', 'wpforms-lite' ),
esc_html( wpforms_date_format( $enabled_since, '', true ) )
);
}
return $string;
}
/**
* Add content before the Chart block in the Dashboard Widget.
*
* @since 1.7.4
*
* @param string $content Content.
*
* @return string
*/
public function dashboard_widget_before_content( $content ) {
$toggle = wpforms_panel_field_toggle_control(
[
'control-class' => 'wpforms-setting-lite-connect-auto-save-toggle',
],
'wpforms-setting-lite-connect-enabled',
'',
esc_html__( 'Enable Form Entry Backups', 'wpforms-lite' ),
$this->is_enabled,
'disabled'
);
return wpforms_render(
'education/admin/lite-connect/dashboard-widget-before',
[
'toggle' => $toggle,
'is_enabled' => $this->is_enabled,
'entries_since_info' => $this->get_lite_connect_entries_since_info(),
],
true
);
}
/**
* Add top bar before the toolbar in the Form Builder.
*
* @since 1.7.4
*
* @param string $content Content before the toolbar. Defaults to empty string.
*
* @return string
*/
public function top_bar_content( $content ) {
if ( $this->is_enabled ) {
return $content;
}
$dismissed = get_user_meta( get_current_user_id(), 'wpforms_dismissed', true );
// Skip when top bar is dismissed.
if ( ! empty( $dismissed['edu-builder-lite-connect-top-bar'] ) ) {
return $content;
}
$toggle = wpforms_panel_field_toggle_control(
[
'control-class' => 'wpforms-setting-lite-connect-auto-save-toggle',
],
'wpforms-setting-lite-connect-enabled',
'',
esc_html__( 'Enable Form Entry Backups for Free', 'wpforms-lite' ),
$this->is_enabled,
'disabled'
);
return wpforms_render(
'education/builder/lite-connect/top-bar',
[
'toggle' => $toggle,
'is_enabled' => $this->is_enabled,
],
true
) . $content;
}
/**
* Challenge Congrats popup footer.
*
* @since 1.7.4
*
* @param string $content Footer content.
*
* @return string
*/
public function challenge_popup_footer_content( $content ) {
if ( $this->is_enabled ) {
return $content;
}
$toggle = wpforms_panel_field_toggle_control(
[
'control-class' => 'wpforms-setting-lite-connect-auto-save-toggle',
],
'wpforms-setting-lite-connect-enabled',
'',
esc_html__( 'Enable Form Entry Backups for Free', 'wpforms-lite' ),
$this->is_enabled,
'disabled'
);
return wpforms_render(
'education/admin/lite-connect/challenge-popup-footer',
[
'toggle' => $toggle,
'is_enabled' => $this->is_enabled,
],
true
);
}
/**
* AJAX checks.
*
* @since 1.9.1
*/
private function ajax_checks() {
// Run a security check.
check_ajax_referer( 'wpforms-lite-connect-toggle', 'nonce' );
// Check for permissions.
if ( ! wpforms_current_user_can( wpforms_get_capability_manage_options() ) ) {
wp_send_json_error( esc_html__( 'You do not have permission.', 'wpforms-lite' ) );
}
}
/**
* AJAX action: update Lite Connect Enabled setting.
*
* @since 1.7.4
*/
public function ajax_update_lite_connect_enabled_setting() {
$this->ajax_checks();
$slug = LiteConnectClass::SETTINGS_SLUG;
$settings = get_option( 'wpforms_settings', [] );
$settings[ $slug ] = ! empty( $_POST['value'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
wpforms_update_settings( $settings );
if ( ! $settings[ $slug ] ) {
wp_send_json_success( '' );
}
// Reset generate key attempts counter.
update_option( API::GENERATE_KEY_ATTEMPT_COUNTER_OPTION, 0 );
// We have to start requesting site keys in ajax, turning on the LC functionality.
// First, the request to the API server will be sent.
// Second, the server will respond to our callback URL /wpforms/auth/key/nonce, and the site key will be stored in the DB.
// Third, we have to get access via a separate HTTP request.
( new LiteConnectIntegration() )->update_keys(); // First request here.
wp_send_json_success( $this->get_lite_connect_entries_since_info() );
}
/**
* AJAX action: Finalize Lite Connect setup.
*
* @since 1.9.1
*/
public function ajax_lite_connect_finalize() {
$this->ajax_checks();
if ( $this->is_enabled ) {
( new LiteConnectIntegration() )->update_keys(); // Simulate third request.
}
wp_send_json_success();
}
}

View File

@@ -0,0 +1,130 @@
<?php
namespace WPForms\Lite\Admin\Pages;
/**
* Addons page for Lite.
*
* @since 1.6.7
*/
class Addons {
/**
* Page slug.
*
* @since 1.6.7
*
* @type string
*/
const SLUG = 'addons';
/**
* Determine if current class is allowed to load.
*
* @since 1.6.7
*
* @return bool
*/
public function allow_load() {
return wpforms_is_admin_page( self::SLUG );
}
/**
* Init.
*
* @since 1.6.7
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
// Define hooks.
$this->hooks();
}
/**
* Hooks.
*
* @since 1.6.7
*/
public function hooks() {
add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
add_action( 'admin_notices', [ $this, 'notices' ] );
add_action( 'wpforms_admin_page', [ $this, 'output' ] );
}
/**
* Add appropriate scripts to the Addons page.
*
* @since 1.6.7
*/
public function enqueues() {
// JavaScript.
wp_enqueue_script(
'listjs',
WPFORMS_PLUGIN_URL . 'assets/lib/list.min.js',
[ 'jquery' ],
'1.5.0',
false
);
}
/**
* Notices.
*
* @since 1.6.7.1
*/
public function notices() {
$notice = sprintf(
'<p class="notice-title"><strong>%1$s</strong></p>
<p>%2$s</p>
<p class="notice-buttons">
<a href="%3$s" class="wpforms-btn wpforms-btn-orange wpforms-btn-md" target="_blank" rel="noopener noreferrer">
%4$s
</a>
</p>',
esc_html__( 'Upgrade to Unlock WPForms Addons', 'wpforms-lite' ),
esc_html__( 'Access powerful marketing and payment integrations, advanced form fields, and more when you purchase our Plus, Pro, or Elite plans.', 'wpforms-lite' ),
esc_url( wpforms_admin_upgrade_link( 'addons', 'All Addons' ) ),
esc_html__( 'Upgrade Now', 'wpforms-lite' )
);
\WPForms\Admin\Notice::info(
$notice,
[ 'autop' => false ]
);
}
/**
* Render the Addons page.
*
* @since 1.6.7
*/
public function output() {
$addons = wpforms()->obj( 'addons' )->get_all();
if ( empty( $addons ) ) {
return;
}
// WPForms 1.8.7 core includes Custom Captcha.
// The Custom Captcha addon will only work on WPForms 1.8.6 and earlier versions.
unset( $addons['wpforms-captcha'] );
echo wpforms_render( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'admin/addons',
[
'upgrade_link_base' => wpforms_admin_upgrade_link( 'addons' ),
'addons' => $addons,
],
true
);
}
}

View File

@@ -0,0 +1,171 @@
<?php
namespace WPForms\Lite\Admin\Settings;
use WPForms\Admin\Education\Helpers;
/**
* Settings Access tab.
*
* @since 1.5.8
*/
class Access {
/**
* View slug.
*
* @since 1.5.8
*
* @var string
*/
const SLUG = 'access';
/**
* Constructor.
*
* @since 1.5.8
*/
public function __construct() {
$this->hooks();
}
/**
* Hooks.
*
* @since 1.5.8
*/
public function hooks() {
add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
add_filter( 'wpforms_settings_tabs', [ $this, 'add_tab' ] );
add_filter( 'wpforms_settings_defaults', [ $this, 'add_section' ] );
}
/**
* Enqueues.
*
* @since 1.5.8
*/
public function enqueues() {
if ( ! wpforms_is_admin_page( 'settings', self::SLUG ) ) {
return;
}
// Lity.
wp_enqueue_style(
'wpforms-lity',
WPFORMS_PLUGIN_URL . 'assets/lib/lity/lity.min.css',
null,
'3.0.0'
);
wp_enqueue_script(
'wpforms-lity',
WPFORMS_PLUGIN_URL . 'assets/lib/lity/lity.min.js',
[ 'jquery' ],
'3.0.0',
true
);
}
/**
* Add Access tab.
*
* @since 1.5.8
*
* @param array $tabs Array of tabs.
*
* @return array Array of tabs.
*/
public function add_tab( $tabs ) {
$tab = [
self::SLUG => [
'name' => esc_html__( 'Access', 'wpforms-lite' ),
'form' => false,
'submit' => false,
],
];
return wpforms_list_insert_after( $tabs, 'geolocation', $tab );
}
/**
* Add Access settings section.
*
* @since 1.5.8
*
* @param array $settings Settings sections.
*
* @return array
*/
public function add_section( $settings ) {
$settings[ self::SLUG ][ self::SLUG . '-page' ] = [
'id' => self::SLUG . '-page',
'content' => wpforms_render( 'education/admin/page', $this->template_data(),true ),
'type' => 'content',
'no_label' => true,
];
return $settings;
}
/**
* Get the template data.
*
* @since 1.8.6
*
* @return array
*/
private function template_data(): array {
$images_url = WPFORMS_PLUGIN_URL . 'assets/images/lite-settings-access/';
return [
'features' => [
__( 'Create Forms', 'wpforms-lite' ),
__( 'Delete Forms', 'wpforms-lite' ),
__( 'Edit Forms Entries', 'wpforms-lite' ),
__( 'Edit Forms', 'wpforms-lite' ),
__( 'Delete Others Forms', 'wpforms-lite' ),
__( 'Edit Others Forms Entries', 'wpforms-lite' ),
__( 'Edit Others Forms', 'wpforms-lite' ),
__( 'View Forms Entries', 'wpforms-lite' ),
__( 'Delete Forms Entries', 'wpforms-lite' ),
__( 'View Forms', 'wpforms-lite' ),
__( 'View Others Forms Entries', 'wpforms-lite' ),
__( 'Delete Others Forms Entries', 'wpforms-lite' ),
__( 'View Others Forms', 'wpforms-lite' ),
],
'images' => [
[
'url' => $images_url . 'screenshot-access-controls.png',
'url2x' => $images_url . 'screenshot-access-controls@2x.png',
'title' => __( 'Simple Built-in Controls', 'wpforms-lite' ),
],
[
'url' => $images_url . 'screenshot-members.png',
'url2x' => $images_url . 'screenshot-members@2x.png',
'title' => __( 'Members Integration', 'wpforms-lite' ),
],
[
'url' => $images_url . 'screenshot-user-role-editor.png',
'url2x' => $images_url . 'screenshot-user-role-editor@2x.png',
'title' => __( 'User Role Editor Integration', 'wpforms-lite' ),
],
],
'utm_medium' => 'Settings - Access',
'utm_content' => 'Access Controls',
'heading_title' => __( 'Access Controls', 'wpforms-lite' ),
'heading_description' => sprintf(
'<p>%1$s</p>',
__( 'Access controls allows you to manage and customize access to WPForms functionality. You can easily grant or restrict access using the simple built-in controls, or use our official integrations with Members and User Role Editor plugins.', 'wpforms-lite' )
),
'badge' => __( 'Pro', 'wpforms-lite' ),
'features_description' => __( 'Custom access to the following capabilities…', 'wpforms-lite' ),
];
}
}

View File

@@ -0,0 +1,221 @@
<?php
namespace WPForms\Lite\Emails;
use WPForms\Lite\Reports\EntriesCount;
use WPForms\Emails\Summaries as BaseSummaries;
/**
* Email Summaries.
*
* @since 1.8.8
*/
class Summaries extends BaseSummaries {
/**
* Whether counting entries is allowed for Lite users.
*
* @since 1.8.8
*
* @var bool
*/
private $allow_entries_count_lite;
/**
* Constructor for the class.
* Initializes the object and registers the Lite weekly entries count cron schedule.
*
* @since 1.8.8
*/
public function __construct() {
// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName
// Disabling this filter will prevent entries submission count from being updated.
/** This filter is documented in /lite/wpforms-lite.php */
$this->allow_entries_count_lite = apply_filters( 'wpforms_dash_widget_allow_entries_count_lite', true );
// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
parent::__construct();
// Register the Lite weekly entries count cron schedule.
$this->register_entries_count_schedule();
}
/**
* Hooks.
*
* @since 1.8.8
*/
public function hooks() {
parent::hooks();
// The following schedule is essential for the Lite version.
// Regardless of the "Weekly Summaries" feature being disabled or enabled,
// it ensures that entries numbers are consistently updated.
if ( ! $this->allow_entries_count_lite ) {
return;
}
add_action( 'wpforms_weekly_entries_count_cron', [ $this, 'entries_count_cron' ] );
}
/**
* Adjusts the Lite weekly entries count cron schedule.
*
* This function modifies the Lite weekly entries count cron schedule by reducing the interval by 5 seconds.
*
* @since 1.8.8
* @deprecated 1.9.1
*
* @param array $schedules WP cron schedules.
*
* @return array
*/
public function weekly_entries_count( $schedules ) {
_deprecated_function( __METHOD__, '1.9.1 of the WPForms plugin' );
$schedules['wpforms_weekly_entries_count'] = [
'interval' => $this->get_next_launch_time() - time(),
'display' => esc_html__( 'Calculate WPForms Lite Weekly Entries Count', 'wpforms-lite' ),
];
return $schedules;
}
/**
* Run the cron job to update entries count for Lite users.
*
* This function retrieves the current entries count for Lite users, calculates the count for the
* previous week, and updates the necessary post meta data for trend calculations.
*
* @since 1.8.8
*/
public function entries_count_cron() {
// Get entries count for Lite users.
$entries = ( new EntriesCount() )->get_by_form();
// Exit if there are no form entries to update.
if ( empty( $entries ) ) {
return;
}
foreach ( $entries as $form_id => &$form ) {
// Set total entries count to the current count.
$form['total'] = $form['count'];
// Retrieve the previous week's count data from post meta.
$previous_week_count = get_post_meta( $form_id, 'wpforms_entries_count_previous_week', true );
// Continue to the next form if the count data is not valid.
if ( ! is_array( $previous_week_count ) || count( $previous_week_count ) !== 3 ) {
$prev_count_previous_week = $form['total'];
// Set the previous week's count zero "0" if the form was published less than or equal to 7 days ago.
if ( $this->is_form_created_in_7days( $form_id ) ) {
$prev_count_previous_week = 0;
}
update_post_meta( $form_id, 'wpforms_entries_count_previous_week', [ $form['total'], $form['total'], $prev_count_previous_week ] );
continue;
}
list( $total_previous_week, $count_previous_week ) = $previous_week_count;
// Calculate count, count_previous_week, and trends.
$form['count'] = $form['total'] - $total_previous_week;
if ( count( array_unique( $previous_week_count ) ) === 1 ) {
// If the previous week's count is the same as the current count, skip trends calculation.
update_post_meta( $form_id, 'wpforms_entries_count_previous_week_skip_trends', true );
} else {
// If the previous week's count is different from the current count, calculate trends.
delete_post_meta( $form_id, 'wpforms_entries_count_previous_week_skip_trends' );
}
// Update post meta data for trend calculations.
update_post_meta( $form_id, 'wpforms_entries_count_previous_week', [ $form['total'], $form['count'], $count_previous_week ] );
}
}
/**
* Get form entries.
*
* @since 1.8.8
*
* @return array
*/
protected function get_entries(): array {
return ( new EntriesCount() )->get_form_trends();
}
/**
* Register entries count schedule.
*
* @since 1.8.8
*/
private function register_entries_count_schedule() {
if ( ! $this->allow_entries_count_lite && wp_next_scheduled( 'wpforms_weekly_entries_count_cron' ) ) {
wp_clear_scheduled_hook( 'wpforms_weekly_entries_count_cron' );
return;
}
if ( $this->allow_entries_count_lite && ! wp_next_scheduled( 'wpforms_weekly_entries_count_cron' ) ) {
// Since v1.9.1 we use a single event and manually reoccur it
// because a recurring event cannot guarantee
// its firing at the same time during WP_CLI execution.
wp_schedule_single_event( $this->get_next_launch_time(), 'wpforms_weekly_entries_count_cron' );
}
}
/**
* Get next Monday midnight with WordPress offset.
*
* @since 1.9.1
*
* @return int
*/
protected function get_next_launch_time(): int {
$datetime = date_create( 'next monday', wp_timezone() );
if ( ! $datetime ) {
return time() + WEEK_IN_SECONDS;
}
return absint( $datetime->getTimestamp() );
}
/**
* Check if the given form_id was published less than or equal to 7 days ago.
*
* @since 1.8.8
*
* @param int $form_id The ID of the form (post).
*
* @return bool
*/
private function is_form_created_in_7days( int $form_id ): bool {
// Get the form (post) publish date.
$date_created = get_post_field( 'post_date', $form_id, 'raw' );
// If the form date is not available, return false.
if ( empty( $date_created ) ) {
return false;
}
// Calculate the time difference between the post date and the current date.
$time_difference = time() - strtotime( $date_created );
// Compare the time difference with 7 days in seconds.
return $time_difference <= 7 * DAY_IN_SECONDS;
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace WPForms\Lite\Integrations\Abilities;
use WP_Error;
use WPForms\Integrations\Abilities\Abilities as AbilitiesBase;
/**
* WordPress Abilities API Integration for WPForms Lite.
*
* @since 1.9.9
*/
class Abilities extends AbilitiesBase {
/**
* Register WPForms abilities for Lite version.
*
* @since 1.9.9
*/
public function register_abilities(): void {
// Register common abilities (list_forms, get_form).
$this->register_common_abilities();
// Lite-specific: Register form stats ability (basic).
$this->register_form_stats_ability();
}
/**
* Register the form_stats ability (Lite version - basic stats with upsell).
*
* @since 1.9.9
*/
protected function register_form_stats_ability(): void {
wp_register_ability(
self::ABILITY_NAMESPACE . '/get-form-stats',
[
'label' => __( 'Get Form Stats', 'wpforms-lite' ),
'description' => __( 'Get basic statistics for a WPForms form. Upgrade to Pro for detailed entry data.', 'wpforms-lite' ),
'category' => self::CATEGORY_SLUG,
'execute_callback' => [ $this, 'ability_get_form_stats' ],
'permission_callback' => [ $this, 'check_view_single_form_permission' ],
'input_schema' => [
'type' => 'object',
'properties' => [
'form_id' => [
'description' => __( 'The ID of the form to get stats for.', 'wpforms-lite' ),
'type' => 'integer',
'required' => true,
'minimum' => 1,
],
],
'required' => [ 'form_id' ],
],
'output_schema' => [
'type' => 'object',
'properties' => [
'form_id' => [ 'type' => 'integer' ],
'entries_available' => [ 'type' => 'boolean' ],
'message' => [ 'type' => 'string' ],
],
],
'meta' => [
'annotations' => [
'readonly' => true,
'destructive' => false,
'idempotent' => true,
],
'show_in_rest' => true,
'mcp' => [
'public' => true,
],
],
]
);
}
/**
* Ability callback: Get form stats (Lite version).
*
* @since 1.9.9
*
* @param mixed $input Input data.
*
* @return array|WP_Error
*/
public function ability_get_form_stats( $input = null ) {
$args = $this->normalize_input( $input );
$form_id = absint( $args['form_id'] ?? 0 );
$form_handler = $this->get_form_handler();
if ( is_wp_error( $form_handler ) ) {
return $form_handler;
}
$form = $form_handler->get( $form_id );
if ( empty( $form ) ) {
return new WP_Error(
'wpforms_form_not_found',
__( 'Form not found.', 'wpforms-lite' ),
[ 'status' => 404 ]
);
}
// Lite version returns limited stats with the upsell message.
return [
'form_id' => $form_id,
'entries_available' => false,
'message' => __( 'Entry statistics require WPForms Pro. Upgrade to access detailed form submission data.', 'wpforms-lite' ),
];
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPForms\Lite\Integrations\Elementor;
use WPForms\Integrations\Elementor\ThemesData as ThemesDataBase;
/**
* Themes data for Gutenberg block for Lite.
*
* @since 1.9.6
*/
class ThemesData extends ThemesDataBase {
/**
* WPForms themes JSON file path.
*
* Relative to the WPForms plugin directory.
*
* @since 1.9.6
*
* @var string
*/
protected const THEMES_WPFORMS_JSON_PATH = 'assets/lite/js/integrations/elementor/themes.json';
}

View File

@@ -0,0 +1,116 @@
<?php
namespace WPForms\Lite\Integrations\Gutenberg;
use WPForms\Integrations\Gutenberg\FormSelector as FormSelectorBase;
use WPForms\Integrations\Gutenberg\RestApi;
/**
* Gutenberg block for Lite.
*
* @since 1.8.8
*/
class FormSelector extends FormSelectorBase {
/**
* Load an integration.
*
* @since 1.8.8
*/
public function load() {
$this->themes_data_obj = new ThemesData();
parent::load();
}
/**
* Integration hooks.
*
* @since 1.8.8
*/
protected function hooks() {
add_action( 'rest_api_init', [ $this, 'init_rest' ] );
parent::hooks();
}
/**
* Initialize rest API.
*
* @since 1.8.8
*/
public function init_rest() {
if ( ! $this->rest_api_obj ) {
$this->rest_api_obj = new RestApi( $this, $this->themes_data_obj );
}
}
/**
* Register WPForms Gutenberg block styles.
*
* @since 1.8.8
*/
protected function register_styles() {
if ( ! is_admin() ) {
return;
}
parent::register_styles();
// FontAwesome.
wp_enqueue_style(
'wpforms-font-awesome',
WPFORMS_PLUGIN_URL . 'assets/lib/font-awesome/css/all.min.css',
null,
'7.0.1'
);
// FontAwesome v4 compatibility shims.
wp_enqueue_style(
'wpforms-font-awesome-v4-shim',
WPFORMS_PLUGIN_URL . 'assets/lib/font-awesome/css/v4-shims.min.css',
null,
'4.7.0'
);
}
/**
* Load WPForms Gutenberg block scripts.
*
* @since 1.8.8
*/
public function enqueue_block_editor_assets() {
parent::enqueue_block_editor_assets();
$min = wpforms_get_min_suffix();
wp_enqueue_script(
'wpforms-generic-utils',
WPFORMS_PLUGIN_URL . "assets/js/share/utils{$min}.js",
[ 'jquery' ],
WPFORMS_VERSION,
true
);
if ( ! $this->is_legacy_block() ) {
wp_enqueue_script(
'wpforms-gutenberg-form-selector',
WPFORMS_PLUGIN_URL . "assets/lite/js/integrations/gutenberg/formselector.es5{$min}.js",
[ 'wp-blocks', 'wp-i18n', 'wp-element', 'jquery', 'wpforms-admin-education-core', 'wpforms-generic-utils' ],
WPFORMS_VERSION,
true
);
}
wp_localize_script(
'wpforms-gutenberg-form-selector',
'wpforms_gutenberg_form_selector',
$this->get_localize_data()
);
}
}

View File

@@ -0,0 +1,24 @@
<?php
namespace WPForms\Lite\Integrations\Gutenberg;
use WPForms\Integrations\Gutenberg\ThemesData as ThemesDataBase;
/**
* Themes data for Gutenberg block for Lite.
*
* @since 1.8.8
*/
class ThemesData extends ThemesDataBase {
/**
* WPForms themes JSON file path.
*
* Relative to WPForms plugin directory.
*
* @since 1.8.8
*
* @var string
*/
const THEMES_WPFORMS_JSON_PATH = 'assets/lite/js/integrations/gutenberg/themes.json';
}

View File

@@ -0,0 +1,165 @@
<?php
namespace WPForms\Lite\Integrations\LiteConnect;
use WPForms\Admin\Notice;
use WPForms\Helpers\Transient;
/**
* Handles admin functionalities and setup for the application.
*
* @since 1.10.0.1
*/
class Admin {
/**
* Dismiss notice slug.
*
* @since 1.10.0.1
*/
private const DISMISS_NOTICE_SLUG = 'lite_connect_send_error_alert';
/**
* Initializes the constructor and setup hooks.
*
* @since 1.10.0.1
*/
public function __construct() {
$this->hooks();
}
/**
* Registers hooks to manage the display of notices on specific pages.
*
* @since 1.10.0.1
*/
private function hooks(): void {
// Reset expired dismissed notice to allow re-displaying after one week.
add_filter( 'option_wpforms_admin_notices', [ $this, 'reset_expired_notice' ] );
// Display notices only on WPForms pages.
if ( $this->is_notice_target_page() ) {
// Display an admin notice if there are entries available to import.
add_action( 'admin_notices', [ $this, 'display_error_notices' ] );
}
}
/**
* Reset the dismissed notice if it was dismissed more than a week ago.
*
* @since 1.10.0.1
*
* @param mixed $notices Dismissed notices option value.
*
* @return array Modified dismissed notices option value.
*/
public function reset_expired_notice( $notices ): array { // phpcs:ignore WPForms.PHP.HooksMethod.InvalidPlaceForAddingHooks
$notices = (array) $notices;
if ( ! isset( $notices[ self::DISMISS_NOTICE_SLUG ] ) ) {
return $notices;
}
$notice_time = $notices[ self::DISMISS_NOTICE_SLUG ]['time'] ?? 0;
if ( ( time() - $notice_time ) <= WEEK_IN_SECONDS ) {
return $notices;
}
Transient::delete( SendEntryTask::SEND_ERROR_KEY );
unset( $notices[ self::DISMISS_NOTICE_SLUG ] );
remove_filter( 'option_wpforms_admin_notices', [ $this, 'reset_expired_notice' ] );
update_option( 'wpforms_admin_notices', $notices, true );
add_filter( 'option_wpforms_admin_notices', [ $this, 'reset_expired_notice' ] );
return $notices;
}
/**
* Display error notices for entry backup failures.
*
* @since 1.10.0.1
*
* @noinspection HtmlUnknownTarget
*/
public function display_error_notices(): void {
if ( ! self::has_repeated_errors() ) {
return;
}
Notice::error(
sprintf(
wp_kses( /* translators: %s - WPForms support URL. */
__( '<strong>Entry Backup Failures Detected</strong><br>Some entry backups may not have been saved. This is usually caused by a scheduling issue on your site. Please <a href="%s" target="_blank" rel="noopener noreferrer">contact Support</a> so we can help resolve it and ensure your entries are protected.', 'wpforms-lite' ),
[
'strong' => [],
'br' => [],
'a' => [
'href' => [],
'target' => [],
'rel' => [],
],
]
),
esc_url(
wpforms_utm_link(
'https://wpforms.com/account/support/',
'Admin',
'Contact Support - Lite Connect Backup Failure'
)
)
),
[
'dismiss' => Notice::DISMISS_GLOBAL,
'slug' => self::DISMISS_NOTICE_SLUG,
]
);
}
/**
* Checks if there are repeated errors in the cached error data.
*
* @since 1.10.0.1
*
* @return bool
*/
public static function has_repeated_errors(): bool {
$lite_connect_send_errors = Transient::get( SendEntryTask::SEND_ERROR_KEY );
if ( empty( $lite_connect_send_errors ) || ! is_array( $lite_connect_send_errors ) ) {
return false;
}
foreach ( $lite_connect_send_errors as $errors ) {
if ( count( $errors ) >= 4 ) {
return true;
}
}
return false;
}
/**
* Determines if the current page is the target page for displaying a notice.
*
* @since 1.10.0.1
*
* @return bool True if the current page is the target page, false otherwise.
*/
private function is_notice_target_page(): bool {
global $pagenow;
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$is_dashboard_page = $pagenow === 'index.php' && empty( $_GET['page'] );
return $is_dashboard_page || wpforms_is_admin_page( 'overview' ) || wpforms_is_admin_page( 'settings' );
}
}

View File

@@ -0,0 +1,109 @@
<?php
namespace WPForms\Lite\Integrations\LiteConnect;
use WPForms\Helpers\Crypto;
/**
* Integration between Lite Connect API and WPForms Lite.
*
* @since 1.7.4
*/
class Integration extends \WPForms\Integrations\LiteConnect\Integration {
/**
* Encrypt the form entry and submit it to the Lite Connect API.
*
* If the regular wp_remote_post() request fail for any reasons, then an
* Action Scheduler task will be created to retry a couple of minutes later.
*
* @since 1.7.4
*
* @param array $entry_args The entry data.
* @param array $form_data The form data.
*
* @return false|string
*/
public function submit( $entry_args, $form_data ) {
if ( ! is_array( $entry_args ) ) {
return false;
}
$entry_args['form_data'] = $form_data;
// Encrypt entry using the WPForms Crypto class.
$entry_data = Crypto::encrypt( wp_json_encode( $entry_args ) );
// We have to start requesting site keys in ajax, turning on the LC functionality.
// First, the request to the API server will be sent.
// Second, the server will respond to our callback URL /wpforms/auth/key/nonce, and the site key will be stored in the DB.
// Third, we have to get access via a separate HTTP request.
$this->update_keys(); // Third request here.
// Submit entry to the Lite Connect API.
$response = $this->add_form_entry( $this->auth['access_token'], $entry_args['form_id'], $entry_data );
// Confirm if entry has been added successfully to the Lite Connect API.
if ( $response ) {
$response = json_decode( $response, true );
}
if ( isset( $response['error'] ) && $response['error'] === 'Access token is invalid or expired.' ) {
// Force to re-generate access token in case it is invalid.
$this->get_access_token( $this->get_site_key(), true );
}
if ( ! isset( $response['status'] ) || $response['status'] !== 'success' ) {
/**
* If Lite Connect API is not available in the add_form_entry()
* request above, then a task is created to run it later via Action
* Scheduler.
*/
( new SendEntryTask() )->create( $entry_args['form_id'], $entry_data );
}
// Increase the entries count if the entry has been added successfully.
if ( isset( $response['status'] ) && $response['status'] === 'success' ) {
$this->increase_entries_count( $entry_args['form_id'] );
}
if ( ! empty( $response['error'] ) ) {
wpforms_log(
'Lite Connect: error submitting form entry',
[
'response' => $response,
'entry_args' => $entry_args,
],
[
'type' => [ 'error' ],
'form_id' => $entry_args['form_id'],
]
);
}
return $response;
}
/**
* Increases the Lite Connect entries count.
*
* @since 1.7.4
*
* @param int|false $form_id The form ID.
*/
public function increase_entries_count( $form_id = false ) {
self::maybe_set_entries_count();
update_option( self::LITE_CONNECT_ENTRIES_COUNT_OPTION, self::get_entries_count() + 1 );
// Increase the form entries count.
// It allows counting entries on per form level.
if ( ! empty( $form_id ) ) {
$count = self::get_form_entries_count( (int) $form_id );
update_post_meta( $form_id, self::LITE_CONNECT_FORM_ENTRIES_COUNT_META, ++$count );
}
}
}

View File

@@ -0,0 +1,187 @@
<?php
namespace WPForms\Lite\Integrations\LiteConnect;
/**
* Class LiteConnect for WPForms Lite.
*
* @since 1.7.4
*/
class LiteConnect extends \WPForms\Integrations\LiteConnect\LiteConnect {
/**
* The Integration object.
*
* @since 1.7.4
*
* @var Integration
*/
private $integration;
/**
* Send Entry Task object.
*
* @since 1.7.4
*
* @var SendEntryTask
*/
private $send_entry_task;
/**
* Whether Lite Connect is enabled.
*
* @since 1.7.4
*
* @return bool
*/
public static function is_enabled() {
// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName
/**
* Determine whether LiteConnect is enabled on the WPForms > Settings admin page.
*
* @since 1.7.4
*
* @param bool $is_enabled Is LiteConnect enabled on WPForms > Settings page?
*/
return (bool) apply_filters( 'wpforms_lite_integrations_lite_connect_is_enabled', wpforms_setting( self::SETTINGS_SLUG ) );
// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
}
/**
* Load the integration.
*
* @since 1.7.4
*/
public function load() {
parent::load();
// Do not load if user doesn't have permissions to update settings.
if ( ! wpforms_current_user_can( wpforms_get_capability_manage_options() ) ) {
return;
}
// Hooks.
$this->hooks();
// Process any pending submissions to the API, even if the Lite Connect integration is disabled.
$this->send_entry_task = new SendEntryTask();
// It won't load if the Lite Connect integration is not enabled.
if ( ! self::is_enabled() ) {
return;
}
// We always need to instance the Integration class as part of the load process for the Lite Connect integration.
$this->integration = new Integration();
if ( is_admin() ) {
new Admin();
}
}
/**
* Hooks.
*
* @since 1.7.4
*/
private function hooks() {
// Add Lite Connect option to settings.
add_filter( 'wpforms_settings_defaults', [ $this, 'settings_option' ] );
// Automatically save the timestamp when Lite Connect was enabled first time.
add_filter( 'wpforms_update_settings', [ $this, 'update_enabled_settings' ] );
}
/**
* Add "Lite Connect: Enable Entry Backups" to the WPForms Lite settings.
*
* @since 1.7.4
*
* @param array $settings WPForms settings.
*
* @return array
*/
public function settings_option( $settings ) {
$setting = [
self::SETTINGS_SLUG => [
'id' => self::SETTINGS_SLUG,
'name' => esc_html__( 'Lite Connect', 'wpforms-lite' ),
'label' => esc_html__( 'Enable Entry Backups', 'wpforms-lite' ),
'type' => 'toggle',
'is-important' => true,
'control-class' => 'wpforms-setting-lite-connect-auto-save-toggle',
'input-attr' => 'disabled',
'desc-on' => sprintf(
wp_kses( /* translators: %s - upgrade to WPForms Pro landing page URL. */
__( '<strong>Your form entries are not being stored locally, but are backed up remotely.</strong> If you <a href="%s" target="_blank" rel="noopener noreferrer" class="wpforms-upgrade-modal">upgrade to WPForms PRO</a>, you can restore your entries and theyll be available in the WordPress dashboard. Entry backups expire after 1 year.', 'wpforms-lite' ),
[
'a' => [
'href' => [],
'class' => [],
'target' => [],
'rel' => [],
],
'strong' => [],
]
),
esc_url( wpforms_admin_upgrade_link( 'settings-lite-connect-enabled' ) )
),
'desc-off' => sprintf(
wp_kses( /* translators: %s - upgrade to WPForms Pro landing page URL. */
__( '<strong>Your form entries are not being stored in WordPress, and your entry backups are not active.</strong> If there\'s a problem with deliverability, you\'ll lose form entries. We recommend that you enable Entry Backups, especially if you\'re considering <a href="%s" target="_blank" rel="noopener noreferrer" class="wpforms-upgrade-modal">upgrading to WPForms PRO</a>.', 'wpforms-lite' ),
[
'a' => [
'href' => [],
'class' => [],
'target' => [],
'rel' => [],
],
'strong' => [],
]
),
esc_url( wpforms_admin_upgrade_link( 'settings-lite-connect-disabled', 'Upgrade to WPForms Pro text Link' ) )
),
],
];
$settings['general'] = wpforms_list_insert_after( $settings['general'], 'license-key', $setting );
return $settings;
}
/**
* Automatically save the additional info when Lite Connect was enabled first time.
*
* @since 1.7.4
*
* @param array $settings WPForms settings.
*
* @return array
*/
public function update_enabled_settings( $settings ) {
if ( empty( $settings[ self::SETTINGS_SLUG ] ) ) {
return $settings;
}
$since = self::SETTINGS_SLUG . '-since';
$email = self::SETTINGS_SLUG . '-email';
if ( empty( $settings[ $since ] ) ) {
$settings[ $since ] = time();
}
if ( empty( $settings[ $email ] ) ) {
$user = wp_get_current_user();
$settings[ $email ] = $user && ! empty( $user->user_email ) ? $user->user_email : get_option( 'admin_email' );
}
return $settings;
}
}

View File

@@ -0,0 +1,161 @@
<?php
namespace WPForms\Lite\Integrations\LiteConnect;
use WPForms\Helpers\Transient;
use WPForms\Integrations\LiteConnect\API;
use WPForms\Tasks\Meta;
/**
* Class SendEntryTask.
*
* @since 1.7.4
*/
class SendEntryTask extends Integration {
/**
* Task name.
*
* @since 1.7.4
*
* @var string
*/
public const LITE_CONNECT_TASK = 'wpforms_lite_connect_send_entry';
/**
* Transient cache error key.
*
* @since 1.10.0.1
*/
public const SEND_ERROR_KEY = 'lite_connect_send_entry_error';
/**
* SendEntryTask constructor.
*
* @since 1.7.4
*/
public function __construct() {
parent::__construct();
$this->hooks();
}
/**
* Initialize the hooks.
*
* @since 1.7.4
*/
private function hooks() {
// Process the tasks as needed.
add_action( self::LITE_CONNECT_TASK, [ $this, 'process' ] );
}
/**
* Creates a task to submit the lite entry to the Lite Connect API via
* Action Scheduler.
*
* @since 1.7.4
*
* @param int $form_id The form ID.
* @param string $entry_data The entry data.
*/
public function create( $form_id, $entry_data ) {
$action_id = wpforms()->obj( 'tasks' )
->create( self::LITE_CONNECT_TASK )
->params( $form_id, $entry_data )
->once( time() + wp_rand( 10, 60 ) * MINUTE_IN_SECONDS )
->register();
if ( $action_id === null ) {
wpforms_log(
'Lite Connect: error creating the AS task',
[
'task' => self::LITE_CONNECT_TASK,
],
[ 'type' => [ 'error' ] ]
);
}
}
/**
* Process the task to submit the entry to the Lite Connect API via
* Action Scheduler.
*
* @since 1.7.4
*
* @param int $meta_id The meta ID.
*/
public function process( $meta_id ) {
// Load task data.
$params = ( new Meta() )->get( (int) $meta_id );
[ $form_id, $entry_data ] = $params->data;
// Grab the current access token. If a site key or access token is not available, then it recreates the task to run later.
$access_token = $this->get_access_token( $this->get_site_key() );
if ( ! $access_token ) {
$this->create( $form_id, $entry_data );
return;
}
// Submit an entry to the Lite Connect API.
$response = ( new API() )->add_form_entry( $access_token, $form_id, $entry_data );
if ( $response ) {
$response = json_decode( $response, true );
}
$response = (array) $response;
if ( isset( $response['error'] ) && $response['error'] === 'Access token is invalid or expired.' ) {
// Force to re-generate an access token in case it is invalid.
$this->get_access_token( $this->get_site_key(), true );
}
if ( ! empty( $response['error'] ) ) {
wpforms_log(
'Lite Connect: error submitting form entry (AS task)',
[
'response' => $response,
'entry_data' => $entry_data,
],
[
'type' => [ 'error' ],
'form_id' => $form_id,
]
);
}
$entry_key = hash( 'md5', $entry_data );
$lite_connect_send_errors = Transient::get( self::SEND_ERROR_KEY );
$lite_connect_send_errors = is_array( $lite_connect_send_errors ) ? $lite_connect_send_errors : [];
$status = $response['status'] ?? 'error';
// Recreate the task if the request to the API fails for any reasons.
if ( $status !== 'success' ) {
$lite_connect_send_errors[ $entry_key ][] = time();
// Keep only 5 last failed times to avoid a too long array.
$lite_connect_send_errors[ $entry_key ] = array_slice( $lite_connect_send_errors[ $entry_key ], -5 );
Transient::set( self::SEND_ERROR_KEY, $lite_connect_send_errors );
$this->create( $form_id, $entry_data );
return;
}
unset( $lite_connect_send_errors[ $entry_key ] );
Transient::set( self::SEND_ERROR_KEY, $lite_connect_send_errors );
// Increase the entries count if the entry has been added successfully.
$this->increase_entries_count( $form_id );
}
}

View File

@@ -0,0 +1,187 @@
<?php
namespace WPForms\Lite\Reports;
/**
* Generate form submissions reports.
*
* @since 1.5.4
*/
class EntriesCount {
/**
* Constructor.
*
* @since 1.5.4
*/
public function __construct() {}
/**
* Get entries count grouped by form.
* Main point of entry to fetch form entry count data from DB.
* Cache the result.
*
* @since 1.5.4
*
* @return array
*/
public function get_by_form() {
// Get form IDs.
$forms = wpforms()->obj( 'form' )->get( '', [ 'fields' => 'ids' ] );
// Return early if no forms found.
if ( empty( $forms ) || ! is_array( $forms ) ) {
return [];
}
$results = [];
// Iterate through form IDs.
foreach ( $forms as $form_id ) {
// Get entries count for the form.
$count = absint( get_post_meta( $form_id, 'wpforms_entries_count', true ) );
// Skip if the count is empty.
if ( empty( $count ) ) {
continue;
}
// Add form details to the result.
$results[ $form_id ] = [
'form_id' => $form_id,
'count' => $count,
'title' => get_the_title( $form_id ),
];
}
// Sort forms by entries count (desc).
if ( ! empty( $results ) ) {
uasort(
$results,
function ( $a, $b ) {
return ( $a['count'] > $b['count'] ) ? -1 : 1;
}
);
}
return $results;
}
/**
* Retrieve and calculate form trends data for Lite users.
*
* This function calculates and returns trends data for Lite users based on the total number
* of entries submitted per week compared to the previous week's total entries. Optionally
* updates the database with the calculated data.
*
* @since 1.8.8
*
* @return array
*/
public function get_form_trends() {
// Get form IDs.
$results = $this->get_by_form();
// Collection of form IDs that don't have valid previous week's count data.
$maybe_unset_form_ids = [];
foreach ( $results as $form_id => &$form ) {
// Retrieve the previous week's count data from post meta.
$previous_week_count = get_post_meta( $form_id, 'wpforms_entries_count_previous_week', true );
// Continue to the next form if the count data is not valid.
if ( ! is_array( $previous_week_count ) || count( $previous_week_count ) !== 3 ) {
$maybe_unset_form_ids[] = $form_id;
continue;
}
// Continue to the next form if the previous week's count data is not valid.
if ( count( array_unique( $previous_week_count ) ) === 1 ) {
continue;
}
list( $total_previous_week, $count_previous_week, $prev_count_previous_week ) = $previous_week_count;
// Calculate the form's trends data.
$form['total'] = $total_previous_week + $count_previous_week;
$form['count'] = $form['total'] - $total_previous_week;
$form['count_previous_week'] = $prev_count_previous_week;
// If both the current week's count and the previous week's count are zero, set trends to zero.
if ( $form['count_previous_week'] === 0 && $form['count'] === 0 ) {
$form['trends'] = 0;
continue;
}
// If trends are set to be skipped, set trends to zero, and set the previous week's count to zero.
// Thies's been needed since at this stage we don't know the number of entries submitted in the previous week.
if ( (bool) get_post_meta( $form_id, 'wpforms_entries_count_previous_week_skip_trends', true ) ) {
$form['trends'] = 0;
$form['count_previous_week'] = 0;
continue;
}
$form['trends'] = $this->get_calculated_trends( $form['count'], $form['count_previous_week'] );
}
// Unset forms that don't have valid previous week's count data.
return $this->maybe_unset_form_ids( $results, $maybe_unset_form_ids );
}
/**
* Unsets forms from the results array that lack valid previous week's count data.
*
* This function checks for the presence of valid previous week's count data for each form in the
* provided results array. If all forms in the array lack valid data, the original results array is
* returned without any changes. Otherwise, forms without valid data are unset from the array.
*
* @since 1.8.8
*
* @param array $results The original array of form results.
* @param array $maybe_unset_form_ids The form IDs that may need to be unset.
*
* @return array
*/
private function maybe_unset_form_ids( $results, $maybe_unset_form_ids ) {
if ( empty( $maybe_unset_form_ids ) ) {
return $results;
}
// If all forms don't have valid previous week's count data, return early.
if ( count( $maybe_unset_form_ids ) === count( $results ) ) {
return $results;
}
// Unset forms that don't have valid previous week's count data.
foreach ( $maybe_unset_form_ids as $form_id ) {
unset( $results[ $form_id ] );
}
return $results;
}
/**
* Get the calculated trends based on the count and count from the previous week.
*
* This function calculates and returns the trends based on the current count
* and the count from the previous week.
*
* @since 1.8.8
*
* @param int $count The current count.
* @param int $count_previous_week The count from the previous week.
*
* @return int
*/
private function get_calculated_trends( $count, $count_previous_week ) {
// If count from the previous week is zero, set trends to 100 to avoid division by zero.
return ( $count_previous_week === 0 ) ? 100 : round( ( $count - $count_previous_week ) / $count_previous_week * 100 );
}
}