HEX
Server: Apache/2.4.62 (Debian)
System: Linux plxsite 6.8.0-47-generic #47-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 27 21:40:26 UTC 2024 x86_64
User: root (0)
PHP: 8.1.30
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/post-views-counter/includes/class-settings-display.php
<?php
// exit if accessed directly
if ( ! defined( 'ABSPATH' ) )
	exit;

/**
 * Post_Views_Counter_Settings_Display class.
 *
 * @class Post_Views_Counter_Settings_Display
 */
class Post_Views_Counter_Settings_Display {

	private $pvc;
	private static $syncing_menu_position = false;

	/**
	 * Class constructor.
	 *
	 * @return void
	 */
	public function __construct() {
		$this->pvc = Post_Views_Counter();

		// actions
		add_action( 'update_option_post_views_counter_settings_display', [ $this, 'sync_menu_position_option' ], 10, 3 );
		add_action( 'add_option_post_views_counter_settings_display', [ $this, 'sync_menu_position_option_on_add' ], 10, 2 );

		// filters
		add_filter( 'pre_update_option_post_views_counter_settings_other', [ $this, 'sync_menu_position_from_other' ], 10, 2 );
	}

	/**
	 * Get sections for display tab.
	 *
	 * @return array
	 */
	public function get_sections() {
		return [
			'post_views_counter_display_appearance' => [
				'tab'      => 'display',
				'title'    => __( 'Counter Appearance', 'post-views-counter' ),
				'callback' => [ $this, 'section_display_appearance' ],
			],
			'post_views_counter_display_locations' => [
				'tab'   => 'display',
				'title' => __( 'Display Targets', 'post-views-counter' ),
				'callback' => [ $this, 'section_display_targets' ],
			],
			'post_views_counter_display_visibility' => [
				'tab'   => 'display',
				'title' => __( 'Display Audience', 'post-views-counter' ),
				'callback' => [ $this, 'section_display_audience' ],
			],
			'post_views_counter_display_admin' => [
				'tab'      => 'display',
				'title'    => __( 'Admin Interface', 'post-views-counter' ),
				'callback' => [ $this, 'section_display_admin' ],
			]
		];
	}

