settings-layout.php (10622B)
1 <?php 2 namespace Elementor\Core\Kits\Documents\Tabs; 3 4 use Elementor\Core\Breakpoints\Breakpoint; 5 use Elementor\Core\Breakpoints\Manager as Breakpoints_Manager; 6 use Elementor\Plugin; 7 use Elementor\Controls_Manager; 8 use Elementor\Core\Base\Document; 9 use Elementor\Modules\PageTemplates\Module as PageTemplatesModule; 10 11 if ( ! defined( 'ABSPATH' ) ) { 12 exit; // Exit if accessed directly 13 } 14 15 class Settings_Layout extends Tab_Base { 16 17 const ACTIVE_BREAKPOINTS_CONTROL_ID = 'active_breakpoints'; 18 19 public function get_id() { 20 return 'settings-layout'; 21 } 22 23 public function get_title() { 24 return esc_html__( 'Layout', 'elementor' ); 25 } 26 27 public function get_group() { 28 return 'settings'; 29 } 30 31 public function get_icon() { 32 return 'eicon-layout-settings'; 33 } 34 35 public function get_help_url() { 36 return 'https://go.elementor.com/global-layout'; 37 } 38 39 protected function register_tab_controls() { 40 $breakpoints_default_config = Breakpoints_Manager::get_default_config(); 41 $breakpoint_key_mobile = Breakpoints_Manager::BREAKPOINT_KEY_MOBILE; 42 $breakpoint_key_tablet = Breakpoints_Manager::BREAKPOINT_KEY_TABLET; 43 44 $this->start_controls_section( 45 'section_' . $this->get_id(), 46 [ 47 'label' => esc_html__( 'Layout Settings', 'elementor' ), 48 'tab' => $this->get_id(), 49 ] 50 ); 51 52 $this->add_responsive_control( 53 'container_width', 54 [ 55 'label' => esc_html__( 'Content Width', 'elementor' ) . ' (px)', 56 'type' => Controls_Manager::SLIDER, 57 'default' => [ 58 'size' => '1140', 59 ], 60 'tablet_default' => [ 61 'size' => $breakpoints_default_config[ $breakpoint_key_tablet ]['default_value'], 62 ], 63 'mobile_default' => [ 64 'size' => $breakpoints_default_config[ $breakpoint_key_mobile ]['default_value'], 65 ], 66 'range' => [ 67 'px' => [ 68 'min' => 300, 69 'max' => 1500, 70 'step' => 10, 71 ], 72 ], 73 'description' => esc_html__( 'Sets the default width of the content area (Default: 1140)', 'elementor' ), 74 'selectors' => [ 75 '.elementor-section.elementor-section-boxed > .elementor-container' => 'max-width: {{SIZE}}{{UNIT}}', 76 ], 77 ] 78 ); 79 80 $this->add_control( 81 'space_between_widgets', 82 [ 83 'label' => esc_html__( 'Widgets Space', 'elementor' ) . ' (px)', 84 'type' => Controls_Manager::SLIDER, 85 'default' => [ 86 'size' => 20, 87 ], 88 'range' => [ 89 'px' => [ 90 'min' => 0, 91 'max' => 40, 92 ], 93 ], 94 'placeholder' => '20', 95 'description' => esc_html__( 'Sets the default space between widgets (Default: 20)', 'elementor' ), 96 'selectors' => [ 97 '.elementor-widget:not(:last-child)' => 'margin-bottom: {{SIZE}}{{UNIT}}', 98 ], 99 ] 100 ); 101 102 $this->add_control( 103 'page_title_selector', 104 [ 105 'label' => esc_html__( 'Page Title Selector', 'elementor' ), 106 'type' => Controls_Manager::TEXT, 107 'default' => 'h1.entry-title', 108 'placeholder' => 'h1.entry-title', 109 'description' => esc_html__( 'Elementor lets you hide the page title. This works for themes that have "h1.entry-title" selector. If your theme\'s selector is different, please enter it above.', 'elementor' ), 110 'label_block' => true, 111 'selectors' => [ 112 // Hack to convert the value into a CSS selector. 113 '' => '}{{VALUE}}{display: var(--page-title-display)', 114 ], 115 ] 116 ); 117 118 $this->add_control( 119 'stretched_section_container', 120 [ 121 'label' => esc_html__( 'Stretched Section Fit To', 'elementor' ), 122 'type' => Controls_Manager::TEXT, 123 'placeholder' => 'body', 124 'description' => esc_html__( 'Enter parent element selector to which stretched sections will fit to (e.g. #primary / .wrapper / main etc). Leave blank to fit to page width.', 'elementor' ), 125 'label_block' => true, 126 'frontend_available' => true, 127 ] 128 ); 129 130 /** 131 * @var PageTemplatesModule $page_templates_module 132 */ 133 $page_templates_module = Plugin::$instance->modules_manager->get_modules( 'page-templates' ); 134 $page_templates = $page_templates_module->add_page_templates( [], null, null ); 135 136 // Removes the Theme option from the templates because 'default' is already handled. 137 unset( $page_templates[ PageTemplatesModule::TEMPLATE_THEME ] ); 138 139 $page_template_control_options = [ 140 'label' => esc_html__( 'Default Page Layout', 'elementor' ), 141 'options' => [ 142 // This is here because the "Theme" string is different than the default option's string. 143 'default' => esc_html__( 'Theme', 'elementor' ), 144 ] + $page_templates, 145 ]; 146 147 $page_templates_module->add_template_controls( $this->parent, 'default_page_template', $page_template_control_options ); 148 149 $this->end_controls_section(); 150 151 $this->start_controls_section( 152 'section_breakpoints', 153 [ 154 'label' => esc_html__( 'Breakpoints', 'elementor' ), 155 'tab' => $this->get_id(), 156 ] 157 ); 158 159 $prefix = Breakpoints_Manager::BREAKPOINT_SETTING_PREFIX; 160 $options = []; 161 162 foreach ( $breakpoints_default_config as $breakpoint_key => $breakpoint ) { 163 $options[ $prefix . $breakpoint_key ] = $breakpoint['label']; 164 } 165 166 if ( Plugin::$instance->experiments->is_feature_active( 'additional_custom_breakpoints' ) ) { 167 $active_breakpoints_control_type = Controls_Manager::SELECT2; 168 } else { 169 $active_breakpoints_control_type = Controls_Manager::HIDDEN; 170 } 171 172 $this->add_control( 173 self::ACTIVE_BREAKPOINTS_CONTROL_ID, 174 [ 175 'label' => esc_html__( 'Active Breakpoints', 'elementor' ), 176 'type' => $active_breakpoints_control_type, 177 'description' => esc_html__( 'Mobile and Tablet options cannot be deleted.', 'elementor' ), 178 'options' => $options, 179 'default' => [ 180 $prefix . $breakpoint_key_mobile, 181 $prefix . $breakpoint_key_tablet, 182 ], 183 'select2options' => [ 184 'allowClear' => false, 185 ], 186 'lockedOptions' => [ 187 $prefix . $breakpoint_key_mobile, 188 $prefix . $breakpoint_key_tablet, 189 ], 190 'label_block' => true, 191 'render_type' => 'none', 192 'frontend_available' => true, 193 'multiple' => true, 194 ] 195 ); 196 197 $this->add_breakpoints_controls(); 198 199 // Include the old mobile and tablet breakpoint controls as hidden for backwards compatibility. 200 $this->add_control( 'viewport_md', [ 'type' => Controls_Manager::HIDDEN ] ); 201 $this->add_control( 'viewport_lg', [ 'type' => Controls_Manager::HIDDEN ] ); 202 203 $this->end_controls_section(); 204 } 205 206 /** 207 * Before Save 208 * 209 * Runs Before the Kit document is saved. 210 * 211 * For backwards compatibility, when the mobile and tablet breakpoints are updated, we also update the 212 * old breakpoint settings ('viewport_md', 'viewport_lg' ) with the saved values + 1px. The reason 1px 213 * is added is because the old breakpoints system was min-width based, and the new system introduced in 214 * Elementor v3.2.0 is max-width based. 215 * 216 * @since 3.2.0 217 * 218 * @param array $data 219 * @return array $data 220 */ 221 public function before_save( array $data ) { 222 // When creating a default kit, $data['settings'] is empty and should remain empty, so settings. 223 if ( empty( $data['settings'] ) ) { 224 return $data; 225 } 226 227 $prefix = Breakpoints_Manager::BREAKPOINT_SETTING_PREFIX; 228 $mobile_breakpoint_key = $prefix . Breakpoints_Manager::BREAKPOINT_KEY_MOBILE; 229 $tablet_breakpoint_key = $prefix . Breakpoints_Manager::BREAKPOINT_KEY_TABLET; 230 231 $default_breakpoint_config = Breakpoints_Manager::get_default_config(); 232 233 // Update the old mobile breakpoint. If the setting is empty, use the default value. 234 $data['settings'][ $prefix . 'md' ] = empty( $data['settings'][ $mobile_breakpoint_key ] ) 235 ? $default_breakpoint_config[ Breakpoints_Manager::BREAKPOINT_KEY_MOBILE ]['default_value'] + 1 236 : $data['settings'][ $mobile_breakpoint_key ] + 1; 237 238 // Update the old tablet breakpoint. If the setting is empty, use the default value. 239 $data['settings'][ $prefix . 'lg' ] = empty( $data['settings'][ $tablet_breakpoint_key ] ) 240 ? $default_breakpoint_config[ Breakpoints_Manager::BREAKPOINT_KEY_TABLET ]['default_value'] + 1 241 : $data['settings'][ $tablet_breakpoint_key ] + 1; 242 243 return $data; 244 } 245 246 public function on_save( $data ) { 247 if ( ! isset( $data['settings'] ) || ( isset( $data['settings']['post_status'] ) && Document::STATUS_PUBLISH !== $data['settings']['post_status'] ) ) { 248 return; 249 } 250 251 $should_compile_css = false; 252 253 $breakpoints_default_config = Breakpoints_Manager::get_default_config(); 254 255 foreach ( $breakpoints_default_config as $breakpoint_key => $default_config ) { 256 $breakpoint_setting_key = Breakpoints_Manager::BREAKPOINT_SETTING_PREFIX . $breakpoint_key; 257 258 if ( isset( $data['settings'][ $breakpoint_setting_key ] ) ) { 259 $should_compile_css = true; 260 } 261 } 262 263 if ( $should_compile_css ) { 264 Breakpoints_Manager::compile_stylesheet_templates(); 265 } 266 } 267 268 private function add_breakpoints_controls() { 269 $default_breakpoints_config = Breakpoints_Manager::get_default_config(); 270 $prefix = Breakpoints_Manager::BREAKPOINT_SETTING_PREFIX; 271 272 // If the ACB experiment is inactive, only add the mobile and tablet controls. 273 if ( ! Plugin::$instance->experiments->is_feature_active( 'additional_custom_breakpoints' ) ) { 274 $default_breakpoints_config = array_intersect_key( $default_breakpoints_config, array_flip( [ Breakpoints_Manager::BREAKPOINT_KEY_MOBILE, Breakpoints_Manager::BREAKPOINT_KEY_TABLET ] ) ); 275 } 276 277 // Add a control for each of the **default** breakpoints. 278 foreach ( $default_breakpoints_config as $breakpoint_key => $default_breakpoint_config ) { 279 $this->add_control( 280 'breakpoint_' . $breakpoint_key . '_heading', 281 [ 282 'label' => $default_breakpoint_config['label'], 283 'type' => Controls_Manager::HEADING, 284 'conditions' => [ 285 'terms' => [ 286 [ 287 'name' => 'active_breakpoints', 288 'operator' => 'contains', 289 'value' => $prefix . $breakpoint_key, 290 ], 291 ], 292 ], 293 ] 294 ); 295 296 $control_config = [ 297 'label' => esc_html__( 'Breakpoint', 'elementor' ) . ' (px)', 298 'type' => Controls_Manager::NUMBER, 299 'placeholder' => $default_breakpoint_config['default_value'], 300 'frontend_available' => true, 301 'validators' => [ 302 'Breakpoint' => [ 303 'breakpointName' => $breakpoint_key, 304 ], 305 ], 306 'conditions' => [ 307 'terms' => [ 308 [ 309 'name' => 'active_breakpoints', 310 'operator' => 'contains', 311 'value' => $prefix . $breakpoint_key, 312 ], 313 ], 314 ], 315 ]; 316 317 if ( Breakpoints_Manager::BREAKPOINT_KEY_WIDESCREEN === $breakpoint_key ) { 318 $control_config['description'] = esc_html__( 319 'Widescreen breakpoint settings will apply from the selected value and up.', 320 'elementor' 321 ); 322 } 323 324 // Add the breakpoint Control itself. 325 $this->add_control( $prefix . $breakpoint_key, $control_config ); 326 } 327 } 328 }