diff --git a/config/install/webform_spam_words.settings.yml b/config/install/webform_spam_words.settings.yml deleted file mode 100644 index 546686c089ce8ace7e78adeeb129a004ec239c84..0000000000000000000000000000000000000000 --- a/config/install/webform_spam_words.settings.yml +++ /dev/null @@ -1,9 +0,0 @@ -spam_words: - - SEO - - 'Digital Marketing' - - 'Click Here' - - unsubscribe - - FREE - - trial -spam_text_message: 'Unable to submit form. Please contact the site administrator, if the problem persists.' -spam_field_name: message diff --git a/config/schema/webform_spam_words.schema.yml b/config/schema/webform_spam_words.schema.yml new file mode 100644 index 0000000000000000000000000000000000000000..a2bc945626b7d6fa5a6a4064dfad63acf81b7a34 --- /dev/null +++ b/config/schema/webform_spam_words.schema.yml @@ -0,0 +1,17 @@ +webform.handler.webform_spam_words: + type: mapping + label: 'Webform Spam Words' + mapping: + spam_words: + type: mapping + label: 'Spam words by field' + mapping: + message: + type: sequence + label: 'Spam words for message field' + sequence: + type: string + label: 'Spam word' + spam_text_message: + type: string + label: 'Error message for spam detection' diff --git a/src/Form/BlockwordsConfigurationSettings.php b/src/Form/BlockwordsConfigurationSettings.php deleted file mode 100644 index 73e6261f796d600282b0aca2f959d4883593ae6e..0000000000000000000000000000000000000000 --- a/src/Form/BlockwordsConfigurationSettings.php +++ /dev/null @@ -1,156 +0,0 @@ -<?php - -namespace Drupal\webform_spam_words\Form; - -use Drupal\Core\Config\ConfigFactoryInterface; -use Drupal\Core\Config\TypedConfigManagerInterface; -use Drupal\Core\Extension\ModuleHandlerInterface; -use Drupal\Core\Form\ConfigFormBase; -use Drupal\Core\Form\FormStateInterface; -use Symfony\Component\DependencyInjection\ContainerInterface; - -/** - * Returns responses for webform block spam words. - */ -class BlockwordsConfigurationSettings extends ConfigFormBase { - - /** - * Constructs a settings controller. - * - * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory - * The factory for configuration objects. - * @param \Drupal\Core\Config\TypedConfigManagerInterface $typedConfigManager - * The typed config service. - * @param \Drupal\Core\Extension\ModuleHandlerInterface $moduleHandler - * The module handler. - */ - public function __construct( - ConfigFactoryInterface $config_factory, - TypedConfigManagerInterface $typedConfigManager, - protected ModuleHandlerInterface $moduleHandler, - ) { - parent::__construct($config_factory, $typedConfigManager); - } - - /** - * {@inheritdoc} - */ - public static function create(ContainerInterface $container) { - return new static( - $container->get('config.factory'), - $container->get('config.typed'), - $container->get('module_handler') - ); - } - - /** - * {@inheritdoc} - */ - protected function getEditableConfigNames() { - return ['webform_spam_words.settings']; - } - - /** - * {@inheritdoc} - */ - public function getFormId() { - return 'wsw_settings_form'; - } - - /** - * {@inheritdoc} - */ - public function buildForm(array $form, FormStateInterface $form_state) { - - if ($this->moduleHandler->moduleExists('webform')) { - - // Get values from settings. - $spam_words = $this->config('webform_spam_words.settings')->get('spam_words') ? implode(PHP_EOL, $this->config('webform_spam_words.settings')->get('spam_words')) : 'SEO'; - $spam_text_message = $this->config('webform_spam_words.settings')->get('spam_text_message') ? $this->config('webform_spam_words.settings')->get('spam_text_message') : 'Unable to submit form. Please contact the site administrator, if the problem persists.'; - $spam_field_name = $this->config('webform_spam_words.settings')->get('spam_field_name') ? $this->config('webform_spam_words.settings')->get('spam_field_name') : 'message'; - - // Webform Block Spam Words Configuration. - $form['config'] = [ - '#type' => 'fieldset', - '#title' => $this->t('Webform Spam words Configuration'), - '#collapsible' => TRUE, - '#collapsed' => FALSE, - ]; - - $form['config']['spam_words'] = [ - '#type' => 'textarea', - '#required' => TRUE, - '#title' => $this->t('Webform Spam words'), - '#default_value' => $spam_words, - '#description' => $this->t('Each Webform spam words should be on a separate line.'), - ]; - - $form['config']['spam_text_message'] = [ - '#type' => 'textfield', - '#title' => $this->t('Webform Error Message'), - '#default_value' => $spam_text_message, - '#required' => TRUE, - '#description' => $this->t("Please enter your error message, it shows on webform if it's failed. So, the spammers don't know your exact webform error message."), - ]; - - $form['config']['spam_field_name'] = [ - '#type' => 'textfield', - '#required' => TRUE, - '#title' => $this->t('Webform Field name(s)'), - '#default_value' => $spam_field_name, - '#description' => $this->t('Please enter your webform field(s). If you have more than one field, separate them with commas. For Example: message, email, name'), - ]; - - // Store the keys we want to save in configuration when form is submitted. - $keys_to_save = array_keys($form['config']); - foreach ($keys_to_save as $key => $key_to_save) { - if (strpos($key_to_save, '#') !== FALSE) { - unset($keys_to_save[$key]); - } - } - $form_state->setStorage(['keys' => $keys_to_save]); - - $form['actions']['#type'] = 'container'; - $form['actions']['submit'] = [ - '#type' => 'submit', - '#value' => $this->t('Save configuration'), - ]; - } - - return $form; - } - - /** - * {@inheritdoc} - */ - public function validateForm(array &$form, FormStateInterface $form_state) { - - } - - /** - * {@inheritdoc} - */ - public function submitForm(array &$form, FormStateInterface $form_state) { - $config = $this->config('webform_spam_words.settings'); - $storage = $form_state->getStorage(); - - // Save configuration items from FormState values. - foreach ($form_state->getValues() as $key => $value) { - if (in_array($key, $storage['keys'])) { - if ($key == 'spam_words') { - $config->set($key, explode(PHP_EOL, trim($value))); - } - else { - $config->set($key, $value); - } - } - } - - // Save config settings. - $config->save(); - - // Message. - $this->messenger()->addMessage($this->t('The configuration has been saved.')); - } - -} diff --git a/src/Plugin/WebformHandler/BlockWordsWebformHandler.php b/src/Plugin/WebformHandler/BlockWordsWebformHandler.php index 2f62334ac62cc42cd4f93914fc1fd4552b5ff038..fea8bc5319adfd676c4f24378fd1842e58c1891b 100644 --- a/src/Plugin/WebformHandler/BlockWordsWebformHandler.php +++ b/src/Plugin/WebformHandler/BlockWordsWebformHandler.php @@ -5,7 +5,6 @@ namespace Drupal\webform_spam_words\Plugin\WebformHandler; use Drupal\Component\Utility\Html; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; -use Drupal\webform\Annotation\WebformHandler; use Drupal\webform\Plugin\WebformHandlerBase; use Drupal\webform\WebformSubmissionInterface; @@ -26,41 +25,100 @@ class BlockWordsWebformHandler extends WebformHandlerBase { use StringTranslationTrait; + /** + * Allowed Webform fields types that support Spam words. + */ + const ALLOWED_WSW_FIELDS = ['textfield', 'textarea', 'text_format']; + /** * {@inheritdoc} */ - public function defaultConfiguration() { + public function defaultConfiguration(): array { return [ - 'spam_words' => 'SEO', + 'spam_words' => [ + 'message' => [ + 'SEO', + 'Digital Marketing', + 'Click Here', + 'unsubscribe', + 'FREE', + 'trial', + ], + ], 'spam_text_message' => $this->t('Unable to submit form. Please contact the site administrator, if the problem persists.'), - 'spam_field_name' => 'message', ]; } /** * {@inheritdoc} */ - public function validateForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission) { + public function buildConfigurationForm(array $form, FormStateInterface $form_state): array { + $webform = $this->getWebform(); + // Get webform elements. + $elements = $webform->getElementsDecodedAndFlattened(); + // Filter elements to get only the allowed field types. + $text_fields = array_filter($elements, function ($element) { + return in_array($element['#type'], self::ALLOWED_WSW_FIELDS); + }); + + // Iterate over the allowed fields and add spam words configuration. + foreach ($text_fields as $name => $text_field) { + $form['spam_words'][$name] = [ + '#type' => 'textarea', + '#required' => FALSE, + '#title' => $this->t('Spam words for "%name" field', ['%name' => $text_field['#title']]), + '#default_value' => implode(PHP_EOL, $this->configuration['spam_words'][$name] ?? []), + '#description' => $this->t('Each spam words should be on a separate line.'), + ]; + } - $fields = explode(',', trim($this->configuration['spam_field_name'])); - if (is_array($fields)) { - foreach ($fields as $value) { - $field = trim($value); - $this->validateSpam($form_state, $field, $this->configuration['spam_words'], $this->configuration['spam_text_message']); - } + $form['spam_text_message'] = [ + '#type' => 'textfield', + '#title' => $this->t('Error message for spam detection'), + '#default_value' => $this->configuration['spam_text_message'], + '#required' => TRUE, + '#description' => $this->t("Please enter your error message, it shows on webform if it's failed. So, the spammers don't know your exact webform error message."), + ]; + + return $this->setSettingsParents($form); + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void { + parent::submitConfigurationForm($form, $form_state); + foreach ($form_state->getValue('spam_words') as $field => $spam_words) { + $this->configuration['spam_words'][$field] = explode(PHP_EOL, trim($spam_words)); } + $this->configuration['spam_text_message'] = $form_state->getValue('spam_text_message'); + } + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, FormStateInterface $form_state, WebformSubmissionInterface $webform_submission): void { + $spam_words = $this->configuration['spam_words'] ?? []; + foreach ($spam_words as $field => $words) { + $this->validateSpam($form_state, $field, $words ?? [], $this->configuration['spam_text_message'] ?? ""); + } } /** * Validate Webform spam words. + * + * @param \Drupal\Core\Form\FormStateInterface $formState + * Form state object. + * @param string $field + * Field to check on if contain spam word. + * @param array $spam_words + * List of spam words. + * @param string $spam_words_error + * Error message to display. */ - private function validateSpam(FormStateInterface $formState, $field, $spam_words, $spam_words_error) { - - $spam_error = FALSE; + private function validateSpam(FormStateInterface &$formState, string $field, array $spam_words, string $spam_words_error): void { $field_value = $formState->getValue($field); - $field_value = (is_array($field_value) && isset($field_value['value'])) ? $field_value['value'] : $field_value; - $value = (!empty($field_value) && !is_array($field_value)) ? Html::escape(mb_strtolower($field_value)) : NULL; + $value = is_array($field_value) ? ($field_value['value'] ?? NULL) : Html::escape(mb_strtolower($field_value)); // Skip empty unique fields or arrays. if (empty($value) || is_array($value)) { @@ -71,19 +129,13 @@ class BlockWordsWebformHandler extends WebformHandlerBase { $value = preg_replace('/\s+/', ' ', $value); foreach ($spam_words as $word) { + if (empty($word)) { + continue; + } if (strpos($value, mb_strtolower(trim($word))) !== FALSE) { - $spam_error = TRUE; + $formState->setErrorByName($field, $this->t('@spam_words_error', ['@spam_words_error' => $spam_words_error])); } } - - // Show web form error. - if ($spam_error) { - $formState->setErrorByName($field, $this->t('@spam_words_error', ['@spam_words_error' => $spam_words_error])); - } - else { - $formState->setValue($field, $formState->getValue($field)); - } - } } diff --git a/webform_spam_words.info.yml b/webform_spam_words.info.yml index 1079e42fba8c84fa49cd09c390c074f95c07dabf..884932888e8e43bc57f6c657c4dc4f45428c5124 100644 --- a/webform_spam_words.info.yml +++ b/webform_spam_words.info.yml @@ -3,6 +3,5 @@ description: 'Provides the ability to block spam words for webform fields.' package: 'Webform' type: module core_version_requirement: ^10.3 || ^11.0 -configure: webform_spam_words.config dependencies: - - 'webform:webform' + - webform:webform diff --git a/webform_spam_words.install b/webform_spam_words.install index 8035da1e290a28e8e1357f39d9b31cbb8ad20aad..a98646e5f228d137cd2beb8fd7d89c770c6a678d 100644 --- a/webform_spam_words.install +++ b/webform_spam_words.install @@ -5,6 +5,9 @@ * Installation hooks for Webform spam words module. */ +use Drupal\webform\Entity\Webform; +use Drupal\webform\WebformInterface; + /** * Implements hook_install(). */ @@ -12,3 +15,55 @@ function webform_spam_words_install() { // Assign a weight 1 higher than webform module. module_set_weight('webform_block_words', 1); } + +/** + * Update WSW handlers configurations from old settings. + */ +function webform_spam_words_update_11101(&$sandbox) { + // Get values from Webform spam words settings. + $wsw_config = \Drupal::configFactory() + ->getEditable('webform_spam_words.settings'); + $wsw_settings = $wsw_config->getRawData(); + + // Return early if there is no WSW settings yet. + if (empty($wsw_settings)) { + return; + } + + // Load all webforms. + $webforms = Webform::loadMultiple(); + + foreach ($webforms as $webform) { + // Check if the webform is valid. + if (!$webform instanceof WebformInterface) { + continue; + } + + // Get the handlers for the webform. + $handlers = $webform->getHandlers(); + foreach ($handlers as $handler) { + if ($handler->getHandlerId() === 'webform_spam_words') { + $field_names = explode(',', trim($wsw_settings['spam_field_name'] ?? "")); + foreach ($field_names as $field_name) { + $configuration['settings']['spam_words'][$field_name] = $wsw_settings['spam_words']; + } + $configuration['settings']['spam_text_message'] = $wsw_settings['spam_text_message']; + // Save the updated configuration. + $handler->setConfiguration($configuration); + break; + } + } + + try { + // Save the webform to persist changes. + $webform->save(); + } + catch (\Exception $e) { + // Log the error. + \Drupal::logger('webform_spam_words')->error($e->getMessage()); + } + } + + // Delete old settings. + $wsw_config->delete(); +} diff --git a/webform_spam_words.links.menu.yml b/webform_spam_words.links.menu.yml deleted file mode 100644 index b0d5f67d7229ddeec3ab4168bb09d313a7cfdda8..0000000000000000000000000000000000000000 --- a/webform_spam_words.links.menu.yml +++ /dev/null @@ -1,5 +0,0 @@ -webform_spam_words.admin: - title: 'Webform spam words settings' - description: 'Configuration page for webform spam words.' - parent: system.admin_config_development - route_name: webform_spam_words.config diff --git a/webform_spam_words.routing.yml b/webform_spam_words.routing.yml deleted file mode 100644 index 62d75bdfae258101a24472c388260b9a62e636d9..0000000000000000000000000000000000000000 --- a/webform_spam_words.routing.yml +++ /dev/null @@ -1,7 +0,0 @@ -webform_spam_words.config: - path: '/admin/config/webform/webform-spam-words' - defaults: - _form: '\Drupal\webform_spam_words\Form\BlockwordsConfigurationSettings' - _title: 'Webform Spam words' - requirements: - _permission: 'administer webform+edit webform spam words'