Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
9215d9e
fix: block form submission when custom button is conditionally hidden
avi1080p Jun 11, 2026
940a575
fix: render InspectorTab children when only a single tab is present
avi1080p Jun 11, 2026
daa952b
feat: add Show Entries feature-preview upsell tab
vanshk141999 Jun 12, 2026
48385d0
fix: prevent silent form submission failure with multiple Turnstile w…
adi3890 Jun 17, 2026
5a3e1d9
Merge pull request #2870 from brainstormforce/fix/turnstile-multi-wid…
vanshk141999 Jun 18, 2026
49677c1
fix(payments): fail-safe reject unresolved hidden-field amount with n…
vanshk141999 Jun 18, 2026
35b1397
fix(editor): fall back to non-iframe path on WP 6.x with legacy blocks
avi1080p Jun 18, 2026
de56ee5
fix(payments): scope one-time Stripe Payment Element to card to fix l…
vanshk141999 Jun 18, 2026
2265de4
Merge pull request #2887 from brainstormforce/master-dev-2.11.1-post
vanshk141999 Jun 19, 2026
acb0d77
Merge branch 'dev' of https://github.com/brainstormforce/sureforms in…
vanshk141999 Jun 19, 2026
6de34e9
Merge pull request #2888 from brainstormforce/dev-nr-2.11.1-post
vanshk141999 Jun 19, 2026
40bb43c
Merge branch 'dev' of https://github.com/brainstormforce/sureforms in…
vanshk141999 Jun 19, 2026
f9278be
Merge pull request #2878 from brainstormforce/fix/iframe-compat-wp6
vanshk141999 Jun 19, 2026
fbac0a9
Resolve SureForms-own Plugin Check findings
vanshk141999 Jun 22, 2026
0bd1822
Add payment lifecycle hooks for access/membership integrations
kudaleganesh Jun 22, 2026
b4e9b0f
Use @since x.x.x placeholder for new hooks and helpers
kudaleganesh Jun 22, 2026
9d4b6f9
Fixed PHPCS errors
kudaleganesh Jun 22, 2026
b876820
test(stripe): cover is_transaction_present() payments-table presence …
vanshk141999 Jun 22, 2026
d3e59f8
Merge pull request #2889 from brainstormforce/fix/plugin-check-findin…
vanshk141999 Jun 22, 2026
dcc59a6
test: cover resolve_payment_user() and build_payment_context()
vanshk141999 Jun 22, 2026
2657dd7
fix(payments): route admin subscription cancel through gateway-agnost…
vanshk141999 Jun 22, 2026
e808b2b
chore: update bsf-analytics to 1.1.28 (RTL deactivation survey fix)
vanshk141999 Jun 23, 2026
0e55fea
Merge pull request #2896 from brainstormforce/chore/update-bsf-analyt…
vanshk141999 Jun 23, 2026
8ba0b26
Merge pull request #2890 from brainstormforce/feat/suremembers-paymen…
vanshk141999 Jun 23, 2026
79cfbfd
fix: resolve Plugin Check findings in SureForms code (phpcs suppressi…
vanshk141999 Jun 23, 2026
6e1affb
fix: resolve plugin-loader direct-access check; document abilities WP…
vanshk141999 Jun 23, 2026
aba09f2
Merge pull request #2897 from brainstormforce/chore/plugin-check-fixes
vanshk141999 Jun 23, 2026
87af820
fix(payments): address review — drop double DB write + empty-gateway …
vanshk141999 Jun 23, 2026
03b7f79
Merge pull request #2884 from brainstormforce/fix/stripe-live-card-fi…
vanshk141999 Jun 23, 2026
2e2e824
Merge pull request #2877 from brainstormforce/fix/payment-unresolved-…
vanshk141999 Jun 23, 2026
de4c2de
Merge branch 'next-release' of https://github.com/brainstormforce/sur…
vanshk141999 Jun 23, 2026
621ac2a
Merge branch 'dev' of https://github.com/brainstormforce/sureforms in…
vanshk141999 Jun 23, 2026
7215e23
Merge pull request #2892 from brainstormforce/fix/admin-paypal-subscr…
vanshk141999 Jun 23, 2026
5cc9215
Merge pull request #2849 from brainstormforce/fix/2848-conditional-lo…
vanshk141999 Jun 24, 2026
bc97818
Merge pull request #2854 from brainstormforce/feat/show-entries-previ…
vanshk141999 Jun 24, 2026
25f51c9
Merge branch 'dev' of https://github.com/brainstormforce/sureforms in…
vanshk141999 Jun 24, 2026
3c4efb0
chore: re-trigger CI (skip-test-check label applied)
vanshk141999 Jun 24, 2026
54dd4f9
test: cover 4 functions flagged by test-coverage gate
vanshk141999 Jun 24, 2026
1cf7613
Merge pull request #2899 from brainstormforce/dev-nr-2.12.0
vanshk141999 Jun 24, 2026
875e1d9
refactor: extract PageBreakSettings into shared component
avi1080p Jun 24, 2026
d7ed6a8
Version Bump 2.12.0
vanshk141999 Jun 24, 2026
c5cda69
style: remove stray double blank lines after PageBreakSettings extrac…
vanshk141999 Jun 24, 2026
1d51922
updated readme
vanshk141999 Jun 24, 2026
aba1847
Merge pull request #2901 from brainstormforce/fix/page-break-settings…
vanshk141999 Jun 24, 2026
dc6252f
Merge pull request #2902 from brainstormforce/version-bump-2.12.0
vanshk141999 Jun 24, 2026
146d192
chore: update i18n translations
github-actions[bot] Jun 24, 2026
efb5005
Merge pull request #2905 from brainstormforce/i18n/next-release
vanshk141999 Jun 24, 2026
82c8a9a
Merge pull request #2903 from brainstormforce/next-release
vanshk141999 Jun 24, 2026
286d6ae
chore: strip internal-only paths from public mirror sync
vanshk141999 Jun 25, 2026
f181644
Sync master from upstream
vanshk141999 Jun 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
**Requires at least:** 6.4
**Tested up to:** 7.0
**Requires PHP:** 7.4
**Stable tag:** 2.11.1
**Stable tag:** 2.12.0
**License:** GPLv2 or later
**License URI:** http://www.gnu.org/licenses/gpl-2.0.html

AI WordPress form builder. Create contact forms, payment forms, surveys, quizzes & multi-step forms — drag & drop, no code.
SureForms is an AI-powered WordPress form builder for creating contact forms, payment forms, surveys, quizzes, and multi-step forms without code.

## Description ##

Expand Down Expand Up @@ -458,17 +458,19 @@ Yes. SureForms Business includes fully functional user registration forms and lo
You can report security issues through our [Bug Bounty Program](https://brainstormforce.com/bug-bounty-program/). We collaborate with Patchstack to provide opportunities for researchers to report vulnerabilities. The Patchstack team will help validate, triage, and handle any reported security issues.

## Changelog ##
### 2.12.0 - 24th June 2026 ###
* New: Added action hooks around payment success, cancellation, and refund events so plugins such as SureMembers, LMS, and CRMs can grant or revoke access for both Stripe and PayPal.
* Fix: Cancel Subscription now routes through the correct payment gateway so PayPal subscriptions cancel properly instead of always calling Stripe.
* Fix: Forms with multiple Cloudflare Turnstile widgets now submit correctly instead of silently failing with a generic error.
* Fix: Resolved an issue where the Stripe Payment Element failed to render on live accounts that have Bacs Direct Debit, Link, Cash App, or BNPL enabled.
* Fix: Restored the form editor on WordPress 6.x sites running plugins that register older-style blocks such as ThirstyAffiliates, Ninja Forms, and Gravity Forms.
### 2.11.1 - 16th June 2026 ###
* Fix: Phone field auto country detection always resolved to the United States.
* Fix: Corrected the Cloudflare Turnstile "Get Keys" link.
* Fix: This update addressed a security bug. Props to Yaswanth Reddy Sunkara for reporting it responsibly to our team.
### 2.11.0 - 10th June 2026 ###
* New: Added a Form Migrator to import forms from Contact Form 7, WPForms, Gravity Forms, and Ninja Forms in a single click.
* New: Added native WPML support to translate each form individually using String Packages.
### 2.10.1 - 1st June 2026 ###
* Improvement: Improved compatibility with older Block API versions so the SureForms editor loads reliably across WordPress environments.
* Fix: Resolved an issue where the Textarea character counter was misaligned.
* Fix: Resolved an issue where the {entry_id} smart tag failed to resolve in email notifications.
The full changelog is available [here](https://sureforms.com/whats-new/?utm_source=wordpress.org&utm_medium=whats_new).

## Upgrade Notice ##
Expand Down
2 changes: 1 addition & 1 deletion admin/admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -1639,7 +1639,7 @@ public function display_srfm_rating_notice() {
'message' => $this->build_notice_markup(
esc_html__( 'Amazing! SureForms is powering your forms and submissions - let\'s keep growing together!', 'sureforms' ),
esc_html__( 'If SureForms has been helpful, would you mind taking a moment to leave a 5-star review on WordPress.org?', 'sureforms' ),
esc_url( 'https://wordpress.org/support/plugin/sureforms/reviews/?filter=5#new-post' ),
esc_url( 'https://wordpress.org/support/plugin/sureforms/reviews/' ),
esc_html__( 'Rate SureForms', 'sureforms' ),
esc_html__( 'Maybe later', 'sureforms' ),
esc_html__( 'I already did', 'sureforms' ),
Expand Down
9 changes: 9 additions & 0 deletions assets/js/stripe-payment.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,15 @@ class StripePayment {
// Add type-specific configuration
if ( paymentType === 'one-time' ) {
elementsConfig.captureMethod = 'manual';
// Manual capture is incompatible with some account-enabled payment methods
// (e.g. Bacs Direct Debit, Link, Cash App, BNPL). When any of those are enabled,
// Stripe rejects the deferred elements/sessions request with HTTP 400 and the
// Payment Element fails to render — which is why the card field does not load in
// live mode while test mode (card-only) works. Scope the element to card so only
// capture-compatible methods are offered. Apple Pay / Google Pay still appear
// (they are surfaced through `card`); the methods dropped here could never be used
// with manual capture anyway, so no working checkout is lost.
elementsConfig.paymentMethodTypes = [ 'card' ];
}

// Create and mount payment element
Expand Down
7 changes: 6 additions & 1 deletion assets/js/unminified/form-submit.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,12 @@ function initializeFormHandlers() {
'button.srfm-custom-button'
);

if ( hasHiddenClass && ! isCustomButton ) {
// Check if the custom button is hidden by conditional logic.
const isCustomButtonHidden = isCustomButton
?.closest( '.srfm-custom-button-ctn' )
?.classList.contains( 'hide-element' );

if ( hasHiddenClass && ( ! isCustomButton || isCustomButtonHidden ) ) {
console.warn(
'Form submission is disabled because the submit button is hidden.'
);
Expand Down
17 changes: 15 additions & 2 deletions assets/js/unminified/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -1226,9 +1226,22 @@ export const handleCaptchaValidation = (
} else if ( !! hCaptchaDiv ) {
captchaResponse = hcaptcha.getResponse();
} else if ( !! turnstileDiv ) {
captchaResponse = turnstile.getResponse();
// `turnstile.getResponse()` without a widget id is unreliable when more
// than one Turnstile widget is rendered on the page — it can return
// `undefined`, which previously threw a TypeError on `.length` below and
// surfaced as a generic "An error occurred while submitting your form".
// Read the token from the hidden response field scoped to THIS form's
// widget, falling back to the global getResponse() for safety.
const turnstileResponseField = turnstileDiv.querySelector(
'[name="cf-turnstile-response"]'
);
captchaResponse =
turnstileResponseField?.value || turnstile.getResponse();
}
const isValid = captchaResponse.length > 0;
// Guard against captcha libraries returning `undefined` (e.g. multiple
// widgets on the page) so a missing token shows the captcha error instead
// of throwing and failing the whole submission silently.
const isValid = ( captchaResponse || '' ).length > 0;
captchaErrorElement.style.display = isValid ? 'none' : 'block';

return isValid;
Expand Down
14 changes: 7 additions & 7 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 9 additions & 0 deletions inc/abilities/abilities-registrar.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class_exists( 'WP\MCP\Plugin' ) &&
* @return void
*/
public function register_mcp_server( $adapter ) {
// wp_get_abilities() is a WP 6.9+ Abilities API function. This method is only hooked
// when mcp_adapter_enabled() is true, which itself requires function_exists( 'wp_register_ability' ),
// so it is inert on WP 6.4-6.8. Plugin Check's static WP-version check reports a false positive here.
$abilities = wp_get_abilities();
$tools = [];

Expand Down Expand Up @@ -122,6 +125,9 @@ public function register_mcp_server( $adapter ) {
* @return void
*/
public function register_category() {
// wp_has_ability_category() / wp_register_ability_category() are WP 6.9+ Abilities API
// functions, each called only behind its own function_exists() guard, so they are inert
// on WP 6.4-6.8. Plugin Check's static WP-version check reports false positives here.
if ( function_exists( 'wp_has_ability_category' ) && wp_has_ability_category( 'sureforms' ) ) {
return;
}
Expand Down Expand Up @@ -198,6 +204,9 @@ public function register_abilities() {
}

// Skip abilities already registered by zipwp-mcp.
// wp_has_ability() is a WP 6.9+ Abilities API function, called only behind its
// function_exists() guard, so it is inert on WP 6.4-6.8. Plugin Check's static
// WP-version check reports a false positive here.
if ( function_exists( 'wp_has_ability' ) && wp_has_ability( $ability->get_id() ) ) {
continue;
}
Expand Down
4 changes: 4 additions & 0 deletions inc/abilities/abstract-ability.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,10 @@ public function register() {

$annotations = $this->get_annotations();

// wp_register_ability() is a WP 6.9+ Abilities API function. It is only reached
// after the function_exists() guard above (and via the wp_abilities_api_init hook),
// so it is inert on WP 6.4-6.8. Plugin Check's static WP-version check cannot see the
// runtime guard, so it reports a false positive here.
wp_register_ability(
$this->id,
[
Expand Down
2 changes: 1 addition & 1 deletion inc/abilities/forms/list-forms.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ private function get_entry_counts( array $form_ids ) {
$table_name = $wpdb->prefix . 'srfm_entries';
$placeholders = implode( ',', array_fill( 0, count( $form_ids ), '%d' ) );

// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Batch query to avoid N+1; results are not cached as they reflect real-time entry counts.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Batch query to avoid N+1; table name from $wpdb->prefix and placeholders from array_fill() (not user input); results not cached as they reflect real-time entry counts.
$results = $wpdb->get_results(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Table name and placeholders are constructed from $wpdb->prefix and array_fill(), not user input.
Expand Down
6 changes: 3 additions & 3 deletions inc/admin-ajax.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ public function generate_data_for_suretriggers_integration() {

// Translators: %s: Form ID.
$form_name = ! empty( $form->post_title ) ? $form->post_title : sprintf( __( 'SureForms id: %s', 'sureforms' ), $form_id );
$api_url = apply_filters( 'suretriggers_get_iframe_url', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL );
$api_url = apply_filters( 'suretriggers_get_iframe_url', SRFM_SURETRIGGERS_INTEGRATION_BASE_URL ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- SureTriggers' own filter; the name must match SureTriggers exactly to integrate.

// This is the format of data required by SureTriggers for adding iframe in target id.
$body = [
Expand Down Expand Up @@ -451,10 +451,10 @@ public function download_export_file() {
}

// Output the file.
readfile( $filepath ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile -- Need direct file output for download.
readfile( $filepath ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_readfile, WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Direct file output is required to stream the download.

// Clean up the temporary file.
unlink( $filepath );
wp_delete_file( $filepath );

exit;
}
Expand Down
2 changes: 2 additions & 0 deletions inc/compatibility/multilingual/providers/wpml-provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
exit; // Exit if accessed directly.
}

// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- This adapter exists solely to call WPML's own hooks (wpml_*); their names must match WPML exactly to integrate.

/**
* WPML_Provider.
*
Expand Down
2 changes: 1 addition & 1 deletion inc/database/tables/entries.php
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ public static function has_duplicate_field_value( $form_id, $field_key, $field_v
$table_name = self::get_instance()->get_tablename();
$json_path = '$."' . $field_key . '"';

// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- One-off existence check; caching not beneficial for uniqueness validation.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- One-off existence check; table name from get_tablename() (not user input); caching not beneficial for uniqueness validation.
$exists = $wpdb->get_var(
$wpdb->prepare(
"SELECT 1 FROM {$table_name} WHERE form_id = %d AND status != 'trash' AND JSON_UNQUOTE(JSON_EXTRACT(form_data, %s)) = %s LIMIT 1", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is internally generated.
Expand Down
4 changes: 2 additions & 2 deletions inc/database/tables/payments.php
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ public static function get_all_main_payments( $args = [], $set_limit = true ) {
$query = $wpdb->prepare( $query, $params );
}

// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Custom table query with dynamic preparation, caching not applicable for dynamic queries.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom table query with dynamic preparation; table name internal, not user input; caching not applicable for dynamic queries.
$results = $wpdb->get_results( $query, ARRAY_A );

return is_array( $results ) ? $results : [];
Expand Down Expand Up @@ -1183,7 +1183,7 @@ public static function get_total_main_payments_by_status( $status = 'all', $form
$query = $wpdb->prepare( $query, $params );
}

// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Custom table query with dynamic preparation, caching not applicable for count operations.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Custom table query with dynamic preparation; table name internal, not user input; caching not applicable for count operations.
$result = $wpdb->get_var( $query );

return absint( $result );
Expand Down
4 changes: 2 additions & 2 deletions inc/entries.php
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ public static function export_entries( $args = [] ) {
$csv_filepath = $temp_dir . $csv_filename;

if ( file_exists( $csv_filepath ) ) {
unlink( $csv_filepath );
wp_delete_file( $csv_filepath );
}

$stream = fopen( $csv_filepath, 'wb' ); // phpcs:ignore -- Using fopen to decrease the memory use.
Expand Down Expand Up @@ -399,7 +399,7 @@ public static function export_entries( $args = [] ) {
// Clean up CSV files.
foreach ( $csv_files as $csv_file ) {
if ( file_exists( $csv_file ) ) {
unlink( $csv_file );
wp_delete_file( $csv_file );
}
}

Expand Down
6 changes: 4 additions & 2 deletions inc/fields/inlinebutton-markup.php
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ public function markup() {
if ( 'cf-turnstile' === $this->captcha_security_type ) {
if ( ! empty( $this->cf_turnstile_site_key ) ) {
// Cloudflare Turnstile script.
wp_enqueue_script( // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
// phpcs:disable WordPress.WP.EnqueuedResourceParameters.MissingVersion, PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent -- Cloudflare Turnstile must be loaded from Cloudflare's servers for token verification; the version is controlled by Cloudflare.
wp_enqueue_script(
SRFM_SLUG . '-cf-turnstile',
'https://challenges.cloudflare.com/turnstile/v0/api.js',
[],
Expand All @@ -218,13 +219,14 @@ public function markup() {
'defer' => true,
]
);
// phpcs:enable WordPress.WP.EnqueuedResourceParameters.MissingVersion, PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent
} else {
Helper::render_missing_sitekey_error( 'Cloudflare Turnstile' );
}
}
if ( 'hcaptcha' === $this->captcha_security_type ) {
if ( ! empty( $this->hcaptcha_site_key ) ) {
wp_enqueue_script( 'hcaptcha', 'https://js.hcaptcha.com/1/api.js', [], null, [ 'strategy' => 'defer' ] ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
wp_enqueue_script( 'hcaptcha', 'https://js.hcaptcha.com/1/api.js', [], null, [ 'strategy' => 'defer' ] ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion, PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent -- hCaptcha must be loaded from hCaptcha's servers for token verification; the version is controlled by hCaptcha.
} else {
Helper::render_missing_sitekey_error( 'HCaptcha' );
}
Expand Down
2 changes: 1 addition & 1 deletion inc/form-submit.php
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ protected function is_known_language( string $language ): bool {
// Use WPML's filter when available — works regardless of which
// multilingual plugin is the active provider, as Polylang implements
// the same filter for compatibility.
$active = apply_filters( 'wpml_active_languages', null, 'skip_missing=0' );
$active = apply_filters( 'wpml_active_languages', null, 'skip_missing=0' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML's own filter; the name must match WPML/Polylang exactly to integrate.
if ( is_array( $active ) && ! empty( $active ) ) {
return array_key_exists( $language, $active );
}
Expand Down
Loading