PluginProbe
Code Snippets / trunk
Code Snippets vtrunk
4.0.0-beta.2 3.10.2 3.10.1 3.10.0 3.10.0-beta.2 3.10.0-beta.1 4.0.0-beta.1 3.9.6 trunk 2.10.0 2.10.1 2.12.0 2.12.1 2.13.0 2.13.1 2.13.2 2.13.3 2.14.0 2.14.1 2.14.2 2.14.3 2.14.4 2.14.5 2.14.6 3.0.0 All 65 releases
code-snippets / php / Admin / Menus / Manage / Manage_Menu_Screen_Options.php

Manage_Menu_Screen_Options.php in Code Snippets trunk, at php/Admin/Menus/Manage/Manage_Menu_Screen_Options.php

273 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Code_Snippets\Admin\Menus\Manage;
4
5 use WP_Screen;
6 use function Code_Snippets\code_snippets;
7
8 /**
9 * Provides Screen Options for the manage snippets table.
10 */
11 class Manage_Menu_Screen_Options {
12
13 /**
14 * Register hooks this class.
15 */
16 public function __construct() {
17 add_action( 'wp_loaded', [ $this, 'save_truncation_preference' ] );
18 add_filter( 'set-screen-option', [ $this, 'save_per_page_option' ], 10, 3 );
19 }
20
21 /**
22 * Load the screen options for the current page.
23 *
24 * @return void
25 */
26 public function load() {
27 $screen = get_current_screen();
28
29 if ( $this->is_upsell_view() ) {
30 // The upsell page has no table or settings of its own, so the whole
31 // screen-meta-links block (Screen Options + Help tabs) is unhooked.
32 add_filter( 'screen_options_show_screen', '__return_false' );
33 return;
34 }
35
36 if ( $screen && ! $this->is_cloud_community_view() ) {
37 add_filter( "manage_{$screen->id}_columns", [ $this, 'get_columns' ] );
38 add_filter( 'default_hidden_columns', [ $this, 'get_default_hidden_columns' ], 10, 2 );
39 add_filter( 'screen_settings', [ $this, 'render' ] );
40 }
41
42 add_screen_option(
43 'per_page',
44 [
45 'label' => __( 'Snippets per page', 'code-snippets' ),
46 'default' => Manage_Menu::get_default_snippets_per_page(),
47 'option' => 'snippets_per_page',
48 ]
49 );
50 }
51
52 /**
53 * Add the snippets table columns.
54 *
55 * @param string[] $columns Existing columns.
56 *
57 * @return string[]
58 */
59 public function get_columns( array $columns = [] ): array {
60 return array_merge(
61 $columns,
62 [
63 '_title' => __( 'Columns', 'code-snippets' ),
64 'activate' => __( 'Active', 'code-snippets' ),
65 'id' => __( 'ID', 'code-snippets' ),
66 'name' => __( 'Name', 'code-snippets' ),
67 'type' => __( 'Type', 'code-snippets' ),
68 'desc' => __( 'Description', 'code-snippets' ),
69 'tags' => __( 'Tags', 'code-snippets' ),
70 'date' => __( 'Modified', 'code-snippets' ),
71 'priority' => __( 'Priority', 'code-snippets' ),
72 'author' => __( 'Author', 'code-snippets' ),
73 'insights' => __( 'Insights', 'code-snippets' ),
74 ]
75 );
76 }
77
78 /**
79 * Hide the optional ID column until a user enables it.
80 *
81 * @param string[] $hidden_columns Column identifiers hidden by default.
82 * @param WP_Screen $screen Current admin screen.
83 *
84 * @return string[]
85 */
86 public function get_default_hidden_columns( array $hidden_columns, WP_Screen $screen ): array {
87 return get_current_screen() === $screen
88 ? array_merge( $hidden_columns, [ 'id' ] )
89 : $hidden_columns;
90 }
91
92 /**
93 * Get the columns hidden for the current user.
94 *
95 * @return string[]
96 */
97 public function get_hidden_columns(): array {
98 $screen = get_current_screen();
99
100 return $screen ? get_hidden_columns( $screen ) : [];
101 }
102
103 /**
104 * Whether long row values should be truncated.
105 *
106 * @return bool
107 */
108 public function should_truncate_rows(): bool {
109 $setting = get_user_option( 'snippets_table_truncate_row_values' );
110 return false === $setting || $setting;
111 }
112
113 /**
114 * Read the current manage subpage.
115 *
116 * @return string
117 */
118 public function get_current_subpage(): string {
119 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only routing parameter.
120 return isset( $_REQUEST['subpage'] ) ? sanitize_key( wp_unslash( $_REQUEST['subpage'] ) ) : '';
121 }
122
123 /**
124 * Whether the current request renders the snippets table.
125 *
126 * @return bool
127 */
128 public function is_manage_table_view(): bool {
129 return in_array( $this->get_current_subpage(), [ '', 'snippets' ], true );
130 }
131
132 /**
133 * Whether the current request renders the AI Agent.
134 *
135 * The subpage has no screen options or help tabs of its own, so it remains
136 * an upsell view for {@see load()}; this detection exists only so its
137 * runtime data can be localized on the subpage that uses it.
138 *
139 * @return bool
140 */
141 public function is_ai_agent_view(): bool {
142 return 'ai-agent' === $this->get_current_subpage();
143 }
144
145 /**
146 * Whether the current request renders Community Cloud.
147 *
148 * The "Bundles" tab within Community Cloud is a Pro-only upsell rather than
149 * genuine Community Cloud content, so it is excluded here and picked up by
150 * {@see is_upsell_view()} instead.
151 *
152 * @return bool
153 */
154 public function is_cloud_community_view(): bool {
155 if ( 'cloud-community' !== $this->get_current_subpage() ) {
156 return false;
157 }
158
159 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only routing parameter.
160 $tab = isset( $_REQUEST['tab'] ) ? sanitize_key( wp_unslash( $_REQUEST['tab'] ) ) : '';
161
162 return 'bundles' !== $tab;
163 }
164
165 /**
166 * Whether the current request renders an upsell page.
167 *
168 * Every genuine Core subpage has its own positive `is_*_view()` detection
169 * above; a subpage that matches none of them (Blueprints, Cloud Library,
170 * and any future Pro-only addition) has no real content of its own and
171 * falls through to the upsell placeholder.
172 *
173 * @return bool
174 */
175 public function is_upsell_view(): bool {
176 return ! $this->is_manage_table_view() && ! $this->is_cloud_community_view();
177 }
178
179 /**
180 * Render the manage table controls.
181 *
182 * Anything may filter `screen_settings` before this runs, and a callback
183 * that forgets to return its value hands the next one null. Declaring the
184 * parameter as a string turned that into a fatal error, and because it is
185 * raised while the screen meta is being rendered, the page dies after the
186 * admin chrome but before any content: the snippets screen appears blank
187 * while the rest of the admin looks fine.
188 *
189 * @param mixed $screen_settings Existing screen settings HTML, from an
190 * unknown number of earlier callbacks.
191 *
192 * @return string
193 */
194 public function render( $screen_settings ): string {
195 $screen_settings = is_string( $screen_settings ) ? $screen_settings : '';
196
197 if ( $this->is_cloud_community_view() ) {
198 return $screen_settings;
199 }
200
201 ob_start();
202 ?>
203 <fieldset class="metabox-prefs table-options-prefs">
204 <legend><?php esc_html_e( 'Table Options', 'code-snippets' ); ?></legend>
205 <div class="metabox-prefs-container">
206 <label for="snippets-table-truncate-row-values">
207 <input
208 id="snippets-table-truncate-row-values"
209 name="snippets_table_truncate_row_values"
210 type="checkbox"
211 value="1"
212 <?php checked( $this->should_truncate_rows() ); ?>
213 />
214 <?php esc_html_e( 'Truncate long snippet names and descriptions', 'code-snippets' ); ?>
215 </label>
216 </div>
217 </fieldset>
218 <?php
219
220 return $screen_settings . ob_get_clean();
221 }
222
223 /**
224 * Persist the row truncation preference.
225 *
226 * @return void
227 */
228 public function save_truncation_preference(): void {
229 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified below before persisting the option.
230 if ( empty( $_POST['wp_screen_options'] ) || ! is_array( $_POST['wp_screen_options'] ) ) {
231 return;
232 }
233
234 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Sanitized and matched to a known admin page.
235 $page = isset( $_REQUEST['page'] ) ? sanitize_key( wp_unslash( $_REQUEST['page'] ) ) : '';
236
237 if ( code_snippets()->get_menu_slug() !== $page || ! current_user_can( code_snippets()->get_cap() ) ) {
238 return;
239 }
240
241 if ( $this->is_cloud_community_view() ) {
242 return;
243 }
244
245 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified here before persisting the option.
246 $nonce = isset( $_POST['screenoptionnonce'] ) ? sanitize_text_field( wp_unslash( $_POST['screenoptionnonce'] ) ) : '';
247
248 if ( ! wp_verify_nonce( $nonce, 'screen-options-nonce' ) ) {
249 return;
250 }
251
252 update_user_option(
253 get_current_user_id(),
254 'snippets_table_truncate_row_values',
255 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified above before reading the checkbox state.
256 isset( $_POST['snippets_table_truncate_row_values'] ) ? 1 : 0
257 );
258 }
259
260 /**
261 * Save only the snippets per-page Screen Option.
262 *
263 * @param mixed $status Current screen option status.
264 * @param string $option The screen option name.
265 * @param mixed $value Screen option value.
266 *
267 * @return mixed
268 */
269 public function save_per_page_option( $status, string $option, $value ) {
270 return 'snippets_per_page' === $option ? $value : $status;
271 }
272 }
273