File "admin.php"

Full Path: /home/fresvfqn/waterdamagerestorationandrepairsmithtown.com/wp-content/plugins/surerank/inc/api/admin.php
File size: 13.01 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * Admin class
 *
 * Handles admin settings related REST API endpoints for the SureRank plugin.
 *
 * @package SureRank\Inc\API
 */

namespace SureRank\Inc\API;

use SureRank\Inc\Admin\Update_Timestamp;
use SureRank\Inc\Functions\Get;
use SureRank\Inc\Functions\Helper;
use SureRank\Inc\Functions\Send_Json;
use SureRank\Inc\Functions\Settings;
use SureRank\Inc\Functions\Update;
use SureRank\Inc\Meta_Variables\Post;
use SureRank\Inc\Meta_Variables\Site;
use SureRank\Inc\Meta_Variables\Term;
use SureRank\Inc\Traits\Get_Instance;
use WP_REST_Request;
use WP_REST_Server;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Class Admin
 *
 * Handles admin settings related REST API endpoints.
 */
class Admin extends Api_Base {
	use Get_Instance;

	/**
	 * Route Editor
	 */
	protected const EDITOR = '/admin/editor';

	/**
	 * Route Get Admin Settings
	 */
	protected const ADMIN_SETTINGS = '/admin/global-settings';

	/**
	 * Route Get Site Settings
	 */
	protected const SITE_SETTINGS = '/admin/site-settings';

	/**
	 * Constructor
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
	}

	/**
	 * Register API routes.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function register_routes() {
		$namespace = $this->get_api_namespace();
		$this->register_all_admin_routes( $namespace );
	}

	/**
	 * Retrieves email logs with optional filters and search.
	 *
	 * @param WP_REST_Request<array<string, mixed>> $request The REST request object.
	 * @return void
	 */
	public function get_initials( $request ) {

		$post_id = $request->get_param( 'post_id' );
		$term_id = $request->get_param( 'term_id' );

		if ( empty( $post_id ) && empty( $term_id ) ) {
			Send_Json::error( [ 'message' => __( 'Post id or term id is required', 'surerank' ) ] );
		}

		Send_Json::success(
			[
				'variables' => $this->get_variables( $request->get_param( 'post_id' ), $request->get_param( 'term_id' ) ),
				'other'     => $this->get_other_data(),
			]
		);
	}

	/**
	 * Get variables
	 *
	 * @param int|null $post_id Post ID.
	 * @param int|null $term_id Term ID.
	 * @since 1.0.0
	 * @return array<string, array<string, mixed>> Array of variable groups keyed by type (e.g., term, post, site).
	 */
	public function get_variables( $post_id = null, $term_id = null ) {

		$meta_variable_instances = [];
		if ( ! empty( $term_id ) ) {
			$meta_variable_instances['term'] = Term::get_instance();
		}
		if ( ! empty( $post_id ) ) {
			$meta_variable_instances['post'] = Post::get_instance();
		}
		$meta_variable_instances['site'] = Site::get_instance();

		$variables = [];
		foreach ( $meta_variable_instances as $key => $instance ) {
			if ( ! empty( $post_id ) && method_exists( $instance, 'set_post' ) ) {
				$instance->set_post( $post_id );
			}
			if ( ! empty( $term_id ) && method_exists( $instance, 'set_term' ) ) {
				$instance->set_term( $term_id );
			}
			$variables[ $key ] = $instance->get_all_values();
		}

		return $variables;
	}

	/**
	 * Get other data.
	 *
	 * @since 1.0.0
	 * @return array<string, string>
	 */
	public function get_other_data() {
		$data = [];

		// Get site favicon icon.
		$data['favicon_url'] = $this->get_favicon();

		return $data;
	}

	/**
	 * Get admin settings
	 *
	 * @param WP_REST_Request<array<string, mixed>> $request Request object.
	 * @since 1.0.0
	 * @return void
	 */
	public function get_admin_settings( $request ) {
		$data                             = Settings::get();
		$data['surerank_analytics_optin'] = Get::option( 'surerank_analytics_optin' ) === 'yes' ? true : false;
		$decode_data                      = Utils::decode_html_entities_recursive( $data ) ?? $data;
		Send_Json::success( [ 'data' => $decode_data ] );
	}

