initialized || ! is_admin() ) { return; } $this->hooks(); $this->initialized = true; } /** * Register WordPress hooks. * * @since 1.0.0 */ private function hooks(): void { add_filter( 'frm_setup_new_form_vars', [ $this, 'ensure_option_on_form_vars' ] ); add_filter( 'frm_setup_edit_form_vars', [ $this, 'ensure_option_on_form_vars' ] ); add_action( 'frm_additional_form_options', [ $this, 'render_settings_row' ] ); add_filter( 'frm_form_options_before_update', [ $this, 'persist_option' ], 10, 3 ); } /** * Ensure option value is present while editing or creating a form. * * @since 1.0.0 * * @param array $values Form values passed to the builder. * * @return array */ public function ensure_option_on_form_vars( array $values ): array { $values = $this->ensure_option_value_present( $values, self::OPTION_KEY ); return $values; } /** * Ensure a specific option key is populated in the builder payload. * * @since 1.0.0 * * @param array $values Form builder values. * @param string $key Option key to populate. * * @return array */ private function ensure_option_value_present( array $values, string $key ): array { $values[ $key ] = $this->resolve_option_value( $values, $key ); if ( ! isset( $values['options'] ) || ! is_array( $values['options'] ) ) { $values['options'] = []; } $values['options'][ $key ] = $values[ $key ]; return $values; } /** * Normalize the boolean option value for builder payloads. * * @since 1.0.0 * @since 1.3.0 Default flipped to opt-out — protection enabled when no explicit toggle stored. * * @param array $values Form builder values. * @param string $key Option key to inspect. * * @return int */ private function resolve_option_value( array $values, string $key ): int { if ( isset( $values[ $key ] ) ) { return (int) (bool) $values[ $key ]; } $form_id = isset( $values['id'] ) ? (int) $values['id'] : 0; if ( $form_id <= 0 ) { // New / unsaved form (no ID yet) — use opt-out default so the builder // checkbox renders ON and the first save persists `enabled = 1`. return 1; } $option_exists = false; $stored_value = $this->get_option_value( $form_id, $key, $option_exists ); if ( $stored_value === null ) { return 1; } return (int) (bool) $stored_value; } /** * Render checkbox in the Formidable form settings screen. * * @since 1.0.0 * * @param array $values Form builder values. */ public function render_settings_row( array $values ): void { $enabled = ! empty( $values[ self::OPTION_KEY ] ); ?>

get_option_value( $form_id, self::OPTION_KEY, $enabled_exists ); if ( ! $enabled_exists ) { return [ 'enabled' => true, ]; } return [ 'enabled' => (bool) $enabled_value, ]; } /** * Get all forms with their protection status. * * @since 1.1.0 * * @return array[] Array of arrays with 'id', 'name', and 'enabled' keys. */ public function get_forms_list(): array { if ( ! class_exists( FrmForm::class ) || ! method_exists( FrmForm::class, 'getAll' ) ) { return []; } $forms = FrmForm::getAll( [ 'is_template' => 0, 'status' => 'published', ] ); if ( empty( $forms ) || ! is_array( $forms ) ) { return []; } $result = []; foreach ( $forms as $form ) { $form_id = isset( $form->id ) ? (int) $form->id : 0; $settings = $this->get_form_settings( $form_id ); $result[] = [ 'id' => $form_id, 'name' => isset( $form->name ) ? $form->name : __( 'Untitled', 'activelayer-anti-spam-spam-protection-for-forms-comments' ), 'enabled' => ! empty( $settings['enabled'] ), ]; } return $result; } /** * Save protection status for a specific form. * * @since 1.1.0 * @since 1.2.0 Replaced maybe_unserialize with allowed_classes=>false to block PHP object injection via Formidable form options. * * @param int $form_id Form ID. * @param bool $enabled Whether protection is enabled. * * @return bool Whether the save was successful. */ public function save_form_protection( int $form_id, bool $enabled ): bool { if ( ! class_exists( FrmForm::class ) ) { return false; } $form = FrmForm::getOne( $form_id ); if ( ! $form ) { return false; } $options = SafeUnserializer::unserialize( $form->options ); if ( ! is_array( $options ) ) { $options = []; } $options[ self::OPTION_KEY ] = $enabled ? '1' : '0'; FrmForm::update( $form_id, [ 'options' => $options ] ); return true; } /** * Fetch stored toggle value from the form record. * * @since 1.0.0 * * @param int $form_id Form identifier. * @param string $key Option key. * @param bool|null $exists Pass-by-reference flag tracking if the option exists. * * @return int|null */ private function get_option_value( int $form_id, string $key, ?bool &$exists = null ): ?int { if ( $form_id <= 0 || ! class_exists( FrmForm::class ) ) { $exists = false; return null; } $form = FrmForm::getOne( $form_id ); if ( ! $form || empty( $form->options ) || ! is_array( $form->options ) || ! array_key_exists( $key, $form->options ) ) { $exists = false; return null; } $exists = true; return (int) ( ! empty( $form->options[ $key ] ) ); } /** * Get the URL-friendly slug for Formidable Forms. * * @since 1.1.0 * * @return string URL slug. */ public function get_url_slug(): string { return 'formidable-forms'; } /** * Get the admin page URL for Formidable Forms. * * @since 1.1.0 * * @return string Admin URL path. */ public function get_admin_page_url(): string { return 'admin.php?page=formidable'; } /** * Get the form edit URL template for Formidable Forms. * * @since 1.1.0 * * @return string URL template with %d placeholder. */ public function get_form_edit_url_template(): string { return 'admin.php?page=formidable&frm_action=settings&id=%d'; } }