Conversation
supportAfter updating to Divi 5.6, the WordPress Dashboard fatals when Antispam Bee’s Dashboard spam counter is enabled. I’ve traced this in both codebases and believe the fix belongs in Antispam Bee, not Divi. Details below. Environment Antispam Bee 2.11.11 Divi 5.6 (Builder 5, D4DomainBridge ) WordPress 7.0 Settings Antispam Bee → dashboard spam counter option enabled Symptom Loading Dashboard ( wp-admin/index.php ) causes: PHP Fatal error: Uncaught TypeError: ET\Builder\I18n\D4DomainBridge::filter_ngettext(): Argument #4 ($number) must be of type int, string given ... Antispam_Bee::add_dashboard_count() (antispam_bee.php ~758) Workaround: disable the dashboard spam counter (or deactivate the plugin). Why this is an Antispam Bee bug In add_dashboard_count() , the third argument to _n() is self::_get_spam_count() : _n( '%s Blocked', '%s Blocked', self::_get_spam_count(), // ← problem 'antispam-bee' ), self::_get_spam_count() // ← correct use (display) But _get_spam_count() returns a locale-formatted string ( number_format() / number_format_i18n() ), not the raw integer: $count = intval( self::get_option( 'spam_count' ) ); return ( get_locale() === 'de_DE' ? number_format( $count, 0, '', '.' ) : number_format_i18n( $count ) ); WordPress expects _n() ’s number argument to be numeric — it is only used to choose singular vs. plural, not for display. The formatted value should be passed only to sprintf() for output, not to _n() . So Antispam Bee is passing the wrong type regardless of which theme is active. Why Divi appears in the stack trace but is not the cause Divi 5.6 registers D4DomainBridge::filter_ngettext() on the global ngettext filter. That callback is typed with int $number , which matches WordPress’s documented expectation for plural selection. Importantly, Divi does not process Antispam Bee’s text domain. The filter only bridges et_builder strings and returns immediately for anything else: public static function filter_ngettext( ..., int $number, string $domain ): string { if ( self::D4_DOMAIN !== $domain ) { // 'et_builder' only return $translation; } // ... } Antispam Bee uses 'antispam-bee' , so Divi would never alter those strings. Divi still shows up in the trace because every ngettext filter runs on every _n() call site-wide. On PHP 8+, argument types are validated before the callback body runs. When Antispam Bee passes a string (e.g. "1,234" ) where an int is required, PHP throws a TypeError while invoking Divi’s callback — even though Divi would have no-op’d for that domain. So Divi is the trigger that exposes the mistake (strict typing on a global hook), not the source of the wrong value. Without Divi active, the same incorrect _n() usage may have gone unnoticed on older PHP / looser coercion; the bug in Antispam Bee is still there. Suggested fix Use the raw integer for _n() and keep _get_spam_count() for display: $spam_count = intval( self::get_option( 'spam_count' ) ); $items[] = '<span class="ab-count">' . esc_html( sprintf( _n( '%s Blocked', '%s Blocked', $spam_count, 'antispam-bee' ), self::_get_spam_count() ) ) . '</span>';
I’ve created this pull request to fix the issue: https://github.com/pluginkollektiv/antispam-bee/pull/692
Thanks for the bug report and patch. This was fixed in version 2.11.12 released just now.
Thank you!
I’ve created this pull request to fix the issue: https://github.com/pluginkollektiv/antispam-bee/pull/692
Thanks for the bug report and patch. This was fixed in version 2.11.12 released just now.
Thank you!