	/**
	 * Update admin settings
	 *
	 * @param WP_REST_Request<array<string, mixed>> $request Request object.
	 * @since 1.0.0
	 * @return void
	 */
	public function update_admin_settings( $request ) {
		$data = $request->get_param( 'data' );
		if ( empty( $data ) ) {
			Send_Json::error( [ 'message' => __( 'No data found', 'surerank' ) ] );
		}

		// Allow pro plugin to handle extended meta templates toggle detection BEFORE getting any settings.
		do_action( 'surerank_admin_settings_before_processing', $data );

		$db_options = Settings::get();

		$updated_options = $this->get_updated_options( $data, $db_options );

		Helper::update_flush_rules( $updated_options );

		$data = $this->process_social_profile_updates( $data, $updated_options );
		$data = array_merge( $db_options, $data );
		$data = $this->process_surerank_analytics_optin( $data );

		if ( Update::option( SURERANK_SETTINGS, $data ) ) {
			Update_Timestamp::timestamp_option();
		}

		Send_Json::success( [ 'message' => __( 'Settings updated', 'surerank' ) ] );
	}

	/**
	 * Process surerank analytics optin
	 *
	 * @param array<string, mixed> $data Data.
	 * @since 1.0.0
	 * @return array<string, mixed>
	 */
	public function process_surerank_analytics_optin( $data ) {

		if ( ! isset( $data['surerank_analytics_optin'] ) ) {
			return $data;
		}

		$surerank_analytics_optin = $data['surerank_analytics_optin'] ? 'yes' : 'no';
		Update::option( 'surerank_analytics_optin', $surerank_analytics_optin );
		unset( $data['surerank_analytics_optin'] );

		return $data;
	}

	/**
	 * Get site settings
	 *
	 * @param WP_REST_Request<array<string, mixed>> $request Request object.
	 * @since 1.0.0
	 * @return void
	 */
	public function get_site_settings( $request ) {
		$data = $this->prepare_site_settings_data();
		Send_Json::success( [ 'data' => $data ] );
	}

	/**
	 * Get updated options
	 *
	 * @param array<string, mixed|array> $data       First array.
	 * @param array<string, mixed|array> $db_options Second array.
	 * @param string                     $parent_key  Parent key.
	 *
	 * @return array<int, string> Updated option keys.
	 */
	public function get_updated_options( $data, $db_options, $parent_key = '' ) {
		$diff_keys = [];

		foreach ( $data as $key => $value ) {
			if ( 'default_global_meta' === $key ) {
				continue;
			}
			if ( is_array( $value ) ) {
				if ( isset( $db_options[ $key ] ) && is_array( $db_options[ $key ] ) ) {
					$nested_diff = $this->get_updated_options( $value, $db_options[ $key ], $key );
					if ( ! empty( $nested_diff ) ) {
						$diff_keys[] = $key;
					}
				} else {
					$diff_keys[] = $key;
				}
			} else {
				if ( ! isset( $db_options[ $key ] ) || $db_options[ $key ] !== $value ) {
					$diff_keys[] = $key;
				}
			}
		}
		return array_unique( $diff_keys );
	}

	/**
	 * Process Onboarding Data
	 *
	 * @param array<string, mixed> $data Data.
	 * @param array<string, mixed> $settings Settings.
	 * @since 1.0.0
	 * @return void
	 */
	public function process_onboarding_data( $data, &$settings ) {
		Onboarding::get_instance()->set_social_schema( $data, $settings );
	}

	/**
	 * Register all admin routes
	 *
	 * @param string $namespace The API namespace.
	 * @return void
	 */
	private function register_all_admin_routes( $namespace ) {
		$this->register_editor_route( $namespace );
		$this->register_admin_settings_routes( $namespace );
		$this->register_site_settings_route( $namespace );
	}

	/**
	 * Register editor route
	 *
	 * @param string $namespace The API namespace.
	 * @return void
	 */
	private function register_editor_route( $namespace ) {
		register_rest_route(
			$namespace,
			self::EDITOR,
			[
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_initials' ],
				'permission_callback' => [ $this, 'validate_permission' ],
				'args'                => $this->get_editor_args(),
			]
		);
	}

	/**
	 * Register admin settings routes
	 *
	 * @param string $namespace The API namespace.
	 * @return void
	 */
	private function register_admin_settings_routes( $namespace ) {
		$this->register_get_admin_settings_route( $namespace );
		$this->register_update_admin_settings_route( $namespace );
	}

	/**
	 * Register get admin settings route
	 *
	 * @param string $namespace The API namespace.
	 * @return void
	 */
	private function register_get_admin_settings_route( $namespace ) {
		register_rest_route(
			$namespace,
			self::ADMIN_SETTINGS,
			[
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_admin_settings' ],
				'permission_callback' => [ $this, 'validate_permission' ],
			]
		);
	}

	/**
	 * Register update admin settings route
	 *
	 * @param string $namespace The API namespace.
	 * @return void
	 */
	private function register_update_admin_settings_route( $namespace ) {
		register_rest_route(
			$namespace,
			self::ADMIN_SETTINGS,
			[
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => [ $this, 'update_admin_settings' ],
				'permission_callback' => [ $this, 'validate_permission' ],
				'args'                => $this->get_admin_settings_update_args(),
			]
		);
	}

