: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
namespace WPForms\Integrations\UsageTracking;
use WPForms\Admin\Builder\Templates;
use WPForms\Integrations\IntegrationInterface;
use WPForms\Integrations\LiteConnect\Integration;
* Usage Tracker functionality to understand what's going on on client's sites.
class UsageTracking implements IntegrationInterface {
* The slug that will be used to save the option of Usage Tracker.
const SETTINGS_SLUG = 'usage-tracking-enabled';
* Indicate if current integration is allowed to load.
public function allow_load(): bool {
* Whether the Usage Tracking code is allowed to be loaded.
* @param bool $var Boolean value.
return (bool) apply_filters( 'wpforms_usagetracking_is_allowed', true ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
* Whether Usage Tracking is enabled.
public function is_enabled(): bool {
* Whether the Usage Tracking is enabled.
* @param bool $var Boolean value taken from the DB.
return (bool) apply_filters( 'wpforms_integrations_usagetracking_is_enabled', wpforms_setting( self::SETTINGS_SLUG ) ); // phpcs:ignore WPForms.PHP.ValidateHooks.InvalidHookName
add_filter( 'wpforms_settings_defaults', [ $this, 'settings_misc_option' ], 4 );
// Deregister the action if option is disabled.
'wpforms_settings_updated',
if ( ! $this->is_enabled() ) {
( new SendUsageTask() )->cancel();
// Register the action handler only if enabled.
if ( $this->is_enabled() ) {
'wpforms_tasks_get_tasks',
static function ( $tasks ) {
$tasks[] = SendUsageTask::class;
* Add "Allow Usage Tracking" to WPForms settings.
* @param array $settings WPForms settings.
public function settings_misc_option( $settings ) {
$settings['misc'][ self::SETTINGS_SLUG ] = [
'id' => self::SETTINGS_SLUG,
'name' => esc_html__( 'Allow Usage Tracking', 'wpforms-lite' ),
'desc' => esc_html__( 'By allowing us to track usage data, we can better help you, as we will know which WordPress configurations, themes, and plugins we should test.', 'wpforms-lite' ),
* Get the User Agent string that will be sent to the API.
public function get_user_agent(): string {
return 'WPForms/' . WPFORMS_VERSION . '; ' . get_bloginfo( 'url' );
* Get data for sending to the server.
* @noinspection PhpUndefinedConstantInspection
* @noinspection PhpUndefinedFunctionInspection
public function get_data(): array {
$theme_data = wp_get_theme();
$activated_dates = get_option( 'wpforms_activated', [] );
$first_form_date = get_option( 'wpforms_forms_first_created' );
$forms = $this->get_all_forms();
$forms_total = count( $forms );
$form_templates_total = count( $this->get_all_forms( 'wpforms-template' ) );
$entries_total = $this->get_entries_total();
$form_fields_count = $this->get_form_fields_count( $forms );
// Generic data (environment).
'php_version' => PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION,
'wp_version' => get_bloginfo( 'version' ),
'mysql_version' => $wpdb->db_version(),
'server_version' => isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '',
'is_multisite' => is_multisite(),
'is_network_activated' => $this->is_active_for_network(),
'is_wpcom' => defined( 'IS_WPCOM' ) && IS_WPCOM,
'is_wpcom_vip' => ( defined( 'WPCOM_IS_VIP_ENV' ) && WPCOM_IS_VIP_ENV ) || ( function_exists( 'wpcom_is_vip' ) && wpcom_is_vip() ),
'is_wp_cache' => defined( 'WP_CACHE' ) && WP_CACHE,
'is_wp_rest_api_enabled' => $this->is_rest_api_enabled(),
'is_user_logged_in' => is_user_logged_in(),
'sites_count' => $this->get_sites_total(),
'active_plugins' => $this->get_active_plugins(),
'theme_name' => $theme_data->get( 'Name' ),
'theme_version' => $theme_data->get( 'Version' ),
'locale' => get_locale(),
'timezone_offset' => wp_timezone_string(),
// WPForms-specific data.
'wpforms_version' => WPFORMS_VERSION,
'wpforms_license_key' => wpforms_get_license_key(),
'wpforms_license_type' => $this->get_license_type(),
'wpforms_license_status' => $this->get_license_status(),
'wpforms_is_pro' => wpforms()->is_pro(),
'wpforms_entries_avg' => $this->get_entries_avg( $forms_total, $entries_total ),
'wpforms_entries_total' => $entries_total,
'wpforms_entries_last_7days' => $this->get_entries_total( '7days' ),
'wpforms_entries_last_30days' => $this->get_entries_total( '30days' ),
'wpforms_forms_total' => $forms_total,
'wpforms_form_fields_count' => $form_fields_count,
'wpforms_form_templates_total' => $form_templates_total,
'wpforms_challenge_stats' => get_option( 'wpforms_challenge', [] ),
'wpforms_lite_installed_date' => $this->get_installed( $activated_dates, 'lite' ),
'wpforms_pro_installed_date' => $this->get_installed( $activated_dates, 'pro' ),
'wpforms_builder_opened_date' => (int) get_option( 'wpforms_builder_opened_date', 0 ),
'wpforms_settings' => $this->get_settings(),
'wpforms_integration_active' => $this->get_forms_integrations( $forms ),
'wpforms_payments_active' => $this->get_payments_active( $forms ),
'wpforms_multiple_confirmations' => count( $this->get_forms_with_multiple_confirmations( $forms ) ),
'wpforms_multiple_notifications' => count( $this->get_forms_with_multiple_notifications( $forms ) ),
'wpforms_ajax_form_submissions' => count( $this->get_ajax_form_submissions( $forms ) ),
'wpforms_notification_count' => wpforms()->get( 'notifications' )->get_count(),
'wpforms_stats' => $this->get_additional_stats(),
if ( ! empty( $first_form_date ) ) {
$data['wpforms_forms_first_created'] = $first_form_date;
if ( $data['is_multisite'] ) {
$data['url_primary'] = network_site_url();
* @since 1.7.2 Clarified the license type.
* @since 1.7.9 Return only the license type, not the status.
private function get_license_type(): string {
return wpforms()->is_pro() ? wpforms_get_license_type() : 'lite';
* Get the license status.
private function get_license_status(): string { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
if ( ! wpforms()->is_pro() ) {
$license_type = wpforms_get_license_type();
$license_key = wpforms_get_license_key();
return empty( $license_key ) ? 'no license' : 'not verified';
if ( wpforms_setting( 'is_expired', false, 'wpforms_license' ) ) {
if ( wpforms_setting( 'is_disabled', false, 'wpforms_license' ) ) {
if ( wpforms_setting( 'is_invalid', false, 'wpforms_license' ) ) {
// The correct type is returned in get_license_type(), so we "collapse" them here to a single value.
if ( in_array( $license_type, [ 'basic', 'plus', 'pro', 'elite', 'ultimate', 'agency' ], true ) ) {
$license_type = 'correct';
* Get all settings, except those with sensitive data.
private function get_settings(): array {
// Remove keys with exact names that we don't need.
$settings = array_diff_key(
get_option( 'wpforms_settings', [] ),
'stripe-test-secret-key',
'stripe-test-publishable-key',
'stripe-live-secret-key',
'stripe-live-publishable-key',
'stripe-webhooks-secret-test',
'stripe-webhooks-secret-live',
'stripe-webhooks-id-test',
'stripe-webhooks-id-live',
'authorize_net-test-api-login-id',
'authorize_net-test-transaction-key',
'authorize_net-live-api-login-id',
'authorize_net-live-transaction-key',
'square-location-id-sandbox',
'square-location-id-production',
'geolocation-google-places-api-key',
'geolocation-algolia-places-application-id',
'geolocation-algolia-places-search-only-api-key',
'geolocation-mapbox-search-access-token',
// Remove keys with a vague names that we don't need.
foreach ( $settings as $key => $value ) {
if ( strpos( $key, 'validation-' ) !== false ) {
$lite_connect_data = get_option( Integration::get_option_name() );
// If lite connect has been restored, set lite connect data.
isset( $lite_connect_data['import']['status'] ) &&
$lite_connect_data['import']['status'] === 'done'
$data['lite_connect'] = [
'restore_date' => $lite_connect_data['import']['ended_at'],
'restored_entry_count' => Integration::get_entries_count(),
// Add favorite templates to the settings array.
return array_merge( $data, $this->get_favorite_templates() );
* Get the list of active plugins.
private function get_active_plugins(): array {
if ( ! function_exists( 'get_plugins' ) ) {
include ABSPATH . '/wp-admin/includes/plugin.php';
$active = is_multisite() ?
array_merge( get_option( 'active_plugins', [] ), array_flip( get_site_option( 'active_sitewide_plugins', [] ) ) ) :
get_option( 'active_plugins', [] );
$plugins = array_intersect_key( get_plugins(), array_flip( $active ) );
static function ( $plugin ) {
if ( isset( $plugin['Version'] ) ) {
return $plugin['Version'];
* @param array $activated_dates Input array with dates.
* @param string $key Input key what you want to get.
private function get_installed( array $activated_dates, string $key ) {
if ( ! empty( $activated_dates[ $key ] ) ) {
return $activated_dates[ $key ];
* Number of forms with some integrations active.
* @param array $forms List of forms.
* @return array List of forms with active integrations count.
private function get_forms_integrations( array $forms ): array {
$integrations = array_map(
static function ( $form ) {
if ( ! empty( $form->post_content['providers'] ) ) {
return array_keys( $form->post_content['providers'] );
$integrations = array_filter( $integrations );
if ( count( $integrations ) > 0 ) {
$integrations = call_user_func_array( 'array_merge', array_values( $integrations ) );
return array_count_values( $integrations );
* Number of forms with active payments.
* @param array $forms Input forms list.
* @return array List of forms with active payments count.
private function get_payments_active( array $forms ): array {
static function ( $form ) {
if ( empty( $form->post_content['payments'] ) ) {
foreach ( $form->post_content['payments'] as $key => $value ) {
if ( ! empty( $value['enable'] ) ) {
return empty( $enabled ) ? false : $enabled;
$payments = array_filter( $payments );
if ( count( $payments ) > 0 ) {
$payments = call_user_func_array( 'array_merge', array_values( $payments ) );
return array_count_values( $payments );
* Forms with multiple notifications.
* @param array $forms List of forms to check.
* @return array List of forms with multiple notifications.
private function get_forms_with_multiple_notifications( array $forms ): array {
static function ( $form ) {
return ! empty( $form->post_content['settings']['notifications'] ) && count( $form->post_content['settings']['notifications'] ) > 1;
* Forms with multiple confirmations.
* @param array $forms List of forms to check.
* @return array List of forms with multiple confirmations.
private function get_forms_with_multiple_confirmations( array $forms ): array {
static function ( $form ) {
return ! empty( $form->post_content['settings']['confirmations'] ) && count( $form->post_content['settings']['confirmations'] ) > 1;
* Forms with ajax submission option enabled.