PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.3
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.3
4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 All 201 releases
← All changes | views/templates/parts/code-snippet.php +141 -44 4.4.1 → 4.9.3 View file →
@@ -1,5 +1,10 @@
1 1 <?php
2 +// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- view template receives variables via extract(); prefixing is impractical.
3 +
4 +if ( ! defined( 'ABSPATH' ) ) {
5 + exit;
6 +}
2 7 /**
3 8 * Template part for BetterDocs Code Snippet
4 9 *
5 10 * @var string $code_content
@@ -5,9 +10,8 @@
5 10 * @var string $code_content
6 11 * @var string $language
7 12 * @var bool $show_language_label
8 13 * @var bool $show_copy_button
9 - * @var bool $show_copy_tooltip
10 14 * @var bool $show_header
11 15 * @var bool $show_line_numbers
12 16 * @var string $theme
13 17 * @var string $block_id (optional)
@@ -15,8 +19,10 @@
15 19 * @var string $file_name (optional)
16 20 * @var bool $show_traffic_lights (optional)
17 21 * @var bool $show_file_icon (optional)
18 22 * @var string $file_icon (optional)
23 + * @var array $code_variants (optional) [ { language, code, file_name } ] — when
24 + * more than one, the header renders a language dropdown.
19 25 */
20 26
21 27 if ( empty( $code_content ) ) {
22 28 return;
@@ -25,11 +31,14 @@
25 31 // Generate unique ID for this code snippet
26 32 $snippet_id = isset( $block_id ) ? $block_id : 'betterdocs-code-snippet-' . wp_rand( 1000, 9999 );
27 33
28 34 // Set defaults for optional parameters
35 +// Gates the language name on the multi-language switcher. The Elementor switch
36 +// and the block's showLanguageLabel attribute both fed this variable and nothing
37 +// ever read it, so the control was a no-op in both editors. Default stays true,
38 +// so existing content renders exactly as before.
29 39 $show_language_label = isset( $show_language_label ) ? $show_language_label : true;
30 40 $show_copy_button = isset( $show_copy_button ) ? $show_copy_button : true;
31 -$show_copy_tooltip = isset( $show_copy_tooltip ) ? $show_copy_tooltip : false;
32 41 $show_header = isset( $show_header ) ? $show_header : true;
33 42 $file_name = isset( $file_name ) ? $file_name : '';
34 43 $show_traffic_lights = isset( $show_traffic_lights ) ? $show_traffic_lights : true;
35 44 $show_file_icon = isset( $show_file_icon ) ? $show_file_icon : true;
@@ -43,23 +52,80 @@
43 52
44 53 // Import Helper class for file icon functionality
45 54 use WPDeveloper\BetterDocs\Utils\Helper;
46 55
47 -// Generate line numbers if needed
48 -$line_numbers = [];
49 -if ( $show_line_numbers ) {
50 - $lines = explode( "\n", $code_content );
51 - $line_numbers = range( 1, count( $lines ) );
56 +// Build the language list. Callers that don't pass code_variants (Elementor /
57 +// shortcode) fall back to the single primary language/code — identical to the
58 +// previous behaviour.
59 +$variants = ( isset( $code_variants ) && is_array( $code_variants ) && ! empty( $code_variants ) )
60 + ? $code_variants
61 + : [
62 + [
63 + 'language' => $language,
64 + 'code' => $code_content,
65 + 'file_name' => $file_name
66 + ]
67 + ];
68 +
69 +// Normalize every entry up front. `code_variants` arrives from block attributes
70 +// (and from Pro's API-docs generator), so a caller can legitimately hand over an
71 +// entry missing `language` or `code` — reading them directly emitted PHP 8
72 +// warnings mid-render. The tab template already guards this way.
73 +$variants = array_values(
74 + array_filter(
75 + array_map(
76 + function ( $variant ) {
77 + if ( ! is_array( $variant ) ) {
78 + return null;
79 + }
80 +
81 + return [
82 + 'language' => isset( $variant['language'] ) ? (string) $variant['language'] : '',
83 + 'code' => isset( $variant['code'] ) ? (string) $variant['code'] : '',
84 + 'file_name' => isset( $variant['file_name'] ) ? (string) $variant['file_name'] : ''
85 + ];
86 + },
87 + $variants
88 + )
89 + )
90 +);
91 +
92 +// Everything below indexes $variants[0]; keep the single-entry fallback so an
93 +// empty or fully-invalid list still renders rather than fatalling.
94 +if ( empty( $variants ) ) {
95 + $variants = [
96 + [
97 + 'language' => $language,
98 + 'code' => (string) $code_content,
99 + 'file_name' => $file_name
100 + ]
101 + ];
52 102 }
53 103
104 +$is_multi = count( $variants ) > 1;
105 +$active = $variants[0];
106 +$active_lang = sanitize_text_field( $active['language'] );
107 +
108 +// Dropdown/tab label for an entry: a custom filename overrides (so the API-docs
109 +// cURL sample reads "cURL", not "Bash"), otherwise the language's display name.
110 +// The block default filename ("filename.js") never wins.
111 +$lang_label = function ( $variant ) {
112 + $file = isset( $variant['file_name'] ) ? (string) $variant['file_name'] : '';
113 + if ( '' !== $file && 'filename.js' !== $file ) {
114 + return $file;
115 + }
116 + return Helper::get_language_label( sanitize_text_field( isset( $variant['language'] ) ? $variant['language'] : '' ) );
117 +};
118 +
54 119 // Enqueue necessary assets
55 120 wp_enqueue_script( 'betterdocs-code-snippet' );
56 121 wp_enqueue_style( 'betterdocs-code-snippet' );
57 122 ?>
58 123
59 -<div class="betterdocs-code-snippet-wrapper theme-<?php echo esc_attr( $theme ); ?> <?php echo esc_attr( $snippet_id ); ?>"
124 +<div class="betterdocs-code-snippet-wrapper theme-<?php echo esc_attr( $theme ); ?> <?php echo esc_attr( $snippet_id ); ?><?php echo $is_multi ? ' is-multi-lang' : ''; ?>"
60 125 id="<?php echo esc_attr( $snippet_id ); ?>"
61 - data-language="<?php echo esc_attr( $language ); ?>"
126 + data-language="<?php echo esc_attr( $active_lang ); ?>"
127 + <?php echo $is_multi ? 'data-multi-lang="true"' : ''; ?>
62 128 data-copy-button="<?php echo $show_copy_button ? 'true' : 'false'; ?>">
63 129
64 130 <?php if ( $show_header ) : ?>
65 131 <div class="betterdocs-code-snippet-header betterdocs-file-preview-header">
@@ -71,57 +137,88 @@
71 137 <span class="traffic-light traffic-light-green"></span>
72 138 </div>
73 139 <?php endif; ?>
74 140
75 - <div class="betterdocs-file-info">
76 - <?php if ( $show_file_icon ) : ?>
77 - <div class="betterdocs-file-icon">
78 - <?php if ( ! empty( $file_icon ) ) : ?>
79 - <img src="<?php echo esc_url( $file_icon ); ?>" alt="<?php esc_attr_e( 'File icon', 'betterdocs' ); ?>" />
80 - <?php else : ?>
81 - <span class="betterdocs-file-icon-emoji"><?php echo esc_html( Helper::get_file_icon_by_language( $language ) ); ?></span>
82 - <?php endif; ?>
83 - </div>
84 - <?php endif; ?>
141 + <?php if ( ! $is_multi ) : ?>
142 + <div class="betterdocs-file-info">
143 + <?php if ( $show_file_icon ) : ?>
144 + <div class="betterdocs-file-icon">
145 + <?php if ( ! empty( $file_icon ) ) : ?>
146 + <img src="<?php echo esc_url( $file_icon ); ?>" alt="<?php esc_attr_e( 'File icon', 'betterdocs' ); ?>" />
147 + <?php else : ?>
148 + <span class="betterdocs-file-icon-emoji"><?php echo esc_html( Helper::get_file_icon_by_language( $active_lang ) ); ?></span>
149 + <?php endif; ?>
150 + </div>
151 + <?php endif; ?>
85 152
86 - <?php if ( ! empty( $file_name ) ) : ?>
87 - <div class="betterdocs-file-name">
88 - <span class="file-name-text"><?php echo esc_html( $file_name ); ?></span>
89 - </div>
90 - <?php endif; ?>
91 - </div>
153 + <?php if ( ! empty( $file_name ) ) : ?>
154 + <div class="betterdocs-file-name">
155 + <span class="file-name-text"><?php echo esc_html( $file_name ); ?></span>
156 + </div>
157 + <?php endif; ?>
158 + </div>
159 + <?php endif; ?>
92 160 </div>
93 161
94 162 <div class="betterdocs-file-preview-right">
95 - <?php if ( $show_copy_button ) : ?>
96 - <div class="betterdocs-code-snippet-copy-container">
97 - <button class="betterdocs-code-snippet-copy-button"
98 - type="button"
99 - data-clipboard-target="#<?php echo esc_attr( $snippet_id ); ?> .betterdocs-code-snippet-code code"
100 - aria-label="<?php esc_attr_e( 'Copy code to clipboard', 'betterdocs' ); ?>">
101 - <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
102 - <path d="M16 1H4C2.9 1 2 1.9 2 3V17H4V3H16V1ZM19 5H8C6.9 5 6 5.9 6 7V21C6 22.1 6.9 23 8 23H19C20.1 23 21 22.1 21 21V7C21 5.9 20.1 5 19 5ZM19 21H8V7H19V21Z" fill="currentColor"/>
163 + <?php if ( $is_multi ) : ?>
164 + <div class="betterdocs-code-lang-dropdown">
165 + <button type="button" class="betterdocs-code-lang-toggle" aria-haspopup="listbox" aria-expanded="false">
166 + <span class="betterdocs-code-lang-current">
167 + <?php if ( $show_file_icon ) : ?>
168 + <span class="betterdocs-file-icon-emoji"><?php echo esc_html( Helper::get_file_icon_by_language( $active_lang ) ); ?></span>
169 + <?php endif; ?>
170 + <?php if ( $show_language_label ) : ?>
171 + <span class="betterdocs-code-lang-label"><?php echo esc_html( $lang_label( $active ) ); ?></span>
172 + <?php endif; ?>
173 + </span>
174 + <svg class="betterdocs-code-lang-caret" width="12" height="12" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
175 + <path d="M6 9l6 6 6-6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
103 176 </svg>
104 177 </button>
105 - <?php if ( $show_copy_tooltip ) : ?>
106 - <div class="betterdocs-code-snippet-tooltip"><?php esc_html_e( 'Copy to clipboard', 'betterdocs' ); ?></div>
107 - <?php endif; ?>
178 + <ul class="betterdocs-code-lang-menu" role="listbox">
179 + <?php foreach ( $variants as $i => $variant ) : ?>
180 + <?php $v_lang = sanitize_text_field( $variant['language'] ); ?>
181 + <li class="betterdocs-code-lang-option<?php echo 0 === $i ? ' is-active' : ''; ?>"
182 + role="option"
183 + data-lang-index="<?php echo esc_attr( $i ); ?>">
184 + <?php if ( $show_file_icon ) : ?>
185 + <span class="betterdocs-file-icon-emoji"><?php echo esc_html( Helper::get_file_icon_by_language( $v_lang ) ); ?></span>
186 + <?php endif; ?>
187 + <span class="betterdocs-code-lang-label"><?php echo esc_html( $lang_label( $variant ) ); ?></span>
188 + </li>
189 + <?php endforeach; ?>
190 + </ul>
108 191 </div>
109 192 <?php endif; ?>
193 +
194 + <?php if ( $show_copy_button ) : ?>
195 + <?php Helper::code_snippet_copy_button(); ?>
196 + <?php endif; ?>
110 197 </div>
111 198 </div>
112 199 <?php endif; ?>
113 200
114 201 <div class="betterdocs-code-snippet-content">
115 - <?php if ( $show_line_numbers ) : ?>
116 - <div class="betterdocs-code-snippet-line-numbers" aria-hidden="true">
117 - <?php foreach ( $line_numbers as $line_num ) : ?>
118 - <div class="line-number"><?php echo esc_html( $line_num ); ?></div>
119 - <?php endforeach; ?>
202 + <?php foreach ( $variants as $i => $variant ) : ?>
203 + <?php
204 + $v_lang = sanitize_text_field( $variant['language'] );
205 + $v_code = (string) $variant['code'];
206 + ?>
207 + <div class="betterdocs-code-snippet-panel<?php echo 0 === $i ? ' is-active' : ''; ?>"
208 + data-lang-index="<?php echo esc_attr( $i ); ?>"
209 + <?php echo 0 === $i ? '' : 'hidden'; ?>>
210 + <?php if ( $show_line_numbers ) : ?>
211 + <div class="betterdocs-code-snippet-line-numbers" aria-hidden="true">
212 + <?php foreach ( range( 1, max( 1, substr_count( $v_code, "\n" ) + 1 ) ) as $line_num ) : ?>
213 + <div class="line-number"><?php echo esc_html( $line_num ); ?></div>
214 + <?php endforeach; ?>
215 + </div>
216 + <?php endif; ?>
217 +
218 + <pre class="betterdocs-code-snippet-code language-<?php echo esc_attr( $v_lang ); ?>"><code><?php echo esc_html( $v_code ); ?></code></pre>
120 219 </div>
121 - <?php endif; ?>
122 -
123 - <pre class="betterdocs-code-snippet-code language-<?php echo esc_attr( $language ); ?>"><code><?php echo esc_html( $code_content ); ?></code></pre>
220 + <?php endforeach; ?>
124 221 </div>
125 222 </div>
126 223
127 224 <?php