	/**
	 * Get fields for display tab.
	 *
	 * @return array
	 */
	public function get_fields() {
		// get post types
		$post_types = $this->pvc->functions->get_post_types();

		// user groups
		$groups = [
			'users'		=> __( 'logged in users', 'post-views-counter' ),
			'guests'	=> __( 'guests', 'post-views-counter' ),
			'roles'		=> __( 'selected user roles', 'post-views-counter' )
		];

		// get user roles
		$user_roles = $this->pvc->functions->get_user_roles();

		return [
			'label' => [
				'tab'			=> 'display',
				'title'			=> __( 'Views Label', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_appearance',
				'type'			=> 'input',
				'html_id'		=> 'pvc-label',
				'description'	=> __( 'Text shown next to the view count.', 'post-views-counter' ),
				'subclass'		=> 'regular-text',
				'validate'		=> [ $this, 'validate_label' ],
				'reset'			=> [ $this, 'reset_label' ]
			],
			'display_period' => [
				'tab'			=> 'display',
				'title'			=> __( 'Views Period', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_appearance',
				'type'			=> 'select',
				'class'			=> 'pvc-pro',
				'disabled'		=> true,
				'skip_saving'	=> true,
				'description'	=> __( 'Time range used when displaying the number of views.', 'post-views-counter' ),
				'pro_only'		=> true,
				'options'		=> 	[
					'total'		=> __( 'Total Views', 'post-views-counter' )
				]
			],
			'display_style' => [
				'tab'			=> 'display',
				'title'			=> __( 'Display Style', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_appearance',
				'type'			=> 'custom',
				'html_id'		=> 'pvc-display-style',
				'description'	=> __( 'Choose whether to show an icon, label text, or both.', 'post-views-counter' ),
				'callback'		=> [ $this, 'setting_display_style' ],
				'validate'		=> [ $this, 'validate_display_style' ],
				'options'		=> [
					'icon'	=> __( 'Icon', 'post-views-counter' ),
					'text'	=> __( 'Label', 'post-views-counter' )
				]
			],
			'icon_class' => [
				'tab'			=> 'display',
				'title'			=> __( 'Icon Class', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_appearance',
				'type'			=> 'class',
				'default'		=> '',
				'html_id'		=> 'pvc-icon-class',
				'parent'		=> 'pvc-display-style',
				'logic'			=> [
					'field'		=> 'pvc-display-style-icon',
					'operator'	=> 'is',
					'value'		=> 'icon'
				],
				'animation'		=> 'slide',
				'description'	=> sprintf( __( 'Enter the CSS class for the views icon. Any Dashicons class is supported.', 'post-views-counter' ), 'https://developer.wordpress.org/resource/dashicons/' ),
				'subclass'		=> 'regular-text'
			],
			'position' => [
				'tab'			=> 'display',
				'title'			=> __( 'Position', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_locations',
				'type'			=> 'select',
				'html_id'		=> 'pvc-position',
				'description'	=> sprintf( __( 'Where to insert the counter automatically. Use %s shortcode for manual placement.', 'post-views-counter' ), '<code>[post-views]</code>' ),
				'options'		=> [
					'before'	=> __( 'Before the content', 'post-views-counter' ),
					'after'		=> __( 'After the content', 'post-views-counter' ),
					'manual'	=> __( 'Manual only', 'post-views-counter' )
				]
			],
			'post_views_column' => [
				'tab'			=> 'display',
				'title'			=> __( 'Admin Column', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_admin',
				'type'			=> 'boolean',
				'description'	=> '',
				'label'			=> __( 'Show a "Views" column on post and page list screens.', 'post-views-counter' )
			],
			'restrict_edit_views' => [
				'tab'			=> 'display',
				'title'			=> __( 'Admin Edit', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_admin',
				'type'			=> 'boolean',
				'description'	=> '',
				'label'			=> __( 'Allow editing the view count on the post edit screen.', 'post-views-counter' )
			],
			'dynamic_loading' => [
				'tab'			=> 'display',
				'title'			=> __( 'Dynamic Loading', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_appearance',
				'type'			=> 'boolean',
				'class'			=> 'pvc-pro',
				'disabled'		=> true,
				'skip_saving'	=> true,
				'value'			=> false,
				'label'			=> __( 'Load the view count dynamically to avoid caching the displayed value.', 'post-views-counter' ),
				'pro_only'		=> true
			],
			'use_format' => [
				'tab'			=> 'display',
				'title'			=> __( 'Format Number', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_appearance',
				'type'			=> 'boolean',
				'label'			=> __( 'Format the view count according to the site locale (uses the WordPress number_format_i18n function).', 'post-views-counter' )
			],
			'taxonomies' => [
				'tab'			=> 'display',
				'title'			=> __( 'Taxonomies', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_locations',
				'type'			=> 'boolean',
				'class'			=> 'pvc-pro',
				'disabled'		=> true,
				'skip_saving'	=> true,
				'value'			=> false,
				'label'			=> __( 'Display the view count on category, tag, or custom taxonomy archive pages.', 'post-views-counter' ),
				'pro_only'		=> true
			],
			'taxonomies_display' => [
				'tab'			=> 'display',
				'section'		=> 'post_views_counter_display_locations',
				'type'			=> 'checkbox',
				'class'			=> 'pvc-pro',
				'description'	=> __( 'Select taxonomies where the view counter will be displayed.', 'post-views-counter' ),			'skip_saving'	=> true,
				'options'		=> $this->pvc->functions->get_taxonomies( 'labels' ),
				'disabled'		=> true,
				'name'			=> 'post_views_counter_settings_display[taxonomies_display]',
				'value'			=> $this->pvc->options['display']['taxonomies_display'],
				'pro_only'		=> true,
				'logic'			=> [
					'field'		=> 'taxonomies',
					'operator'	=> 'is',
					'value'		=> 'true'
				],
				'animation'		=> 'slide'
			],
			'user_display' => [
				'tab'			=> 'display',
				'title'			=> __( 'Author Archives', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_locations',
				'type'			=> 'boolean',
				'class'			=> 'pvc-pro',
				'disabled'		=> true,
				'skip_saving'	=> true,
				'value'			=> false,
				'label'			=> __( 'Display the view count on author archive pages.', 'post-views-counter' ),
				'pro_only'		=> true
			],
			'post_types_display' => [
				'tab'			=> 'display',
				'title'			=> __( 'Post Types', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_locations',
				'type'			=> 'checkbox',
				'description'	=> __( 'Select post types where the view counter will be displayed.', 'post-views-counter' ),
				'options'		=> $post_types
			],
			'page_types_display' => [
				'tab'			=> 'display',
				'title'			=> __( 'Page Type', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_locations',
				'type'			=> 'checkbox',
				'description'	=> __( 'Select page contexts where the view counter will be displayed.', 'post-views-counter' ),
				'options'		=> apply_filters(
					'pvc_page_types_display_options',
					[
						'home'		=> __( 'Home', 'post-views-counter' ),
						'archive'	=> __( 'Archives', 'post-views-counter' ),
						'singular'	=> __( 'Single posts and pages', 'post-views-counter' ),
						'search'	=> __( 'Search results', 'post-views-counter' ),
					]
				)
			],
			'restrict_display_groups' => [
				'tab' => 'display',
				'title' => __( 'User Type', 'post-views-counter' ),
				'section' => 'post_views_counter_display_visibility',
				'type' => 'checkbox',
				'description' => __( 'Hide the view counter for selected visitor groups.', 'post-views-counter' ),
				'options' => $groups,
				'name' => 'post_views_counter_settings_display[restrict_display][groups]',
				'value' => $this->pvc->options['display']['restrict_display']['groups'],
				'validate' => [ $this, 'validate_restrict_display_groups' ],
			],
			'restrict_display_roles' => [
				'tab' => 'display',
				'title' => __( 'User Roles', 'post-views-counter' ),
				'section' => 'post_views_counter_display_visibility',
				'type' => 'checkbox',
				'description' => __( 'Hide the view counter for selected user roles.', 'post-views-counter' ),
				'options' => $user_roles,
				'name' => 'post_views_counter_settings_display[restrict_display][roles]',
				'value' => $this->pvc->options['display']['restrict_display']['roles'],
				'logic' => [ [ 'field' => 'restrict_display_groups', 'operator' => 'contains', 'value' => 'roles' ] ],
				'animation' => 'slide',
				'validate' => [ $this, 'validate_restrict_display_roles' ],
			],
			'toolbar_statistics' => [
				'tab'			=> 'display',
				'title'			=> __( 'Toolbar Chart', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_admin',
				'type'			=> 'boolean',
				'description'	=> __( 'A views chart is shown for content types that are being counted.', 'post-views-counter' ),
				'label'			=> __( 'Show a views chart in the admin toolbar.', 'post-views-counter' )
			],
			'menu_position' => [
				'tab'			=> 'display',
				'title'			=> __( 'Menu Position', 'post-views-counter' ),
				'section'		=> 'post_views_counter_display_admin',
				'type'			=> 'radio',				'html_id'		=> 'pvc-menu-position',				'options'		=> [
					'top'	=> __( 'Top menu', 'post-views-counter' ),
					'sub'	=> __( 'Settings submenu', 'post-views-counter' )
				],
				'description'	=> __( 'Choose where the plugin menu appears in the admin sidebar.', 'post-views-counter' ),
			]
		];
	}

	/**
	 * Validate label.
	 *
	 * @param array $input
	 * @param array $field
	 * @return array
	 */
	public function validate_label( $input, $field ) {
		if ( ! isset( $input ) )
			$input = $this->pvc->defaults['display']['label'];

		// use internal settings API to validate settings first
		$input = $this->pvc->settings_api->validate_field( $input, 'input', $field );

		if ( function_exists( 'icl_register_string' ) )
			icl_register_string( 'Post Views Counter', 'Post Views Label', $input );

		return $input;
	}

	/**
	 * Restore post views label to default value.
	 *
	 * @param array $default
	 * @param array $field
	 * @return array
	 */
	public function reset_label( $default, $field ) {
		if ( function_exists( 'icl_register_string' ) )
			icl_register_string( 'Post Views Counter', 'Post Views Label', $default );

		return $default;
	}

	/**
	 * Setting: display style.
	 *
	 * @param array $field
	 * @return string
	 */
	public function setting_display_style( $field ) {
		$html = '<div class="pvc-field-group pvc-checkbox-group">';
		$html .= '<input type="hidden" name="post_views_counter_settings_display[display_style]" value="empty" />';
		
		foreach ( $field['options'] as $key => $label ) {
			$html .= '
			<label><input id="pvc-display-style-' . esc_attr( $key ) . '" type="checkbox" name="post_views_counter_settings_display[display_style][]" value="' . esc_attr( $key ) . '" ' . checked( ! empty( $this->pvc->options['display']['display_style'][$key] ), true, false ) . ' />' . esc_html( $label ) . '</label> ';
		}
		$html .= '</div>';

		return $html;
	}

	/**
	 * Validate display style.
	 *
	 * @param array $input
	 * @param array $field
	 * @return array
	 */
	public function validate_display_style( $input, $field ) {
		$data = [];

		foreach ( $field['options'] as $value => $label ) {
			$data[$value] = false;
		}

		// any data?
		if ( ! empty( $input['display_style'] && $input['display_style'] !== 'empty' && is_array( $input['display_style'] ) ) ) {
			foreach ( $input['display_style'] as $value ) {
				if ( array_key_exists( $value, $field['options'] ) )
					$data[$value] = true;
			}
		}

		$input['display_style'] = $data;

		return $input;
	}

	/**
	 * Validate user type.
	 *
	 * @param array $input
	 * @param array $field
	 *
	 * @return array
	 */
	public function validate_restrict_display_groups( $input, $field ) {
		$groups = [];

		if ( is_array( $input ) ) {
			foreach ( $input as $group ) {
				// sanitize value
				$group = sanitize_key( $group );

				if ( $group === 'robots' || $group === 'ai_bots' )
					continue;

				if ( isset( $field['options'][$group] ) )
					$groups[] = $group;
			}
		}

		return array_unique( $groups );
	}

	public function validate_restrict_display_roles( $input, $field ) {
		$roles = [];

		if ( is_array( $input ) ) {
			foreach ( $input as $role ) {
				// sanitize value
				$role = sanitize_key( $role );

				if ( isset( $field['options'][$role] ) )
					$roles[] = $role;
			}
		}

		return array_unique( $roles );
	}

	/**
	 * Section description: display targets.
	 *
	 * @return void
	 */
	public function section_display_targets() {
		echo '<p class="description">' . esc_html__( 'Choose where the counter is inserted and which content types it attaches to.', 'post-views-counter' ) . '</p>';
	}

	/**
	 * Section description: display audience.
	 *
	 * @return void
	 */
	public function section_display_audience() {
		echo '<p class="description">' . esc_html__( 'Control which visitor groups can see the counter. These rules apply on top of the display targets.', 'post-views-counter' ) . '</p>';
	}

	/**
	 * Section description: counter appearance.
	 *
	 * @return void
	 */
	public function section_display_appearance() {
		echo '<p class="description">' . esc_html__( 'Adjust the label, period, icon, and formatting used when the counter is rendered.', 'post-views-counter' ) . '</p>';
	}

	/**
	 * Section description: admin interface.
	 *
	 * @return void
	 */
	public function section_display_admin() {
		echo '<p class="description">' . esc_html__( 'Control how view counts are shown and managed in WordPress admin (columns, edit permissions, toolbar chart).', 'post-views-counter' ) . '</p>';
	}

	/**
	 * Mirror the saved menu position to legacy storage.
	 *
	 * @param mixed $old_value
	 * @param mixed $value
	 * @param string $option
	 * @return void
	 */
	public function sync_menu_position_option( $old_value, $value, $option ) {
		if ( self::$syncing_menu_position )
			return;

		self::$syncing_menu_position = true;
		$this->mirror_menu_position_value( $value );
		self::$syncing_menu_position = false;
	}

	/**
	 * Mirror the saved menu position when the option is added.
	 *
	 * @param string $option
	 * @param mixed $value
	 * @return void
	 */
	public function sync_menu_position_option_on_add( $option, $value ) {
		if ( self::$syncing_menu_position )
			return;

		self::$syncing_menu_position = true;
		$this->mirror_menu_position_value( $value );
		self::$syncing_menu_position = false;
	}

	/**
	 * Update the legacy menu position value stored under "Other" settings.
	 *
	 * @param mixed $value
	 * @return void
	 */
	private function mirror_menu_position_value( $value ) {
		if ( ! is_array( $value ) )
			return;

		$menu_position = isset( $value['menu_position'] ) && in_array( $value['menu_position'], [ 'top', 'sub' ], true ) ? $value['menu_position'] : 'top';
		$other_options = get_option( 'post_views_counter_settings_other', [] );

		if ( ! is_array( $other_options ) )
			$other_options = [];

		if ( ! isset( $other_options['menu_position'] ) || $other_options['menu_position'] !== $menu_position ) {
			$other_options['menu_position'] = $menu_position;
			update_option( 'post_views_counter_settings_other', $other_options );
		}

		$this->pvc->options['other']['menu_position'] = $menu_position;
	}

	/**
	 * Sync menu position from legacy writes to "Other" settings.
	 *
	 * @param mixed $value
	 * @param mixed $old_value
	 * @return mixed
	 */
	public function sync_menu_position_from_other( $value, $old_value ) {
		if ( self::$syncing_menu_position || ! is_array( $value ) || ! isset( $value['menu_position'] ) )
			return $value;

		$menu_position = in_array( $value['menu_position'], [ 'top', 'sub' ], true ) ? $value['menu_position'] : 'top';

		self::$syncing_menu_position = true;

		$display_options = get_option( 'post_views_counter_settings_display', [] );

		if ( ! is_array( $display_options ) )
			$display_options = [];

		if ( ! isset( $display_options['menu_position'] ) || $display_options['menu_position'] !== $menu_position ) {
			$display_options['menu_position'] = $menu_position;
			update_option( 'post_views_counter_settings_display', $display_options );
		}

		$this->pvc->options['display']['menu_position'] = $menu_position;

		self::$syncing_menu_position = false;

		return $value;
	}
}