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 / modules / actions-v2 / insert-post / properties / post-meta-property.php

post-meta-property.php in JetFormBuilder — Dynamic Blocks Form Builder 3.6.6, at modules/actions-v2/insert-post/properties/post-meta-property.php

220 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 namespace JFB_Modules\Actions_V2\Insert_Post\Properties;
5
6 use Jet_Form_Builder\Actions\Methods\Abstract_Modifier;
7 use Jet_Form_Builder\Actions\Methods\Object_Dynamic_Property;
8 use Jet_Form_Builder\Classes\Tools;
9 use Jet_Form_Builder\Classes\Value_Normalizers\Single_Value_As_Array;
10 use Jet_Form_Builder\Actions\Methods\Base_Object_Property;
11 use Jet_Form_Builder\Exceptions\Silence_Exception;
12 use JFB_Modules\Actions_V2\Insert_Post\Traits\Process_Meta_Boxes_Trait;
13 use JFB_Modules\Media_Cleanup\Module as Media_Cleanup;
14
15 // If this file is called directly, abort.
16 if ( ! defined( 'WPINC' ) ) {
17 die;
18 }
19
20 class Post_Meta_Property extends Base_Object_Property implements
21 Object_Dynamic_Property {
22
23
24 use Process_Meta_Boxes_Trait;
25
26 public function get_id(): string {
27 return 'meta_input';
28 }
29
30 public function get_label(): string {
31 return __( 'Post Meta', 'jet-form-builder' );
32 }
33
34 public function is_supported( string $key, $value ): bool {
35 return true;
36 }
37
38 /**
39 * @param Abstract_Modifier|Post_Modifier $modifier
40 */
41 public function do_before( string $key, $value, Abstract_Modifier $modifier ) {
42 if ( ! Tools::is_repeater_val( $value ) ) {
43 $this->set_meta(
44 array(
45 $key => $value,
46 )
47 );
48
49 return;
50 }
51
52 $this->set_meta(
53 array(
54 $key => Tools::prepare_repeater_value( $value, $modifier->fields_map ),
55 )
56 );
57 }
58
59 public function do_after( Abstract_Modifier $modifier ) {
60 /** @var Base_Post_Action $action */
61 $action = $modifier->get_action();
62 $id = $action->get_inserted();
63
64 if ( ! $id ) {
65 return;
66 }
67
68 /**
69 * @see https://github.com/Crocoblock/issues-tracker/issues/16657
70 */
71
72 $single_value_as_array = Single_Value_As_Array::prepare_flags(
73 $modifier->single_value_as_array ?? array()
74 );
75
76 $single_as_array_fields = array_keys(
77 array_filter(
78 $single_value_as_array,
79 static function ( $val ) {
80 return (bool) $val;
81 }
82 )
83 );
84
85 $meta_keys_to_array = array();
86
87 if ( ! empty( $single_as_array_fields ) && ! empty( $modifier->fields_map ) ) {
88 $meta_keys_to_array = array_values(
89 array_intersect_key(
90 $modifier->fields_map,
91 array_flip( $single_as_array_fields )
92 )
93 );
94 }
95
96 $meta_box_fields = $this->get_meta_box_fields( $id, $modifier );
97
98 foreach ( $this->value as $meta_key => $value ) {
99 if ( ! in_array( $meta_key, $meta_keys_to_array, true ) ) {
100 continue;
101 }
102
103 $this->value[ $meta_key ] = Single_Value_As_Array::maybe_wrap(
104 $value,
105 $meta_key,
106 array_fill_keys( $meta_keys_to_array, true )
107 );
108 }
109
110 $prepared_value = $this->normalize_checkboxes( $meta_box_fields, $this->value );
111
112 foreach ( $single_as_array_fields as $field_name ) {
113
114 // By form field name.
115 if ( array_key_exists( $field_name, $prepared_value ) ) {
116 $prepared_value[ $field_name ] = Single_Value_As_Array::maybe_wrap(
117 $prepared_value[ $field_name ],
118 $field_name,
119 $single_value_as_array
120 );
121 }
122
123 // By meta key fallback.
124 if ( isset( $modifier->fields_map[ $field_name ] ) ) {
125 $meta_key = $modifier->fields_map[ $field_name ];
126
127 if ( array_key_exists( $meta_key, $prepared_value ) ) {
128 $prepared_value[ $meta_key ] = Single_Value_As_Array::maybe_wrap(
129 $prepared_value[ $meta_key ],
130 $field_name,
131 $single_value_as_array
132 );
133 }
134 }
135 }
136
137 // Push processed values into $_POST. JetEngine reads from here.
138 $_POST = array_merge( $_POST, $prepared_value ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
139
140 $meta_keys_for_cleanup = Media_Cleanup::get_post_meta_keys_for_cleanup( $modifier );
141 $old_attachment_ids = Media_Cleanup::collect_post_meta_attachment_ids(
142 $id,
143 $meta_keys_for_cleanup
144 );
145
146 foreach ( $this->value as $key => $value ) {
147 if ( in_array( $key, $meta_keys_to_array, true ) ) {
148 update_post_meta( $id, $key, array_values( (array) $value ) );
149 continue;
150 }
151
152 update_post_meta( $id, $key, $value );
153 }
154
155 /**
156 * Snapshot what the form itself just wrote, before process_meta_boxes() below can
157 * touch the same meta key. A JetEngine meta box can be configured to write the same
158 * post meta key a media-cleanup-enabled field uses (fields_map allows any meta key
159 * to be shared); Cherry_X_Post_Meta::save_meta_option() may overwrite, transform, or
160 * (per filter_meta_box_fields_by_values()) leave that key untouched depending on
161 * what it finds in $this->value - there is no guarantee it reproduces exactly what
162 * the form submitted.
163 *
164 * @see https://github.com/Crocoblock/issues-tracker/issues/20547
165 */
166 $form_written_attachment_ids = Media_Cleanup::collect_post_meta_attachment_ids(
167 $id,
168 $meta_keys_for_cleanup
169 );
170
171 // JetEngine meta boxes processing.
172 $this->process_meta_boxes( $id, $modifier );
173
174 /**
175 * The final "new" snapshot is taken AFTER process_meta_boxes(), since that is what
176 * the post's meta actually ends up persisted as - but it is unioned with what the
177 * form itself wrote rather than used alone. Using only the post-meta-box value would
178 * let a meta box silently drop an attachment ID the submitter's own field still
179 * legitimately included (e.g. by overwriting the shared key with a stale or
180 * differently-shaped value), causing maybe_delete_attachments() below to delete an
181 * attachment the saved post still actually needs. Since the diff below only deletes
182 * IDs that are absent from BOTH snapshots would ever fail to catch, this union can
183 * only ever cause an attachment to be kept when in doubt, never wrongly deleted -
184 * the same fail-closed-on-deletion posture the rest of this fix uses throughout
185 * (see Media_Cleanup::delete_attachments()' own docblock).
186 */
187 $new_attachment_ids = array_unique(
188 array_merge(
189 $form_written_attachment_ids,
190 Media_Cleanup::collect_post_meta_attachment_ids( $id, $meta_keys_for_cleanup )
191 )
192 );
193
194 Media_Cleanup::maybe_delete_attachments( $old_attachment_ids, $new_attachment_ids, $id );
195 }
196
197 public function set_meta( array $meta ) {
198 if ( ! is_array( $this->value ) ) {
199 $this->value = array();
200 }
201
202 $this->value = array_merge( $this->value, $meta );
203 }
204
205 public static function prepare_meta( array $meta ): array {
206 foreach ( $meta as $meta_key => $meta_row ) {
207 if ( ! empty( $meta_row['key'] ) ) {
208 $meta[ $meta_row['key'] ] = $meta_row['value'];
209 unset( $meta[ $meta_key ] );
210 }
211 }
212
213 return $meta;
214 }
215
216 public function get_value( Abstract_Modifier $modifier ) {
217 throw new Silence_Exception();
218 }
219 }
220