diff --git a/src/Plugin/views/sort/AISorting.php b/src/Plugin/views/sort/AISorting.php index 81fd57a..91136f9 100644 --- a/src/Plugin/views/sort/AISorting.php +++ b/src/Plugin/views/sort/AISorting.php @@ -83,6 +83,9 @@ protected function defineOptions() { $options = parent::defineOptions(); $options['order'] = ['default' => '']; $options['cache_max_age'] = ['default' => 60]; + $options['favor_recent'] = ['default' => FALSE]; + // 3 months default + $options['time_window_seconds'] = ['default' => 7776000]; return $options; } @@ -94,7 +97,17 @@ public function query() { $this->ensureMyTable(); $experiment_uuid = sha1($this->view->id() . ':' . $this->view->current_display); - $scores = $this->experimentManager->getThompsonScores($experiment_uuid); + + // Only apply time window if "Favor recent content" is enabled. + $time_window_seconds = NULL; + if ($this->options['favor_recent']) { + $time_window_seconds = $this->options['time_window_seconds']; + } + + $scores = $this->experimentManager->getThompsonScoresWithWindow( + $experiment_uuid, + $time_window_seconds + ); if (empty($scores)) { throw new \RuntimeException(sprintf( @@ -143,8 +156,53 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { How it works:
Turns: When content appears in this view
Rewards: When users click on that content
- • The algorithm balances showing popular content with exploring new options

- Best for: News feeds, product listings, blog posts, or any content where user engagement matters.'), + • The algorithm balances showing popular content with exploring new options.'), + ]; + + $form['ai_sorting_settings']['favor_recent'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Favor recent content'), + '#default_value' => $this->options['favor_recent'] ?? FALSE, + '#description' => $this->t('Enable this for content that becomes outdated (news, campaigns, seasonal products).'), + ]; + + $form['ai_sorting_settings']['time_window_seconds'] = [ + '#type' => 'select', + '#title' => $this->t('Count interactions from'), + '#default_value' => $this->options['time_window_seconds'] ?? 7776000, + '#options' => [ + // 30 * 24 * 60 * 60 + 2592000 => $this->t('Last month'), + // 90 * 24 * 60 * 60 + 7776000 => $this->t('Last 3 months'), + // 180 * 24 * 60 * 60 + 15552000 => $this->t('Last 6 months'), + // 365 * 24 * 60 * 60 + 31536000 => $this->t('Last year'), + ], + '#states' => [ + 'visible' => [ + ':input[name="options[ai_sorting_settings][favor_recent]"]' => ['checked' => TRUE], + ], + ], + '#description' => $this->t('Only recently active content influences recommendations.'), + ]; + + $form['ai_sorting_settings']['help'] = [ + '#type' => 'details', + '#title' => $this->t('Which timeframe should I choose?'), + '#open' => FALSE, + '#states' => [ + 'visible' => [ + ':input[name="options[ai_sorting_settings][favor_recent]"]' => ['checked' => TRUE], + ], + ], + '#description' => $this->t(' + News & announcements: Last month
+ Blog posts: Last 3 months
+ Products: Last 6 months
+ Leave unchecked for: Documentation, tutorials, evergreen content + '), ]; $url = Url::fromUri('https://en.wikipedia.org/wiki/Thompson_sampling', [ @@ -186,6 +244,14 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) { $options = &$form_state->getValue('options'); + if (isset($options['ai_sorting_settings']['favor_recent'])) { + $this->options['favor_recent'] = $options['ai_sorting_settings']['favor_recent']; + } + + if (isset($options['ai_sorting_settings']['time_window_seconds'])) { + $this->options['time_window_seconds'] = $options['ai_sorting_settings']['time_window_seconds']; + } + if (isset($options['ai_sorting_settings']['advanced']['cache_max_age'])) { $this->options['cache_max_age'] = $options['ai_sorting_settings']['advanced']['cache_max_age']; } @@ -223,6 +289,28 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state) { public function adminSummary() { $summary = []; + // Time window summary. + if (!empty($this->options['favor_recent'])) { + $time_window_seconds = $this->options['time_window_seconds']; + if ($time_window_seconds == 2592000) { + $summary[] = $this->t('Time window: Last month'); + } + elseif ($time_window_seconds == 7776000) { + $summary[] = $this->t('Time window: Last 3 months'); + } + elseif ($time_window_seconds == 15552000) { + $summary[] = $this->t('Time window: Last 6 months'); + } + elseif ($time_window_seconds == 31536000) { + $summary[] = $this->t('Time window: Last year'); + } + else { + $days = round($time_window_seconds / 86400); + $summary[] = $this->t('Time window: Last @days days', ['@days' => $days]); + } + } + + // Cache summary. $cache_max_age = $this->options['cache_max_age']; if ($cache_max_age == 0) { $summary[] = $this->t('Cache: Never cache');