	/**
	 * Register site settings route
	 *
	 * @param string $namespace The API namespace.
	 * @return void
	 */
	private function register_site_settings_route( $namespace ) {
		register_rest_route(
			$namespace,
			self::SITE_SETTINGS,
			[
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'get_site_settings' ],
				'permission_callback' => [ $this, 'validate_permission' ],
			]
		);
	}

	/**
	 * Get editor route arguments
	 *
	 * @return array<string, array<string, mixed>>
	 */
	private function get_editor_args() {
		return [
			'post_id' => [
				'type'              => 'integer',
				'sanitize_callback' => 'absint',
			],
			'term_id' => [
				'type'              => 'integer',
				'sanitize_callback' => 'absint',
			],
		];
	}

	/**
	 * Get admin settings update arguments
	 *
	 * @return array<string, array<string, mixed>>
	 */
	private function get_admin_settings_update_args() {
		return [
			'data' => [
				'type'              => 'object',
				'required'          => true,
				'sanitize_callback' => [ $this, 'sanitize_array_data' ],
			],
		];
	}

	/**
	 * Process social profile updates
	 *
	 * @param array<string, mixed> $data Data.
	 * @param array<string>        $updated_options Updated options.
	 * @return array<string, mixed>
	 */
	private function process_social_profile_updates( $data, $updated_options ) {
		if ( $this->should_update_social_profiles( $updated_options ) ) {
			$data = $this->update_social_profile_data( $data );
			$this->process_onboarding_data( $data, $data );
		}
		return $data;
	}

	/**
	 * Check if social profiles should be updated
	 *
	 * @param array<string> $updated_options Updated options.
	 * @return bool
	 */
	private function should_update_social_profiles( $updated_options ) {
		return is_array( $updated_options ) && array_intersect(
			[ 'social_profiles', 'facebook_page_url', 'twitter_profile_username' ],
			$updated_options
		);
	}

	/**
	 * Update social profile data
	 *
	 * @param array<string, mixed> $data Data.
	 * @return array<string, mixed>
	 */
	private function update_social_profile_data( $data ) {
		$data['social_profiles']['facebook'] = $data['facebook_page_url'] ?? '';

		if ( ! empty( $data['twitter_profile_username'] ) ) {
			$data['social_profiles']['twitter'] = str_replace( '@', '', $data['twitter_profile_username'] );
		}

		return $data;
	}

	/**
	 * Prepare site settings data
	 *
	 * @return array<string, mixed>
	 */
	private function prepare_site_settings_data() {
		$data = [];

		$data['site']         = $this->get_site_variables();
		$data['is_wc_active'] = class_exists( 'WooCommerce' );

		$home_page_data = $this->get_home_page_data();
		return array_merge( $data, $home_page_data );
	}

	/**
	 * Get home page data
	 *
	 * @return array<string, mixed>
	 */
	private function get_home_page_data() {
		$show_option   = Get::option( 'show_on_front' );
		$page_on_front = Get::option( 'page_on_front' );
		$home_page_id  = intval( $page_on_front );

		$featured_image = get_the_post_thumbnail_url( $home_page_id, 'full' );
		$data           = [
			'home_page_static'         => $show_option,
			'home_page_featured_image' => $featured_image ? $featured_image : false,
		];

		if ( $this->is_static_home_page( $show_option, $page_on_front ) ) {
			$data = array_merge( $data, $this->get_static_home_page_data( $home_page_id ) );
		}

		return $data;
	}

	/**
	 * Check if home page is static
	 *
	 * @param string $show_option Show on front option.
	 * @param mixed  $page_on_front Page on front ID.
	 * @return bool
	 */
	private function is_static_home_page( $show_option, $page_on_front ) {
		return 'page' === $show_option &&
			! empty( $page_on_front ) &&
			( is_string( $page_on_front ) || is_int( $page_on_front ) );
	}

	/**
	 * Get static home page data
	 *
	 * @param int $home_page_id Home page ID.
	 * @return array<string, mixed>
	 */
	private function get_static_home_page_data( $home_page_id ) {
		$page_url = get_edit_post_link( $home_page_id );
		return [
			'home_page_id'       => $home_page_id,
			'home_page_edit_url' => $this->sanitize_edit_url( $page_url ),
		];
	}

	/**
	 * Sanitize edit URL
	 *
	 * @param mixed $page_url Page URL.
	 * @return string
	 */
	private function sanitize_edit_url( $page_url ) {
		return '' !== $page_url && is_string( $page_url )
			? html_entity_decode( $page_url, ENT_QUOTES | ENT_HTML5, 'UTF-8' )
			: '';
	}
}