options_repository = $options_repository; } /** * Render the table, or a notice when there is nothing to show. * * @since 1.0.0 */ public function display(): void { $rules = $this->get_sorted_rules(); if (empty($rules)) { echo '

' . esc_html__('No rules found. Try creating some rules first.', 'ads-destroyer') . '

'; return; } $this->render_table(array_slice($rules, 0, self::PER_PAGE)); $this->render_reset_form(); } /** * Get rules sorted by the requested column. * * @since 1.0.0 * @return array> Sorted rules. */ private function get_sorted_rules(): array { $rules = array_values($this->options_repository->get_rules()); $allowed_orderby = ['created_at', 'xpath', 'active', 'page_title']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- URL parameter for sorting, not form submission $orderby = isset($_GET['orderby']) ? sanitize_key(wp_unslash($_GET['orderby'])) : 'created_at'; if (!in_array($orderby, $allowed_orderby, true)) { $orderby = 'created_at'; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- URL parameter for sorting, not form submission $order = isset($_GET['order']) ? sanitize_key(wp_unslash($_GET['order'])) : 'desc'; if (!in_array($order, ['asc', 'desc'], true)) { $order = 'desc'; } usort($rules, static function (array $a, array $b) use ($orderby, $order): int { $a_val = $a[$orderby] ?? ''; $b_val = $b[$orderby] ?? ''; if ($orderby === 'created_at') { $a_val = strtotime((string) $a_val) ?: 0; $b_val = strtotime((string) $b_val) ?: 0; } return $order === 'asc' ? ($a_val <=> $b_val) : ($b_val <=> $a_val); }); return $rules; } /** * Render the rules table. * * @since 1.0.0 * @param array> $rules Rules to display. */ private function render_table(array $rules): void { echo '
'; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; echo ''; foreach ($rules as $rule) { echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Cell methods return escaped HTML echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Cell methods return escaped HTML echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Cell methods return escaped HTML echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Cell methods return escaped HTML echo ''; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Cell methods return escaped HTML echo ''; echo ''; } echo ''; echo '
' . esc_html__('Active', 'ads-destroyer') . '' . esc_html__('XPath Rule', 'ads-destroyer') . '' . esc_html__('Page Info', 'ads-destroyer') . '' . esc_html__('Info', 'ads-destroyer') . '' . esc_html__('Actions', 'ads-destroyer') . '
' . $this->render_active_cell($rule) . '' . $this->render_xpath_cell($rule) . '' . $this->render_page_cell($rule) . '' . $this->render_info_cell($rule) . '' . $this->render_actions_cell($rule) . '
'; echo '
'; } /** * Render the "reset all rules" form. * * @since 1.0.0 */ private function render_reset_form(): void { echo '
'; echo '
'; wp_nonce_field('adsd_reset_rules'); echo ''; echo ''; echo '
'; echo '
'; } /** * Render the active status cell. * * @since 1.0.0 * @param array $rule Rule data. * @return string Cell HTML. */ private function render_active_cell(array $rule): string { $active = !empty($rule['active']); return sprintf( '%s', esc_attr($active ? 'adsd-status-active' : 'adsd-status-inactive'), esc_html($active ? __('Yes', 'ads-destroyer') : __('No', 'ads-destroyer')) ); } /** * Render the XPath cell. * * @since 1.0.0 * @param array $rule Rule data. * @return string Cell HTML. */ private function render_xpath_cell(array $rule): string { $label = (string) ($rule['label'] ?? ''); $output = '
'; $output .= '
'; $output .= '' . esc_html((string) ($rule['xpath'] ?? '')) . ''; $output .= '
'; if ($label !== '') { $output .= '
'; $output .= '' . esc_html($label) . ''; $output .= '
'; } return $output . '
'; } /** * Render the page information cell. * * @since 1.0.0 * @param array $rule Rule data. * @return string Cell HTML. */ private function render_page_cell(array $rule): string { $page_title = (string) ($rule['page_title'] ?? ''); $page_url = (string) ($rule['page_url'] ?? ''); if ($page_title === '') { return '' . esc_html__('Not specified', 'ads-destroyer') . ''; } $output = '
'; $output .= '
' . esc_html($page_title) . '
'; if ($page_url !== '') { $output .= ''; } return $output . '
'; } /** * Render the creation and expiration cell. * * @since 1.0.0 * @param array $rule Rule data. * @return string Cell HTML. */ private function render_info_cell(array $rule): string { $created_at = (string) ($rule['created_at'] ?? ''); $created_by = (string) ($rule['created_by'] ?? ''); $expires_at = (int) ($rule['expires_at'] ?? 0); $output = '
'; if ($created_at !== '') { $output .= '
' . esc_html(sprintf( // translators: %s: Formatted date and time __('Created: %s', 'ads-destroyer'), mysql2date(get_option('date_format') . ' ' . get_option('time_format'), $created_at) )) . '
'; } if ($created_by !== '') { $output .= '
' . esc_html(sprintf( // translators: %s: Author username __('By: %s', 'ads-destroyer'), $created_by )) . '
'; } if ($expires_at <= 0) { $output .= '
' . esc_html__('Forever', 'ads-destroyer') . '
'; return $output . '
'; } $now = time(); if ($expires_at > $now) { $output .= '
' . esc_html(sprintf( // translators: %s: Human-readable time difference __('Expires in: %s', 'ads-destroyer'), human_time_diff($now, $expires_at) )) . '
'; } else { $output .= '
' . esc_html__('Expired', 'ads-destroyer') . '
'; } return $output . ''; } /** * Render the row actions cell. * * @since 1.0.0 * @param array $rule Rule data. * @return string Cell HTML. */ private function render_actions_cell(array $rule): string { $rule_id = (string) ($rule['id'] ?? ''); $active = !empty($rule['active']); $output = '
'; $output .= sprintf( '', esc_attr($rule_id), esc_attr((string) ($rule['xpath'] ?? '')), esc_attr__('Edit Rule', 'ads-destroyer') ); $output .= sprintf( '', esc_attr($rule_id), esc_attr($active ? 'deactivate' : 'activate'), esc_attr($active ? __('Deactivate', 'ads-destroyer') : __('Activate', 'ads-destroyer')), esc_attr($active ? 'dashicons-hidden' : 'dashicons-visibility') ); $output .= sprintf( '', esc_attr($rule_id), esc_attr__('Delete Rule', 'ads-destroyer') ); return $output . '
'; } }