render-mode-manager.php (3663B)
1 <?php 2 namespace Elementor\Core\Frontend; 3 4 use Elementor\Core\Frontend\RenderModes\Render_Mode_Base; 5 use Elementor\Core\Frontend\RenderModes\Render_Mode_Normal; 6 7 if ( ! defined( 'ABSPATH' ) ) { 8 exit; // Exit if accessed directly. 9 } 10 11 class Render_Mode_Manager { 12 const QUERY_STRING_PARAM_NAME = 'render_mode'; 13 const QUERY_STRING_POST_ID = 'post_id'; 14 const QUERY_STRING_NONCE_PARAM_NAME = 'render_mode_nonce'; 15 const NONCE_ACTION_PATTERN = 'render_mode_{post_id}'; 16 17 /** 18 * @var Render_Mode_Base 19 */ 20 private $current; 21 22 /** 23 * @var Render_Mode_Base[] 24 */ 25 private $render_modes = []; 26 27 /** 28 * @param $post_id 29 * @param $render_mode_name 30 * 31 * @return string 32 */ 33 public static function get_base_url( $post_id, $render_mode_name ) { 34 return add_query_arg( [ 35 self::QUERY_STRING_POST_ID => $post_id, 36 self::QUERY_STRING_PARAM_NAME => $render_mode_name, 37 self::QUERY_STRING_NONCE_PARAM_NAME => wp_create_nonce( self::get_nonce_action( $post_id ) ), 38 'ver' => time(), 39 ], get_permalink( $post_id ) ); 40 } 41 42 /** 43 * @param $post_id 44 * 45 * @return string 46 */ 47 public static function get_nonce_action( $post_id ) { 48 return str_replace( '{post_id}', $post_id, self::NONCE_ACTION_PATTERN ); 49 } 50 51 /** 52 * Register a new render mode into the render mode manager. 53 * 54 * @param $class_name 55 * 56 * @return $this 57 * @throws \Exception 58 */ 59 public function register_render_mode( $class_name ) { 60 if ( ! is_subclass_of( $class_name, Render_Mode_Base::class ) ) { 61 throw new \Exception( "'{$class_name}' must extends 'Render_Mode_Base'" ); 62 } 63 64 $this->render_modes[ $class_name::get_name() ] = $class_name; 65 66 return $this; 67 } 68 69 /** 70 * Get the current render mode. 71 * 72 * @return Render_Mode_Base 73 */ 74 public function get_current() { 75 return $this->current; 76 } 77 78 /** 79 * @param Render_Mode_Base $render_mode 80 * 81 * @return $this 82 */ 83 private function set_current( Render_Mode_Base $render_mode ) { 84 $this->current = $render_mode; 85 86 return $this; 87 } 88 89 /** 90 * Set render mode. 91 * 92 * @return $this 93 */ 94 private function choose_render_mode() { 95 $post_id = null; 96 $key = null; 97 $nonce = null; 98 99 if ( isset( $_GET[ self::QUERY_STRING_POST_ID ] ) ) { 100 $post_id = $_GET[ self::QUERY_STRING_POST_ID ]; // phpcs:ignore -- Nonce will be checked next line. 101 } 102 103 if ( isset( $_GET[ self::QUERY_STRING_NONCE_PARAM_NAME ] ) ) { 104 $nonce = $_GET[ self::QUERY_STRING_NONCE_PARAM_NAME ]; // phpcs:ignore -- Nonce will be checked next line. 105 } 106 107 if ( isset( $_GET[ self::QUERY_STRING_PARAM_NAME ] ) ) { 108 $key = $_GET[ self::QUERY_STRING_PARAM_NAME ]; // phpcs:ignore -- Nonce will be checked next line. 109 } 110 111 if ( 112 $post_id && 113 $nonce && 114 wp_verify_nonce( $nonce, self::get_nonce_action( $post_id ) ) && 115 $key && 116 array_key_exists( $key, $this->render_modes ) 117 ) { 118 $this->set_current( new $this->render_modes[ $key ]( $post_id ) ); 119 } else { 120 $this->set_current( new Render_Mode_Normal( $post_id ) ); 121 } 122 123 return $this; 124 } 125 126 /** 127 * Add actions base on the current render. 128 * 129 * @throws \Requests_Exception_HTTP_403 130 */ 131 private function add_current_actions() { 132 if ( ! $this->current->get_permissions_callback() ) { 133 throw new \Requests_Exception_HTTP_403(); 134 } 135 136 // Run when 'template-redirect' actually because the the class is instantiate when 'template-redirect' run. 137 $this->current->prepare_render(); 138 } 139 140 /** 141 * Render_Mode_Manager constructor. 142 * 143 * @throws \Exception 144 */ 145 public function __construct() { 146 $this->register_render_mode( Render_Mode_Normal::class ); 147 148 do_action( 'elementor/frontend/render_mode/register', $this ); 149 150 $this->choose_render_mode(); 151 $this->add_current_actions(); 152 } 153 }