PluginProbe
JetFormBuilder — Dynamic Blocks Form Builder / 3.6.6
JetFormBuilder — Dynamic Blocks Form Builder v3.6.6
3.6.6.1 3.6.6 3.6.5.4 3.6.5.3 3.6.5.2 3.6.5.1 3.6.5 3.6.4.2 3.6.4.1 3.6.4 3.6.3.1 3.6.3 3.6.2.2 3.6.2.1 3.6.2 3.6.1.1 3.6.1 3.6.0.1 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 All 134 releases
jetformbuilder / includes / admin / tabs-handlers / ssr-callbacks-handler.php

ssr-callbacks-handler.php in JetFormBuilder — Dynamic Blocks Form Builder 3.6.6, at includes/admin/tabs-handlers/ssr-callbacks-handler.php

122 lines 4.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 namespace Jet_Form_Builder\Admin\Tabs_Handlers;
5
6 use Jet_Form_Builder\Migrations\Auto_Migrator;
7 use JFB_Modules\Validation\Advanced_Rules\Ssr_Callback_Registry;
8 use JFB_Modules\Validation\Ssr\Ssr_Blocked_Callback_Usages;
9
10 // If this file is called directly, abort.
11 if ( ! defined( 'WPINC' ) ) {
12 die;
13 }
14
15 /**
16 * Settings tab for the global, admin-managed "Allowed Server-Side Callbacks" registry
17 * (`Ssr_Callback_Registry`). This is the only place a custom "Server-Side callback"
18 * function name can be added — saving a form never does it.
19 *
20 * @since 3.6.5.3
21 */
22 class Ssr_Callbacks_Handler extends Base_Handler {
23
24 public function slug() {
25 return 'ssr-callbacks-tab';
26 }
27
28 public function on_load() {
29 return array(
30 'callbacks' => implode( "\n", Ssr_Callback_Registry::get_allowed_callbacks() ),
31 'blocked' => $this->get_blocked_usages(),
32 'migrationInProgress' => Auto_Migrator::instance()->is_migration_in_progress(),
33 );
34 }
35
36 /**
37 * Informational only — a denylisted callback can never be approved, so each entry only
38 * needs enough context for an admin to find and manually fix the form.
39 *
40 * @since 3.6.5.3
41 *
42 * @return array{form_id: int, form_title: string, edit_url: string, field: string, name: string}[]
43 */
44 private function get_blocked_usages(): array {
45 $usages = array();
46
47 foreach ( Ssr_Blocked_Callback_Usages::get_usages() as $usage ) {
48 $form_id = (int) ( $usage['form_id'] ?? 0 );
49
50 if ( $form_id <= 0 ) {
51 continue;
52 }
53
54 // `get_the_title()` runs the `the_title` filter, which HTML-entity-encodes the
55 // raw post title (e.g. "–" becomes "&#8211;") for direct HTML output. This value
56 // is sent as JSON and rendered by Vue's text interpolation, which does its own
57 // escaping on display — so it needs the plain-text title, not the HTML-encoded
58 // one, or the entities show up literally in the settings tab.
59 $usages[] = array(
60 'form_id' => $form_id,
61 'form_title' => html_entity_decode( get_the_title( $form_id ), ENT_QUOTES, 'UTF-8' ),
62 'edit_url' => get_edit_post_link( $form_id, 'raw' ) ?: admin_url( 'post.php?post=' . $form_id . '&action=edit' ),
63 'field' => (string) ( $usage['field'] ?? '' ),
64 'name' => (string) ( $usage['name'] ?? '' ),
65 );
66 }
67
68 return $usages;
69 }
70
71 public function on_get_request() {
72 $migration_in_progress = Auto_Migrator::instance()->is_migration_in_progress();
73
74 // The legacy-migration import (`Version_3_6_5_3::up()`, via
75 // `Ssr_Callback_Registry::import_trusted_callbacks()`) does its own unlocked
76 // read-merge-write of `OPTION_KEY` once the scan across however many resumed
77 // requests it takes finally completes. A manual save from this tab in the middle of
78 // that window would race it: whichever of the two writes lands last silently
79 // discards the other's names. Refusing to save while the migration is still in
80 // progress removes the race outright, rather than only hiding it behind a UI that
81 // a direct AJAX request could still bypass (issues-tracker #20361 follow-up).
82 if ( $migration_in_progress ) {
83 wp_send_json_error(
84 array_merge(
85 $this->get_success_response_data(),
86 array(
87 'message' => __( 'A server-side callback migration is still restoring previously used functions. Please wait for it to finish before editing this list.', 'jet-form-builder' ),
88 'migrationInProgress' => true,
89 )
90 )
91 );
92
93 return;
94 }
95
96 // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- nonce verified in Base_Handler::on_raw_request(); each line is validated/sanitized via Server_Side_Rule::sanitize_callback_name() inside Ssr_Callback_Registry::save_allowed_callbacks() below.
97 $raw = isset( $_POST['callbacks'] ) ? wp_unslash( $_POST['callbacks'] ) : null;
98
99 $result = array(
100 'saved' => Ssr_Callback_Registry::get_allowed_callbacks(),
101 'rejected' => array(),
102 );
103
104 if ( is_string( $raw ) ) {
105 $lines = preg_split( '/\r\n|\r|\n/', $raw );
106 $result = Ssr_Callback_Registry::save_allowed_callbacks( $lines ?: array() );
107 }
108
109 wp_send_json_success(
110 array_merge(
111 $this->get_success_response_data(),
112 array(
113 'callbacks' => implode( "\n", $result['saved'] ),
114 'rejected' => $result['rejected'],
115 'migrationInProgress' => false,
116 )
117 )
118 );
119 }
120
121 }
122