PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.7.15
Post Views Counter v1.7.15
1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / includes / class-settings-other.php
post-views-counter / includes Last commit date
class-admin.php 2 weeks ago class-columns-modal.php 2 weeks ago class-columns.php 2 weeks ago class-counter.php 2 weeks ago class-crawler-detect.php 2 weeks ago class-cron.php 2 weeks ago class-dashboard.php 2 weeks ago class-emails-mailer.php 2 weeks ago class-emails-period.php 2 weeks ago class-emails-query.php 2 weeks ago class-emails-scheduler.php 2 weeks ago class-emails-template.php 2 weeks ago class-emails.php 2 weeks ago class-frontend.php 2 weeks ago class-functions.php 2 weeks ago class-import.php 2 weeks ago class-integration-gutenberg.php 2 weeks ago class-integrations.php 2 weeks ago class-query.php 2 weeks ago class-settings-api.php 2 weeks ago class-settings-display.php 2 weeks ago class-settings-emails.php 2 weeks ago class-settings-general.php 2 weeks ago class-settings-integrations.php 2 weeks ago class-settings-other.php 2 weeks ago class-settings-reports.php 2 weeks ago class-settings.php 2 weeks ago class-toolbar.php 2 weeks ago class-traffic-signals.php 2 weeks ago class-update.php 2 weeks ago class-widgets.php 2 weeks ago functions.php 2 weeks ago
class-settings-other.php
486 lines
1 <?php
2 // exit if accessed directly
3 if ( ! defined( 'ABSPATH' ) )
4 exit;
5
6 /**
7 * Post_Views_Counter_Settings_Other class.
8 *
9 * @class Post_Views_Counter_Settings_Other
10 */
11 class Post_Views_Counter_Settings_Other {
12
13 private $pvc;
14 private $settings;
15
16 /**
17 * Class constructor.
18 *
19 * @param Post_Views_Counter_Settings $settings
20 * @return void
21 */
22 public function __construct( $settings = null ) {
23 $this->pvc = Post_Views_Counter();
24 $this->settings = $settings;
25 }
26
27 /**
28 * Get sections for other tab.
29 *
30 * @return array
31 */
32 public function get_sections() {
33 return [
34 'post_views_counter_other_status' => [
35 'tab' => 'other',
36 'title' => __( 'Plugin Status', 'post-views-counter' ),
37 'callback' => [ $this, 'section_other_status' ]
38 ],
39 'post_views_counter_other_import' => [
40 'tab' => 'other',
41 'title' => __( 'Data Import', 'post-views-counter' ),
42 'callback' => [ $this, 'section_other_import' ]
43 ],
44 'post_views_counter_other_management' => [
45 'tab' => 'other',
46 'title' => __( 'Data Removal', 'post-views-counter' ),
47 'callback' => [ $this, 'section_other_management' ]
48 ]
49 ];
50 }
51
52 /**
53 * Get fields for other tab.
54 *
55 * @return array
56 */
57 public function get_fields() {
58 return [
59 'license' => [
60 'tab' => 'other',
61 'title' => __( 'License Key', 'post-views-counter' ),
62 'section' => 'post_views_counter_other_status',
63 'disabled' => true,
64 'value' => $this->pvc->options['other']['license'],
65 'type' => 'input',
66 'description' => sprintf( __( 'Enter your %s license key (requires Pro version to be installed and active).', 'post-views-counter' ), '<a href="' . esc_url( $this->pvc->get_postviewscounter_url( '/upgrade/', 'link', 'license', 'license-field-pro-link', 'free' ) ) . '" target="_blank">Post Views Counter Pro</a>' ),
67 'subclass' => 'regular-text',
68 'validate' => [ $this, 'validate_license' ],
69 'append' => '<span class="pvc-status-icon"></span>'
70 ],
71 'import_from' => [
72 'tab' => 'other',
73 'title' => __( 'Import From', 'post-views-counter' ),
74 'section' => 'post_views_counter_other_import',
75 'type' => 'custom',
76 'skip_saving' => true,
77 'callback' => [ $this, 'setting_import_from' ]
78 ],
79 'import_strategy' => [
80 'tab' => 'other',
81 'title' => __( 'Import Strategy', 'post-views-counter' ),
82 'section' => 'post_views_counter_other_import',
83 'type' => 'custom',
84 'skip_saving' => true,
85 'callback' => [ $this, 'setting_import_strategy' ]
86 ],
87 'import_actions' => [
88 'tab' => 'other',
89 'title' => '',
90 'section' => 'post_views_counter_other_import',
91 'type' => 'custom',
92 'description' => __( 'Click Analyse Views to check how many views are available for import, or Import Views to begin the import process.', 'post-views-counter' ),
93 'skip_saving' => true,
94 'callback' => [ $this, 'setting_import_actions' ]
95 ],
96 'delete_views' => [
97 'tab' => 'other',
98 'title' => __( 'Delete Views', 'post-views-counter' ),
99 'section' => 'post_views_counter_other_management',
100 'type' => 'custom',
101 'description' => __( 'Delete ALL the existing post views data. Note that this is an irreversible process!', 'post-views-counter' ),
102 'skip_saving' => true,
103 'callback' => [ $this, 'setting_delete_views' ]
104 ],
105 'deactivation_delete' => [
106 'tab' => 'other',
107 'title' => __( 'Delete on Deactivation', 'post-views-counter' ),
108 'section' => 'post_views_counter_other_management',
109 'type' => 'boolean',
110 'description' => __( 'When enabled, deactivating the plugin will delete all plugin data from the database, including all content view counts.', 'post-views-counter' ),
111 'label' => __( 'Delete all plugin data on deactivation.', 'post-views-counter' )
112 ]
113 ];
114 }
115
116 /**
117 * Validate license.
118 *
119 * @param array $input
120 * @param array $field
121 * @return array
122 */
123 public function validate_license( $input, $field ) {
124 // save value from database
125 return $field['value'];
126 }
127
128 /**
129 * Setting: import from.
130 *
131 * @return string
132 */
133 public function setting_import_from() {
134 // get all providers (not just available ones)
135 $all_providers = $this->pvc->import->get_all_providers();
136
137 // get currently selected provider
138 $selected_provider = isset( $this->pvc->options['other']['import_provider_settings']['provider'] ) ? $this->pvc->options['other']['import_provider_settings']['provider'] : 'custom_meta_key';
139
140 // if selected provider is not available, fallback to custom_meta_key
141 if ( isset( $all_providers[$selected_provider] ) ) {
142 $is_selected_available = is_callable( $all_providers[$selected_provider]['is_available'] ) && call_user_func( $all_providers[$selected_provider]['is_available'] );
143 if ( ! $is_selected_available ) {
144 $selected_provider = 'custom_meta_key';
145 }
146 }
147
148 $html = '<div class="pvc-import-provider-selection">';
149 $html .= '<div class="pvc-field-group pvc-radio-group">';
150
151 foreach ( $all_providers as $slug => $provider ) {
152 $is_available = is_callable( $provider['is_available'] ) && call_user_func( $provider['is_available'] );
153 $is_checked = ( $selected_provider === $slug );
154 $disabled_attr = ! $is_available ? ' disabled="disabled"' : '';
155 $disabled_class = ! $is_available ? ' class="pvc-disabled"' : '';
156 $tooltip = ! $is_available ? ' title="' . esc_attr( sprintf( __( '%s is not currently available. Please install and activate the required plugin.', 'post-views-counter' ), $provider['label'] ) ) . '"' : '';
157
158 $html .= '
159 <label' . $disabled_class . $tooltip . '>
160 <input type="radio" id="pvc-other-import-from-' . esc_attr( $slug ) . '" name="pvc_import_provider" value="' . esc_attr( $slug ) . '" ' . checked( $is_checked, true, false ) . $disabled_attr . ' />
161 ' . esc_html( $provider['label'] ) . '
162 </label>';
163 }
164
165 $html .= '</div>';
166 $html .= '<p class="description">' . esc_html__( 'Choose a data source to import existing view counts from.', 'post-views-counter' ) . '</p>';
167
168 $html .= '</div><div class="pvc-import-provider-fields">';
169
170 foreach ( $all_providers as $slug => $provider ) {
171 $is_available = is_callable( $provider['is_available'] ) && call_user_func( $provider['is_available'] );
172 $is_active = ( $selected_provider === $slug );
173 $provider_html = '';
174
175 if ( $is_available && is_callable( $provider['render'] ) ) {
176 $provider_html = call_user_func( $provider['render'] );
177 } elseif ( ! $is_available ) {
178 $provider_html = '<p class="description pvc-provider-unavailable">' . sprintf( __( '%s is not available. Please install and activate the required plugin to use this import source.', 'post-views-counter' ), '<strong>' . esc_html( $provider['label'] ) . '</strong>' ) . '</p>';
179 }
180
181 $logic = [ [ 'field' => 'pvc-other-import-from', 'operator' => 'is', 'value' => $slug, 'container' => 'self' ] ];
182
183 $html .= '
184 <div class="pvc-provider-content pvc-provider-' . esc_attr( $slug ) . '" data-pvc-logic="' . esc_attr( wp_json_encode( $logic ) ) . '" data-pvc-animation="slide">
185 ' . $provider_html . '
186 </div>';
187 }
188
189 $html .= '</div>';
190
191 return $html;
192 }
193
194 /**
195 * Setting: import strategy.
196 *
197 * @return string
198 */
199 public function setting_import_strategy() {
200 // get import strategy
201 $import_strategy = isset( $this->pvc->options['other']['import_provider_settings']['strategy'] ) ? $this->pvc->import->normalize_strategy( $this->pvc->options['other']['import_provider_settings']['strategy'] ) : $this->pvc->import->get_default_strategy();
202 $strategies = $this->pvc->import->get_import_strategies();
203
204 $html = '<div class="pvc-field-group pvc-radio-group">';
205
206 foreach ( $strategies as $slug => $strategy ) {
207 $label = isset( $strategy['label'] ) ? $strategy['label'] : ucwords( str_replace( '_', ' ', $slug ) );
208 $description = isset( $strategy['description'] ) ? $strategy['description'] : '';
209 $is_enabled = $this->pvc->import->is_strategy_enabled( $slug );
210 $input_id = 'pvc-other-import-strategy-' . $slug;
211 $is_pro = ! empty( $strategy['pro_only'] );
212 $pro_unavailable = $is_pro && ! $is_enabled;
213
214 if ( $slug === $import_strategy ) {
215 $current_description = $description;
216 }
217
218 $label_classes = [ 'pvc-import-strategy-option' ];
219 if ( $pro_unavailable ) {
220 $label_classes[] = 'pvc-pro';
221 $label_classes[] = 'pvc-disabled';
222 } elseif ( ! $is_enabled ) {
223 $label_classes[] = 'pvc-disabled';
224 }
225
226 $html .= '<label for="' . esc_attr( $input_id ) . '" class="' . esc_attr( implode( ' ', $label_classes ) ) . '" data-description="' . esc_attr( $description ) . '">
227 <input type="radio" id="' . esc_attr( $input_id ) . '" name="pvc_import_strategy" value="' . esc_attr( $slug ) . '" ' . checked( $import_strategy, $slug, false ) . ' ' . disabled( ! $is_enabled, true, false ) . ' />
228 ' . esc_html( $label );
229
230 $html .= '</label>';
231 }
232
233 $html .= '</div>';
234
235 $html .= '</div>';
236
237 $html .= '<p class="description">' . esc_html__( 'Choose how to handle existing view counts when importing.', 'post-views-counter' ) . '</p>';
238
239 $html .= '<div class="pvc-provider-fields pvc-import-strategy-details">';
240
241 foreach ( $strategies as $slug => $strategy ) {
242 $description = isset( $strategy['description'] ) ? $strategy['description'] : '';
243 $is_active = ( $slug === $import_strategy );
244
245 $logic = [ [ 'field' => 'pvc-other-import-strategy', 'operator' => 'is', 'value' => $slug, 'container' => 'self' ] ];
246 $html .= '<div class="pvc-strategy-content pvc-strategy-' . esc_attr( $slug ) . '" data-pvc-logic="' . esc_attr( wp_json_encode( $logic ) ) . '" data-pvc-animation="slide">
247 <p class="description">' . esc_html( $description ) . '</p>
248 </div>';
249 }
250
251 $html .= '</div>';
252
253 return $html;
254 }
255
256 /**
257 * Setting: import actions.
258 *
259 * @return string
260 */
261 public function setting_import_actions() {
262 $html = '<input type="submit" class="button outline" name="post_views_counter_analyse_views" value="' . esc_attr__( 'Analyse Views', 'post-views-counter' ) . '" />
263 <input type="submit" class="button outline" name="post_views_counter_import_views" value="' . esc_attr__( 'Import Views', 'post-views-counter' ) . '" />';
264
265 return $html;
266 }
267
268 /**
269 * Setting: delete views.
270 *
271 * @return string
272 */
273 public function setting_delete_views() {
274 $html = '
275 <input type="submit" class="button outline" name="post_views_counter_reset_views" value="' . esc_attr__( 'Delete Views', 'post-views-counter' ) . '" />';
276
277 return $html;
278 }
279
280 /**
281 * Section description: other - status.
282 *
283 * @return void
284 */
285 public function section_other_status() {
286 echo '<p class="description">' . esc_html__( 'View license details and other status information.', 'post-views-counter' ) . '</p>';
287
288 // render plugin status rows
289 $rows = $this->get_plugin_status_rows();
290
291 echo '<table class="form-table pvc-status-table"><tbody>';
292 foreach ( (array) $rows as $row ) {
293 $label = isset( $row['label'] ) ? $row['label'] : '';
294 $value = isset( $row['value'] ) ? $row['value'] : '';
295 $active = isset( $row['active'] ) ? (bool) $row['active'] : null;
296 $tables = isset( $row['tables'] ) ? $row['tables'] : null;
297 $actions = isset( $row['actions'] ) && is_array( $row['actions'] ) ? $row['actions'] : [];
298
299 echo '<tr>';
300 echo '<th scope="row">' . esc_html( $label ) . '</th>';
301 echo '<td>';
302
303 // handle tables structure with individual badges
304 if ( is_array( $tables ) && ! empty( $tables ) ) {
305 foreach ( $tables as $table ) {
306 $table_name = isset( $table['name'] ) ? esc_html( $table['name'] ) : '';
307 $table_label = isset( $table['label'] ) ? esc_html( $table['label'] ) : $table_name;
308 $table_exists = isset( $table['exists'] ) ? (bool) $table['exists'] : false;
309
310 echo '<p>';
311 echo $table_label;
312 if ( $table_exists ) {
313 echo ' <span class="pvc-status pvc-status-active">&#10003;</span>';
314 } else {
315 echo ' <span class="pvc-status pvc-status-missing">&#10007;</span>';
316 }
317 echo '</p>';
318 }
319 // handle lines array
320 } elseif ( isset( $row['lines'] ) && is_array( $row['lines'] ) ) {
321 foreach ( $row['lines'] as $line ) {
322 echo '<p>' . wp_kses( $line, [ 'span' => [ 'class' => [] ] ] ) . '</p>';
323 }
324 // handle boolean active status
325 } elseif ( $active === true ) {
326 echo '<span class="pvc-status pvc-status-active">&#10003; ' . esc_html__( 'Active', 'post-views-counter' ) . '</span>';
327 } elseif ( $active === false ) {
328 echo '<span class="pvc-status pvc-status-missing">&#10007; ' . esc_html__( 'Not Detected', 'post-views-counter' ) . '</span>';
329 // handle plain text value
330 } else {
331 echo wp_kses( $value, [ 'br' => [] ] );
332 }
333
334 foreach ( $actions as $action ) {
335 if ( ! is_array( $action ) )
336 continue;
337
338 $action_label = isset( $action['label'] ) && is_scalar( $action['label'] ) ? trim( (string) $action['label'] ) : '';
339 $action_href = isset( $action['href'] ) && is_scalar( $action['href'] ) ? esc_url( (string) $action['href'] ) : '';
340
341 if ( $action_label === '' || $action_href === '' )
342 continue;
343
344 $action_classes = isset( $action['class'] ) && is_string( $action['class'] ) ? preg_split( '/\s+/', trim( $action['class'] ) ) : [];
345 $action_classes = array_values( array_unique( array_filter( array_map( 'sanitize_html_class', $action_classes ) ) ) );
346
347 echo '<p><a href="' . $action_href . '"' . ( ! empty( $action_classes ) ? ' class="' . esc_attr( implode( ' ', $action_classes ) ) . '"' : '' ) . '>' . esc_html( $action_label ) . '</a></p>';
348 }
349
350 echo '</td>';
351 echo '</tr>';
352 }
353 echo '</tbody></table>';
354 }
355
356 /**
357 * Prepare an array with plugin status rows.
358 *
359 * Rows should be associative arrays with: label, value (string), optional active (bool),
360 * and optional actions (arrays containing label, href, and class) keys.
361 * The returned rows will be filtered by 'pvc_plugin_status_rows' which allows extensions to add/modify rows.
362 *
363 * @return array
364 */
365 protected function get_plugin_status_rows() {
366 global $wpdb;
367
368 $version = isset( $this->pvc->defaults['version'] ) ? $this->pvc->defaults['version'] : '';
369
370 if ( empty( $version ) ) {
371 $version = esc_html__( 'unknown', 'post-views-counter' );
372 }
373
374 // detect companion plugin activation status
375 $pvc_pro_active = class_exists( 'Post_Views_Counter_Pro' );
376
377 // get companion plugin version
378 $pro_version = $pvc_pro_active ? get_option( 'post_views_counter_pro_version', '1.0.0' ) : '<span class="pvc-status pvc-status-missing">✗</span>';
379
380 // get database tables via filter
381 $tables = $this->get_plugin_status_tables();
382
383 $rows = [
384 [
385 'label' => __( 'Plugin Version', 'post-views-counter' ),
386 'lines' => [ 'Post Views Counter: ' . $version, 'Post Views Counter Pro: ' . $pro_version ]
387 ]
388 ];
389
390 // add database tables row if any tables are defined
391 if ( ! empty( $tables ) ) {
392 $rows[] = [
393 'label' => __( 'Database Tables', 'post-views-counter' ),
394 'tables' => $tables
395 ];
396 }
397
398 /**
399 * Filter the plugin status rows.
400 *
401 * Allows extensions to add or modify status rows displayed in the settings page.
402 *
403 * @since 1.5.9
404 * @param array $rows Status rows
405 * @param Post_Views_Counter_Settings $this Instance of settings class
406 */
407 $rows = apply_filters( 'pvc_plugin_status_rows', $rows, $this->settings );
408
409 return $rows;
410 }
411
412 /**
413 * Get database tables for status display.
414 *
415 * Collects table definitions via filter, validates that table names contain 'post_views',
416 * checks actual existence in database, and returns formatted array.
417 *
418 * @return array
419 */
420 protected function get_plugin_status_tables() {
421 global $wpdb;
422
423 /**
424 * Filter the database tables to check for plugin status.
425 *
426 * @since 1.5.9
427 * @param array $table_definitions Array of table definitions
428 * @param Post_Views_Counter_Settings $this Instance of settings class
429 */
430 $table_definitions = apply_filters( 'pvc_plugin_status_tables', [], $this->settings );
431
432 if ( empty( $table_definitions ) || ! is_array( $table_definitions ) ) {
433 return [];
434 }
435
436 $validated_tables = [];
437
438 foreach ( $table_definitions as $table_def ) {
439 // validate structure
440 if ( ! is_array( $table_def ) || empty( $table_def['name'] ) ) {
441 continue;
442 }
443
444 $table_name = sanitize_key( $table_def['name'] );
445
446 // security: only allow tables with 'post_views' in the name
447 if ( strpos( $table_name, 'post_views' ) === false ) {
448 continue;
449 }
450
451 // check if table exists
452 $full_table_name = $wpdb->prefix . $table_name;
453 $exists = (bool) $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $full_table_name ) );
454
455 // use provided label or fallback to table name
456 $label = ! empty( $table_def['label'] ) ? $table_def['label'] : $table_name;
457
458 $validated_tables[] = [
459 'name' => $table_name,
460 'label' => $label,
461 'exists' => $exists
462 ];
463 }
464
465 return $validated_tables;
466 }
467
468 /**
469 * Section description: other - data import.
470 *
471 * @return void
472 */
473 public function section_other_import() {
474 echo '<p class="description">' . esc_html__( 'Import view counts when migrating from custom meta key or other analytics plugins.', 'post-views-counter' ) . '</p>';
475 }
476
477 /**
478 * Section description: other - admin & cleanup.
479 *
480 * @return void
481 */
482 public function section_other_management() {
483 echo '<p class="description">' . esc_html__( 'Choose what happens to stored view data on uninstall, and manage other removal-related tools.', 'post-views-counter' ) . '</p>';
484 }
485 }
486