start_controls_section('section_content', [ 'label' => __('Table of Contents', 'thinkrank'), ]); $this->add_control('heading', [ 'label' => __('Title', 'thinkrank'), 'type' => \Elementor\Controls_Manager::TEXT, 'default' => __('Table of Contents', 'thinkrank'), 'label_block' => true, ]); $this->add_control('heading_tag', [ 'label' => __('Heading tag', 'thinkrank'), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => 'h2', 'options' => ['h2' => 'H2', 'h3' => 'H3', 'h4' => 'H4', 'p' => __('Paragraph', 'thinkrank')], ]); $this->add_control('max_level', [ 'label' => __('Include headings up to', 'thinkrank'), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => '3', 'options' => ['2' => 'H2', '3' => 'H3', '4' => 'H4'], ]); $this->add_control('list_style', [ 'label' => __('List style', 'thinkrank'), 'type' => \Elementor\Controls_Manager::SELECT, 'default' => 'disc', 'options' => [ 'disc' => __('Bulleted', 'thinkrank'), 'decimal' => __('Numbered', 'thinkrank'), 'none' => __('Plain', 'thinkrank'), ], ]); $this->end_controls_section(); } protected function render(): void { $settings = $this->get_settings_for_display(); $heading_tag = in_array($settings['heading_tag'] ?? 'h2', ['h2', 'h3', 'h4', 'p'], true) ? $settings['heading_tag'] : 'h2'; $max_level = in_array($settings['max_level'] ?? '3', ['2', '3', '4'], true) ? (int) $settings['max_level'] : 3; $list_style = in_array($settings['list_style'] ?? 'disc', ['disc', 'decimal', 'none'], true) ? $settings['list_style'] : 'disc'; $widget_id = 'thinkrank-toc-' . esc_attr($this->get_id()); echo '
'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped if (!empty($settings['heading'])) { printf( '<%1$s class="thinkrank-toc__heading">%2$s', esc_html($heading_tag), // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped esc_html($settings['heading']) ); } printf( '', esc_attr__('Table of contents', 'thinkrank'), esc_attr($list_style) ); echo '
'; $this->render_builder_script($widget_id, $max_level); } /** * Inline, dependency-free script that builds the list from the page's * headings (h2..maxLevel), assigning ids to headings that lack one. * * @param string $widget_id DOM id of this widget instance. * @param int $max_level Deepest heading level to include. * @return void */ private function render_builder_script(string $widget_id, int $max_level): void { $selector = implode(',', array_map( static fn($level) => 'h' . $level, range(2, max(2, $max_level)) )); ?>