: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param array $forms All forms.
private function get_ajax_form_submissions( array $forms ): array {
static function ( $form ) {
return ! empty( $form->post_content['settings']['ajax_submit'] );
private function get_sites_total(): int {
return function_exists( 'get_blog_count' ) ? (int) get_blog_count() : 1;
* Total number of entries.
* @param string $period Which period should be counted? Possible values: 7days, 30days.
* Everything else will mean "all" entries.
private function get_entries_total( string $period = 'all' ): int {
if ( ! wpforms()->is_pro() ) {
if ( $period === '7days' || $period === '30days' ) {
$count = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching
WHERE meta_key = 'wpforms_entries_count';"
// Limit results to only forms, excluding form templates.
$form_ids = wp_list_pluck( $this->get_all_forms(), 'ID' );
if ( ! empty( $form_ids ) ) {
$args['form_id'] = $form_ids;
gmdate( 'Y-m-d', strtotime( '-7 days' ) ),
gmdate( 'Y-m-d', strtotime( '-30 days' ) ),
$entry_obj = wpforms()->get( 'entry' );
return $entry_obj ? $entry_obj->get_entries( $args, true ) : 0;
* Forms field occurrences.
* @param array $forms List of forms.
* @return array List of field occurrences in all forms created.
private function get_form_fields_count( array $forms ): array {
// Bail early, in case there are no forms created yet!
static function( $form ) {
return $form->post_content['fields'] ?? [];
$fields_flatten = array_merge( [], ...$fields );
$field_types = array_column( $fields_flatten, 'type' );
return array_count_values( $field_types );
* Determines whether the plugin is active for the entire network.
* This is a copy of the WP core is_plugin_active_for_network() function.
private function is_active_for_network(): bool {
// Bail early, in case we are not in multisite.
if ( ! is_multisite() ) {
// Get all active plugins.
$plugins = get_site_option( 'active_sitewide_plugins' );
// Bail early, in case the plugin is active for the entire network.
if ( isset( $plugins[ plugin_basename( WPFORMS_PLUGIN_FILE ) ] ) ) {
* @param int $forms Total forms count.
* @param int $entries Total entries count.
private function get_entries_avg( int $forms, int $entries ): int {
return $forms ? round( $entries / $forms ) : 0;
* @since 1.8.9 Added post_type parameter.
* @param string|string[] $post_type Allow to sort result by post_type. By default, it's 'wpforms'.
private function get_all_forms( $post_type = 'wpforms' ): array {
$forms = wpforms()->get( 'form' )->get( '', [ 'post_type' => $post_type ] );
if ( ! is_array( $forms ) ) {
static function ( $form ) {
$form->post_content = wpforms_decode( $form->post_content );
* Get the favorite templates.
private function get_favorite_templates(): array {
$templates = (array) get_option( Templates::FAVORITE_TEMPLATES_OPTION, [] );
foreach ( $templates as $user_templates ) {
foreach ( $user_templates as $template => $v ) {
$name = 'fav_templates_' . str_replace( '-', '_', $template );
$settings[ $name ] = empty( $settings[ $name ] ) ? 1 : ++ $settings[ $name ];
* Test if the REST API is accessible.
* The REST API might be inaccessible due to various security measures,
* or it might be completely disabled by a plugin.
private function is_rest_api_enabled(): bool {
// phpcs:disable WPForms.PHP.ValidateHooks.InvalidHookName
/** This filter is documented in wp-includes/class-wp-http-streams.php */
$sslverify = apply_filters( 'https_local_ssl_verify', false );
// phpcs:enable WPForms.PHP.ValidateHooks.InvalidHookName
$url = rest_url( 'wp/v2/types/post' );
$response = wp_remote_get(
'cookies' => is_user_logged_in() ? wp_unslash( $_COOKIE ) : [],
'sslverify' => $sslverify,
'Cache-Control' => 'no-cache',
'X-WP-Nonce' => wp_create_nonce( 'wp_rest' ),
// When testing the REST API, an error was encountered, leave early.
if ( is_wp_error( $response ) ) {
// When testing the REST API, an unexpected result was returned, leave early.
if ( wp_remote_retrieve_response_code( $response ) !== 200 ) {
// The REST API did not behave correctly, leave early.
if ( ! wpforms_is_json( wp_remote_retrieve_body( $response ) ) ) {
// We are all set. Confirm the connection.
* Retrieves additional statistics.
private function get_additional_stats(): array {
// Initialize an empty array to store the statistics.
return $this->get_admin_pointer_stats( $stats );
* Retrieves statistics for admin pointers.
* This function retrieves statistics for admin pointers based on their engagement or dismissal status.
* Note: Pointers can only be engaged (interacted with) or dismissed.
* - If the value is 1 or true, it means the pointer is shown and interacted with (engaged).
* - If the value is 0 or false, it means the pointer is dismissed.
* - If there is no pointer ID in the stats, it means the user hasn't seen the pointer yet.
* @param array $stats An array containing existing statistics.
private function get_admin_pointer_stats( array $stats ): array {
$pointers = get_option( 'wpforms_pointers', [] );
// If there are no pointers, return empty statistics.
if ( empty( $pointers ) ) {
// Pointers can only be interacted with or dismissed.
// If there are engagement pointers, process them.
if ( isset( $pointers['engagement'] ) ) {
foreach ( $pointers['engagement'] as $pointer ) {
$stats[ sanitize_key( $pointer ) ] = true;
// If there are dismiss pointers, process them.
if ( isset( $pointers['dismiss'] ) ) {
foreach ( $pointers['dismiss'] as $pointer ) {
$stats[ sanitize_key( $pointer ) ] = false;