PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 3.9.8
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v3.9.8
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
profile-builder / assets / lib / wck-api / wordpress-creation-kit.php

wordpress-creation-kit.php in User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor 3.9.8, at assets/lib/wck-api/wordpress-creation-kit.php

1,611 lines 64.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* Copyright 2011 Ungureanu Madalin (email : [email protected])
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or
6 (at your option) any later version.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
11 You should have received a copy of the GNU General Public License
12 along with this program; if not, write to the Free Software
13 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
14 */
15
16 if( file_exists( dirname(__FILE__). '/wck-fep/wck-fep.php' ) )
17 require_once( 'wck-fep/wck-fep.php' );
18
19 if( file_exists( dirname(__FILE__). '/wck-static-metabox-api.php' ) )
20 require_once( 'wck-static-metabox-api.php' );
21
22
23 /*
24
25 Usage Example 1:
26
27
28 $fint = array(
29 array( 'type' => 'text', 'title' => 'Title', 'description' => 'Description for this input' ),
30 array( 'type' => 'textarea', 'title' => 'Description' ),
31 array( 'type' => 'upload', 'title' => 'Image', 'description' => 'Upload a image' ),
32 array( 'type' => 'select', 'title' => 'Select This', 'options' => array( 'Option 1', 'Option 2', 'Option 3' ) ),
33 array( 'type' => 'checkbox', 'title' => 'Check This', 'options' => array( 'Option 1', 'Option 2', 'Option 3' ) ),
34 array( 'type' => 'radio', 'title' => 'Radio This', 'options' => array( 'Radio 1', 'Radio 2', 'Radio 3' ) ),
35 );
36
37 $args = array(
38 'metabox_id' => 'rm_slider_content',
39 'metabox_title' => 'Slideshow Class',
40 'post_type' => 'slideshows',
41 'meta_name' => 'rmscontent',
42 'meta_array' => $fint
43 );
44
45 new Wordpress_Creation_Kit_PB( $args );
46
47
48 On the frontend:
49
50 $meta = get_post_meta( $post->ID, 'rmscontent', true );
51
52 */
53
54 class Wordpress_Creation_Kit_PB{
55
56 private $defaults = array(
57 'metabox_id' => '',
58 'metabox_title' => 'Meta Box',
59 'post_type' => 'post',
60 'meta_name' => '',
61 'meta_array' => array(),
62 'page_template' => '',
63 'post_id' => '',
64 'single' => false,
65 'unserialize_fields' => false,
66 'sortable' => true,
67 'context' => 'post_meta',
68 'mb_context' => 'normal'
69 );
70 private $args;
71
72
73 /* Constructor method for the class. */
74 function __construct( $args ) {
75
76 /* Global that will hold all the arguments for all the custom boxes */
77 global $wck_objects;
78
79 /* Merge the input arguments and the defaults. */
80 $this->args = wp_parse_args( $args, $this->defaults );
81
82 /* Add the settings for this box to the global object */
83 $wck_objects[$this->args['metabox_id']] = $this->args;
84
85 /*print scripts*/
86 add_action('admin_enqueue_scripts', array( &$this, 'wck_print_scripts' ), 9);
87 /* add our own ajaxurl because we are going to use the wck script also in frontend and we want to avoid any conflicts */
88 add_action( 'admin_head', array( &$this, 'wck_print_ajax_url' ) );
89
90 // Set up the AJAX hooks
91 add_action("wp_ajax_wck_add_meta".$this->args['meta_name'], array( &$this, 'wck_add_meta') );
92 add_action("wp_ajax_wck_update_meta".$this->args['meta_name'], array( &$this, 'wck_update_meta') );
93 add_action("wp_ajax_wck_show_update".$this->args['meta_name'], array( &$this, 'wck_show_update_form') );
94 add_action("wp_ajax_wck_refresh_list".$this->args['meta_name'], array( &$this, 'wck_refresh_list') );
95 add_action("wp_ajax_wck_remove_meta".$this->args['meta_name'], array( &$this, 'wck_remove_meta') );
96 add_action("wp_ajax_wck_reorder_meta".$this->args['meta_name'], array( &$this, 'wck_reorder_meta') );
97
98 add_action('add_meta_boxes', array( &$this, 'wck_add_metabox') );
99
100 /* For single forms we save them the old fashion way */
101 if( $this->args['single'] ){
102 add_action('save_post', array($this, 'wck_save_single_metabox'), 10, 2);
103 /* wp_insert_post executes after save_post so at this point if we have the error global we can redirect the page
104 and add the error message and error fields urlencoded as $_GET */
105 add_action('wp_insert_post', array($this, 'wck_single_metabox_redirect_if_errors'), 10, 2);
106 /* if we have any $_GET errors alert them with js so we have consistency */
107 add_action('admin_print_footer_scripts', array($this, 'wck_single_metabox_errors_display') );
108 }
109
110 }
111
112
113 //add metabox using wordpress api
114
115 function wck_add_metabox() {
116
117 global $pb_wck_pages_hooknames;
118
119 if( $this->args['context'] == 'post_meta' ){
120 if( $this->args['post_id'] == '' && $this->args['page_template'] == '' ){
121 add_meta_box($this->args['metabox_id'], $this->args['metabox_title'], array( &$this, 'wck_content' ), $this->args['post_type'], $this->args['mb_context'], 'high', array( 'meta_name' => $this->args['meta_name'], 'meta_array' => $this->args['meta_array']) );
122 /* add class to meta box */
123 add_filter( "postbox_classes_".$this->args['post_type']."_".$this->args['metabox_id'], array( &$this, 'wck_add_metabox_classes' ) );
124 }
125 else{
126 if( !empty( $_GET['post'] ) )
127 $post_id = filter_var( $_GET['post'], FILTER_SANITIZE_NUMBER_INT );
128 else if( !empty( $_POST['post_ID'] ) )
129 $post_id = filter_var( $_POST['post_ID'], FILTER_SANITIZE_NUMBER_INT );
130 else
131 $post_id = '';
132
133
134 if( $this->args['post_id'] != '' && $this->args['page_template'] != '' ){
135 $template_file = get_post_meta($post_id,'_wp_page_template',TRUE);
136 if( $this->args['post_id'] == $post_id && $template_file == $this->args['page_template'] )
137 add_meta_box($this->args['metabox_id'], $this->args['metabox_title'], array( &$this, 'wck_content' ), 'page', $this->args['mb_context'], 'high', array( 'meta_name' => $this->args['meta_name'], 'meta_array' => $this->args['meta_array'] ) );
138
139 /* add class to meta box */
140 add_filter( "postbox_classes_page_".$this->args['metabox_id'], array( &$this, 'wck_add_metabox_classes' ) );
141 }
142 else{
143
144 if( $this->args['post_id'] != '' ){
145 if( $this->args['post_id'] == $post_id ){
146 $post_type = get_post_type( $post_id );
147 add_meta_box($this->args['metabox_id'], $this->args['metabox_title'], array( &$this, 'wck_content' ), $post_type, $this->args['mb_context'], 'high', array( 'meta_name' => $this->args['meta_name'], 'meta_array' => $this->args['meta_array'] ) );
148 /* add class to meta box */
149 add_filter( "postbox_classes_".$post_type."_".$this->args['metabox_id'], array( &$this, 'wck_add_metabox_classes' ) );
150 }
151 }
152
153 if( $this->args['page_template'] != '' ){
154 $template_file = get_post_meta($post_id,'_wp_page_template',TRUE);
155 if ( $template_file == $this->args['page_template'] ){
156 add_meta_box($this->args['metabox_id'], $this->args['metabox_title'], array( &$this, 'wck_content' ), 'page', $this->args['mb_context'], 'high', array( 'meta_name' => $this->args['meta_name'], 'meta_array' => $this->args['meta_array']) );
157 /* add class to meta box */
158 add_filter( "postbox_classes_page_".$this->args['metabox_id'], array( &$this, 'wck_add_metabox_classes' ) );
159 }
160 }
161
162 }
163
164 }
165 }
166 else if( $this->args['context'] == 'option' ){
167 if( !empty( $pb_wck_pages_hooknames[$this->args['post_type']] ) ) {
168 add_meta_box($this->args['metabox_id'], $this->args['metabox_title'], array(&$this, 'wck_content'), $pb_wck_pages_hooknames[$this->args['post_type']], $this->args['mb_context'], 'high', array('meta_name' => $this->args['meta_name'], 'meta_array' => $this->args['meta_array']));
169 /* add class to meta box */
170 add_filter("postbox_classes_" . $pb_wck_pages_hooknames[$this->args['post_type']] . "_" . $this->args['metabox_id'], array(&$this, 'wck_add_metabox_classes'));
171 }
172 }
173 }
174
175 /* Function used to add classes to the wck meta boxes */
176 function wck_add_metabox_classes( $classes ){
177 array_push($classes,'wck-post-box');
178 return $classes;
179 }
180
181 function wck_content($post, $metabox){
182 if( !empty( $post->ID ) )
183 $post_id = $post->ID;
184 else
185 $post_id = '';
186
187
188
189 // //output the add form or themes metabox content
190 if ($metabox['id'] == 'wppb-ul-themes-settings' ) {
191 echo $metabox['args']['meta_array']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
192 }
193 else self::create_add_form($metabox['args']['meta_array'], $metabox['args']['meta_name'], $post);
194
195 //output the entries only for repeater fields
196 if( !$this->args['single'] )
197 echo self::wck_output_meta_content($metabox['args']['meta_name'], $post_id, $metabox['args']['meta_array']); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
198 }
199
200 /**
201 * The function used to create a form element
202 *
203 * @since 1.0.0
204 *
205 * @param string $meta Meta name.
206 * @param array $details Contains the details for the field.
207 * @param string $value Contains input value;
208 * @param string $context Context where the function is used. Depending on it some actions are preformed.;
209 * @param int $post_id The post ID;
210 * @return string $element input element html string.
211 */
212
213 function wck_output_form_field( $meta, $details, $value = '', $context = '', $post_id = '' ){
214 $element = '';
215
216 if( $context == 'edit_form' ){
217 $edit_class = '.mb-table-container ';
218 $var_prefix = 'edit';
219 }
220 else if( $context == 'fep' ){
221 /* id prefix for frontend posting */
222 $frontend_prefix = 'fep-';
223 }
224 else{
225 if( isset( $details['default'] ) && !( $this->args['single'] == true && !is_null( $value ) ) ) {
226 $value = apply_filters("wck_default_value_{$meta}_" . Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details ), $details['default']);
227 }
228 }
229
230 /* for single post meta metaboxes we need a prefix in the name attr of the input because in the case we have multiple single metaboxes on the same
231 post we need to prevent the fields from having the same name attr */
232 if( $this->args['context'] == 'post_meta' && $this->args['single'] && $context != 'fep' )
233 $single_prefix = $this->args['meta_name'].'_';
234 else
235 $single_prefix = '';
236
237 $element .= '<label for="'. $single_prefix . esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details ) ) .'" class="field-label">'. apply_filters( "wck_label_{$meta}_". Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details ), ucfirst($details['title']) ) .':';
238 if( !empty( $details['required'] ) && $details['required'] )
239 $element .= '<span class="required">*</span>';
240 $element .= '</label>';
241
242 $element .= '<div class="mb-right-column">';
243
244 // Allow for appeding custom markup before the element.
245 $element .= apply_filters( 'wck_output_form_field_before_customtype_' . $details['type'], '', $value, $details, $single_prefix );
246
247 /*
248 include actual field type
249 possible field types: text, textarea, select, checkbox, radio, upload, wysiwyg editor, datepicker, country select, user select, cpt select
250 */
251
252 if( function_exists( 'wck_nr_get_repeater_boxes' ) ){
253 $cfc_titles = wck_nr_get_repeater_boxes();
254 if( in_array( $details['type'], $cfc_titles ) ){
255 $details['type'] = 'nested repeater';
256 }
257 }
258
259 if ( isset( $details['options'] ) ) {
260 // Allow to filter the options for specific field slugs.
261 $details = apply_filters( 'wck_output_form_field_options_by_slug', $details, $details['slug'], $value, $single_prefix );
262 }
263
264 if( file_exists( dirname( __FILE__ ).'/fields/'.$details['type'].'.php' ) ){
265 require( dirname( __FILE__ ).'/fields/'.$details['type'].'.php' );
266 }
267
268 // Add a filter that allows us to add support for custom field types, not just the ones defined in fields (wck api)
269 $element .= apply_filters('wck_output_form_field_customtype_' . $details['type'], '', $value, $details, $single_prefix);
270
271
272 // Allow for appeding custom markup after the element.
273 $element .= apply_filters( 'wck_output_form_field_after_customtype_' . $details['type'], '', $value, $details, $single_prefix );
274
275 if( !empty( $details['description'] ) ){
276 $element .= '<p class="description">'. $details['description'].'</p>';
277 }
278
279 $element .= '</div><!-- .mb-right-column -->';
280
281 $element = apply_filters( "wck_output_form_field_{$meta}_" . Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details ), $element );
282
283 return $element;
284
285 }
286
287
288 /**
289 * The function used to create the form for adding records
290 *
291 * @since 1.0.0
292 *
293 * @param array $fields Contains the desired inputs in the repeater field. Must be like: array('Key:type').
294 * Key is used for the name attribute of the field, label of the field and as the meta_key.
295 * Supported types: input, textarea, upload
296 * @param string $meta It is used in update_post_meta($id, $meta, $results);. Use '_' prefix if you don't want
297 * the meta to apear in custom fields box.
298 * @param object $post Post object
299 */
300 function create_add_form($fields, $meta, $post, $context = '' ){
301 $nonce = wp_create_nonce( 'wck-add-meta' );
302 if( !empty( $post->ID ) )
303 $post_id = $post->ID;
304 else
305 $post_id = '';
306
307 /* for single forms we need the values that are stored in the meta */
308 if( $this->args['single'] == true ) {
309 if ($this->args['context'] == 'post_meta')
310 $results = get_post_meta($post_id, $meta, true);
311 else if ($this->args['context'] == 'option')
312 $results = get_option( apply_filters( 'wck_option_meta' , $meta ));
313
314 /* Filter primary used for CFC/OPC fields in order to show/hide fields based on type */
315 $wck_update_container_css_class = apply_filters("wck_add_form_class_{$meta}", '', $meta, $results );
316 }
317 ?>
318 <div id="<?php echo esc_attr( $meta ) ?>" style="padding:10px 0;" class="wck-add-form<?php if( $this->args['single'] ) echo ' single' ?> <?php if( !empty( $wck_update_container_css_class ) ) echo esc_attr( $wck_update_container_css_class ); ?>">
319 <ul class="mb-list-entry-fields">
320 <?php
321 $element_id = 0;
322 if( !empty( $fields ) ){
323 foreach( $fields as $details ){
324
325 do_action( "wck_before_add_form_{$meta}_element_{$element_id}" );
326
327 /* set values in the case of single forms */
328 $value = '';
329 if( $this->args['single'] == true ) {
330 $value = null;
331 if (isset($results[0][Wordpress_Creation_Kit_PB::wck_generate_slug($details['title'], $details )]))
332 $value = $results[0][Wordpress_Creation_Kit_PB::wck_generate_slug($details['title'], $details )];
333 }
334 ?>
335 <li class="row-<?php echo esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details ) ) ?>">
336 <?php echo self::wck_output_form_field( $meta, $details, $value, $context, $post_id ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
337 </li>
338 <?php
339
340 do_action( "wck_after_add_form_{$meta}_element_{$element_id}" );
341
342 $element_id++;
343 }
344 }
345 ?>
346 <?php if( ! $this->args['single'] || $this->args['context'] == 'option' ){ ?>
347 <li style="overflow:visible;" class="add-entry-button">
348 <a href="javascript:void(0)" class="button-primary" onclick="addMeta('<?php echo esc_js($meta); ?>', '<?php echo esc_js( $post_id ); ?>', '<?php echo esc_js($nonce); ?>')"><span><?php if( $this->args['single'] ) echo esc_html( apply_filters( 'wck_add_entry_button', __( 'Save', 'profile-builder' ), $meta, $post ) ); else echo esc_html( apply_filters( 'wck_add_entry_button', __( 'Add Entry', 'profile-builder' ), $meta, $post ) ); ?></span></a>
349 </li>
350 <?php }elseif($this->args['single'] && $this->args['context'] == 'post_meta' ){ ?>
351 <input type="hidden" name="_wckmetaname_<?php echo esc_attr( $meta ) ?>#wck" value="true">
352 <?php } ?>
353 </ul>
354 </div>
355 <script>wck_set_to_widest( '.field-label', '<?php echo esc_js( $meta ) ?>' );</script>
356 <?php
357 }
358
359 /**
360 * The function used to display a form to update a reccord from meta
361 *
362 * @since 1.0.0
363 *
364 * @param string $meta It is used in get_post_meta($id, $meta, $results);. Use '_' prefix if you don't want
365 * the meta to apear in custom fields box.
366 * @param int $id Post id
367 * @param int $element_id The id of the reccord. The meta is stored as array(array());
368 */
369 function mb_update_form($fields, $meta, $id, $element_id){
370
371 $update_nonce = wp_create_nonce( 'wck-update-entry' );
372
373 if( $this->args['context'] == 'post_meta' )
374 $results = get_post_meta($id, $meta, true);
375 else if ( $this->args['context'] == 'option' )
376 $results = get_option( apply_filters( 'wck_option_meta' , $meta ) );
377
378 /* Filter primary used for CFC/OPC fields in order to show/hide fields based on type */
379 $wck_update_container_css_class = " class='wck_update_container update_container_$meta'";
380 $wck_update_container_css_class = apply_filters("wck_update_container_class_{$meta}", $wck_update_container_css_class, $meta, $results, $element_id );
381
382 $form = '';
383 $form .= '<tr id="update_container_'.$meta.'_'.$element_id.'" ' . $wck_update_container_css_class . '><td colspan="4">';
384 if($results != null){
385 $i = 0;
386 $form .= '<ul class="mb-list-entry-fields">';
387
388 if( !empty( $fields ) ){
389 foreach( $fields as $field ){
390 $details = $field;
391 if( isset( $results[$element_id][Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details )] ) )
392 $value = $results[$element_id][Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details )];
393 else
394 $value = '';
395
396 $form = apply_filters( "wck_before_update_form_{$meta}_element_{$i}", $form, $element_id, $value );
397
398 $form .= '<li class="row-'. esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details ) ) .'">';
399
400 $form .= self::wck_output_form_field( $meta, $details, $value, 'edit_form', $id );
401
402 $form .= '</li>';
403
404 $form = apply_filters( "wck_after_update_form_{$meta}_element_{$i}", $form, $element_id, $value );
405
406 $i++;
407 }
408 }
409 $form .= '<li style="overflow:visible;">';
410 $form .= '<a href="javascript:void(0)" class="button-primary" onclick=\'updateMeta("'.esc_js($meta).'", "'.esc_js($id).'", "'.esc_js($element_id).'", "'.esc_js($update_nonce).'")\'><span>'. apply_filters( 'wck_save_changes_button', __( 'Save Changes', 'profile-builder' ), $meta ) .'</span></a>';
411 $form .= '<a href="javascript:void(0)" class="button-secondary" style="margin-left:10px;" onclick=\'removeUpdateForm("'. esc_js( 'update_container_'.$meta.'_'.$element_id ). '" )\'><span>'. apply_filters( 'wck_cancel_button', __( 'Cancel', 'profile-builder' ), $meta ) .'</span></a>';
412 $form .= '</li>';
413
414 $form .= '</ul>';
415 }
416 $form .= '</td></tr>';
417
418 return $form;
419 }
420
421
422 /**
423 * The function used to output the content of a meta
424 *
425 * @since 1.0.0
426 *
427 * @param string $meta It is used in get_post_meta($id, $meta, $results);. Use '_' prefix if you don't want
428 * the meta to apear in custom fields box.
429 * @param int $id Post id
430 */
431 function wck_output_meta_content($meta, $id, $fields, $box_args = '' ){
432 /* in fep $this->args is empty so we need it as a parameter */
433 if( !empty( $box_args ) )
434 $this->args = wp_parse_args( $box_args, $this->defaults );
435
436
437 if( $this->args['context'] == 'post_meta' || $this->args['context'] == '' )
438 $results = get_post_meta($id, $meta, true);
439 else if ( $this->args['context'] == 'option' )
440 $results = get_option( apply_filters( 'wck_option_meta' , $meta ) );
441
442 $list = '';
443 $list .= '<table id="container_'.esc_attr($meta).'" class="mb-table-container widefat';
444
445 if( $this->args['single'] ) $list .= ' single';
446 if( !$this->args['sortable'] ) $list .= ' not-sortable';
447
448 $list .= '" post="'.esc_attr($id).'">';
449
450
451 if( !empty( $results ) ){
452 $list .= apply_filters( 'wck_metabox_content_header_'.$meta , '<thead><tr><th class="wck-number">#</th><th class="wck-content">'. __( 'Content', 'profile-builder' ) .'</th><th class="wck-edit">'. __( 'Edit', 'profile-builder' ) .'</th><th class="wck-delete">'. __( 'Delete', 'profile-builder' ) .'</th></tr></thead>' );
453 $i=0;
454 foreach ($results as $result){
455
456 $list .= self::wck_output_entry_content( $meta, $id, $fields, $results, $i );
457
458 $i++;
459 }
460 }
461 $list .= apply_filters( 'wck_metabox_content_footer_'.$meta , '', $id );
462 $list .= '</table>';
463
464 $list = apply_filters('wck_metabox_content_'.$meta, $list, $id);
465 return $list;
466 }
467
468 function wck_output_entry_content( $meta, $id, $fields, $results, $element_id ){
469 $edit_nonce = wp_create_nonce( 'wck-edit-entry' );
470 $delete_nonce = wp_create_nonce( 'wck-delete-entry' );
471 $entry_nr = $element_id +1;
472
473 $wck_element_class = '';
474 $wck_element_class = apply_filters( "wck_element_class_{$meta}", $wck_element_class, $meta, $results, $element_id );
475
476 $list = '';
477 $list .= '<tr id="element_'.$element_id.'" ' . $wck_element_class . '>';
478 $list .= apply_filters( 'wck_add_content_before_columns', '', $list, $meta );
479 $list .= '<td style="text-align:center;vertical-align:middle;" class="wck-number">'. $entry_nr .'</td>';
480 $list .= '<td class="wck-content"><ul>' . "\r\n";
481
482 $j = 0;
483
484 if( !empty( $fields ) ){
485 foreach( $fields as $field ){
486 $details = $field;
487
488 if( !empty( $results[$element_id][Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details )] ) )
489 $value = $results[$element_id][Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details )];
490 else
491 $value ='';
492
493 /* filter display value */
494 $value = apply_filters( "wck_displayed_value_{$meta}_element_{$j}", $value );
495
496 /* display it differently based on field type*/
497 if( $details['type'] == 'upload' ){
498 $display_value = self::wck_get_entry_field_upload($value);
499 } elseif ( $details['type'] == 'user select' ) {
500 $display_value = self::wck_get_entry_field_user_select( $value ) . '</pre>';
501 } elseif ( $details['type'] == 'cpt select' ){
502 $display_value = self::wck_get_entry_field_cpt_select( $value ) . '</pre>';
503 } elseif ( $details['type'] == 'checkbox' && is_array( $value ) ){
504 $display_value = implode( ', ', $value );
505 } elseif ( $details['type'] == 'select' || $details['type'] === 'select-2' ){
506 if ( $details['slug'] === 'pble-label' || $details['slug'] === 'field'){
507 $display_value = '<pre>' . self::wck_get_entry_field_select( $value, $details ) . '</pre>';
508 } else {
509 $display_value = '<pre>' . __(self::wck_get_entry_field_select( $value, $details ), 'profile-builder') . '</pre>'; //phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
510 }
511 } else {
512 $display_value = '<pre>'.htmlspecialchars( $value ) . '</pre>';
513 }
514
515 $display_value = apply_filters( "wck_pre_displayed_value_{$meta}_element_{$field['slug']}", $display_value );
516
517 $list = apply_filters( "wck_before_listed_{$meta}_element_{$j}", $list, $element_id, $value );
518 /*check for nested repeater type and set it acordingly */
519 if( strpos( $details['type'], 'CFC-') === 0 )
520 $details['type'] = 'nested-repeater';
521
522 $list .= '<li class="row-'. esc_attr( Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details ) ) .'" data-type="'.$details['type'].'"><strong>'.$details['title'].': </strong>'.$display_value.' </li>' . "\r\n";
523
524 $list = apply_filters( "wck_after_listed_{$meta}_element_{$j}", $list, $element_id, $value );
525
526 $j++;
527
528 /* In CFC/OPC we need the field title. Find it out and output it if found */
529 if ($meta == 'wck_cfc_fields') {
530 if( !empty( $results[$element_id][Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details )] ) ){
531 $field_title = $results[$element_id][Wordpress_Creation_Kit_PB::wck_generate_slug( $details['title'], $details )];
532 if ($field_title == "Field Type")
533 $cfc_field_type = $value;
534 }
535 }
536 }
537 }
538 $list .= '</ul>';
539
540 $list = apply_filters( 'wck_after_content_element', $list, $meta, $id, $results, $element_id );
541 /* check if we have nested repeaters */
542 if( function_exists( 'wck_nr_check_for_nested_repeaters' ) ){
543 if( wck_nr_check_for_nested_repeaters( $fields ) === true ){
544 $list .= wck_nr_handle_repeaters( $meta, $id, $fields, $results, $element_id );
545 }
546 }
547
548 if( $element_id === 0 ){
549 $list .= "<script>wck_set_to_widest( 'strong', '". $meta ."' );</script>";
550 }
551
552 $list .= '</td>';
553 $list .= '<td style="text-align:center;vertical-align:middle;" class="wck-edit"><a href="javascript:void(0)" class="button-secondary" onclick=\'showUpdateFormMeta("'.esc_js($meta).'", "'.esc_js($id).'", "'.esc_js($element_id).'", "'.esc_js($edit_nonce).'")\' title="'. __( 'Edit this item', 'profile-builder' ) .'">'. apply_filters( 'wck_edit_button', __('Edit','profile-builder'), $meta ) .'</a></td>';
554 $list .= '<td style="text-align:center;vertical-align:middle;" class="wck-delete"><a href="javascript:void(0)" class="mbdelete" onclick=\'removeMeta("'.esc_js($meta).'", "'.esc_js($id).'", "'.esc_js($element_id).'", "'.esc_js($delete_nonce).'")\' title="'. __( 'Delete this item', 'profile-builder' ) .'">'. apply_filters( 'wck_delete_button', __( 'Delete', 'profile-builder' ), $meta) .'</a></td>';
555 $list .= apply_filters( 'wck_add_content_after_columns', '', $list, $meta );
556
557 $list .= "</tr> \r\n";
558
559 return $list;
560 }
561
562 /* function to generate the output for the select field */
563 function wck_get_entry_field_select( $value, $field_details ){
564 if ( (!is_array( $field_details ) && !isset( $field_details['options']) ) || empty( $value )){
565 return $value;
566 }
567
568 //convert field_details to single array if option groups are defined.
569 if( Wordpress_Creation_Kit_PB::wck_is_multi( $field_details['options'] ) ){
570 $select_options = array();
571 foreach($field_details['options']['optgroups'] as $optgroup) {
572 foreach($optgroup['options'] as $group_option ){
573
574 if( !is_array( $group_option ) )
575 $select_options[] = $group_option;
576
577 }
578 }
579
580 $field_details['options'] = $select_options;
581 }
582
583 foreach( $field_details['options'] as $option ){
584
585 if( is_array( $option ) ){
586
587 if( !empty( $option['field_name'] ) )
588 return $option['field_name'];
589
590 } elseif ( strpos( $option, $value ) !== false ){
591 if( strpos( $option, '%' ) === false ){
592 return $value;
593 } else {
594 $option_parts = explode( '%', $option );
595 if( !empty( $option_parts ) ){
596 if( empty( $option_parts[0] ) && count( $option_parts ) == 3 ){
597 $label = $option_parts[1];
598 return $label;
599 }
600 }
601 }
602 }
603
604 }
605
606 //this was added for select-2 custom values that do not exist in the defined options
607 return $value;
608 }
609
610 /* function to generate output for upload field */
611 function wck_get_entry_field_upload($id){
612 if( !empty ( $id ) && is_numeric( $id ) ){
613 $file_src = wp_get_attachment_url($id);
614 $thumbnail = wp_get_attachment_image( $id, array( 80, 60 ), true );
615 $file_name = get_the_title( $id );
616
617 if ( preg_match( '/^.*?\.(\w+)$/', get_attached_file( $id ), $matches ) )
618 $file_type = esc_html( strtoupper( $matches[1] ) );
619 else
620 $file_type = strtoupper( str_replace( 'image/', '', get_post_mime_type( $id ) ) );
621
622 return $display_value = '<div class="upload-field-details">'. $thumbnail .'<p><span class="file-name">'. $file_name .'</span><span class="file-type">'. $file_type . '</span></p></div>';
623 } else {
624 return '';
625 }
626 }
627
628 /* function to generate output for user select */
629 function wck_get_entry_field_user_select($id){
630 if( !empty ( $id ) && is_numeric( $id ) ){
631 $user = get_user_by( 'id', $id );
632 if ( $user )
633 return '<pre>'.htmlspecialchars( $user->display_name );
634 else
635 return 'Error - User ID not found in database';
636
637 } else {
638 return '';
639 }
640 }
641
642 /* function to generate output for cpt select */
643 function wck_get_entry_field_cpt_select($id){
644 if( !empty ( $id ) && is_numeric( $id ) ){
645 $post = get_post( $id );
646
647 if ( $post != null ){
648 if ( $post->post_title == '' )
649 $post->post_title = 'No title. ID: ' . $id;
650
651 return '<pre>'.htmlspecialchars( $post->post_title );
652 }
653 else
654 return 'Error - Post ID not found in database';
655
656 } else {
657 return '';
658 }
659 }
660
661 /* enque the js/css */
662 function wck_print_scripts($hook){
663 global $pb_wck_pages_hooknames;
664
665 if( $this->args['context'] == 'post_meta' ) {
666 if( 'post.php' == $hook || 'post-new.php' == $hook){
667
668 /* only add on profile builder custom post types */
669 if( !empty( $_GET['post'] ) )
670 $post_id = filter_var( $_GET['post'], FILTER_SANITIZE_NUMBER_INT );
671 else if( !empty( $_POST['post_ID'] ) )
672 $post_id = filter_var( $_POST['post_ID'], FILTER_SANITIZE_NUMBER_INT );
673 else
674 $post_id = '';
675 if( !empty( $post_id ) ){
676 $current_post_type = get_post_type( $post_id );
677 if( strpos( $current_post_type, 'wppb-' ) === false )
678 return '';
679 }
680
681 self::wck_enqueue();
682 }
683 }
684 elseif( $this->args['context'] == 'option' ){
685 if( !empty( $pb_wck_pages_hooknames ) && isset( $this->args[ 'post_type' ] ) && isset( $pb_wck_pages_hooknames[ $this->args[ 'post_type' ] ] ) && $pb_wck_pages_hooknames[$this->args['post_type']] == $hook ){
686 self::wck_enqueue( 'options' );
687 }
688 }
689 }
690
691 /* our own ajaxurl */
692 function wck_print_ajax_url(){
693 echo '<script type="text/javascript">var wppbWckAjaxurl = "'. esc_js( apply_filters( 'wck_ajax_url', admin_url('admin-ajax.php') ) ).'";</script>';
694 }
695
696
697 /* Helper function for enqueueing scripts and styles */
698 private static function wck_enqueue( $context = '' ){
699
700 wp_enqueue_script( 'jquery-ui-draggable' );
701 wp_enqueue_script( 'jquery-ui-droppable' );
702 wp_enqueue_script( 'jquery-ui-sortable' );
703
704 if( $context == 'options' ){
705 wp_enqueue_script( 'thickbox' );
706 wp_enqueue_style( 'thickbox' );
707 }
708
709 wp_enqueue_script('wordpress-creation-kit', plugins_url('/wordpress-creation-kit.js', __FILE__), array('jquery', 'jquery-ui-draggable', 'jquery-ui-droppable', 'jquery-ui-sortable' ), PROFILE_BUILDER_VERSION );
710 wp_register_style('wordpress-creation-kit-css', plugins_url('/wordpress-creation-kit.css', __FILE__), array(), PROFILE_BUILDER_VERSION );
711 wp_enqueue_style('wordpress-creation-kit-css');
712
713 //select 2 KEEP the wppb-select2 handle so we don't include it multiple times, seeing we include it from PB as well
714 wp_enqueue_script( 'wppb-select2', plugins_url( '/assets/js/select2/select2.min.js', __FILE__ ), array(), PROFILE_BUILDER_VERSION, true );
715 wp_enqueue_script( 'wppb-select2-compat', WPPB_PLUGIN_URL . 'assets/js/select2-compat.js', array(), PROFILE_BUILDER_VERSION, true );
716 wp_enqueue_style( 'wppb-select2-style', plugins_url( '/assets/js/select2/select2.min.css', __FILE__ ), false, PROFILE_BUILDER_VERSION );
717
718 //datepicker
719 wp_enqueue_script('jquery-ui-datepicker');
720 wp_enqueue_style( 'jquery-style', plugins_url( '/assets/datepicker/datepicker.css', __FILE__ ) );
721
722
723 /* media upload */
724 wp_enqueue_media();
725 wp_enqueue_script('wck-upload-field', plugins_url('/fields/upload.js', __FILE__), array('jquery') );
726
727 }
728
729 /* Helper function for required fields */
730 function wck_test_required( $meta_array, $meta, $values, $id ){
731 $fields = apply_filters( 'wck_before_test_required', $meta_array, $meta, $values, $id );
732 $required_fields = array();
733 $required_fields_with_errors = array();
734 $required_message = '';
735
736 $errors = '';
737
738 if( !empty( $fields ) ){
739 foreach( $fields as $field ){
740 if( !empty( $field['required'] ) && $field['required'] )
741 $required_fields[Wordpress_Creation_Kit_PB::wck_generate_slug( $field['title'], $field )] = $field['title'];
742 }
743 }
744
745 if( !empty( $values ) ){
746 foreach( $values as $key => $value ){
747 if( array_key_exists( $key, $required_fields ) && apply_filters( "wck_required_test_{$meta}_{$key}", empty( $value ), $value, $id ) ){
748 $required_message .= apply_filters( "wck_required_message_{$meta}_{$key}", __( "Please enter a value for the required field ", "profile-builder" ) . "$required_fields[$key] \n", $value );
749 $required_fields_with_errors[] = $key;
750 }
751 }
752 }
753
754 $required_message .= apply_filters( "wck_extra_message", "", $fields, $required_fields, $meta, $values, $id );
755 $required_fields_with_errors = apply_filters( "wck_required_fields_with_errors", $required_fields_with_errors, $fields, $required_fields, $meta, $value, $id );
756
757 if( $required_message != '' ){
758 $errors = array( 'error' => $required_message, 'errorfields' => $required_fields_with_errors );
759 }
760
761 return $errors;
762 }
763
764 /* Checks to see wether the current user can modify data */
765 function wck_verify_user_capabilities( $context, $meta = '', $id = 0 ) {
766
767 $return = true;
768
769 // Meta is an option
770 if( $context == 'option' && !current_user_can( 'manage_options' ) )
771 $return = false;
772
773 // Meta is post related
774 if( $context == 'post_meta' && is_user_logged_in() ) {
775
776 // Current user must be able to edit posts
777 if( !current_user_can( 'edit_posts' ) )
778 $return = false;
779
780 // If the user can't edit others posts the current post must be his/hers
781 elseif( !current_user_can( 'edit_others_posts' ) ) {
782
783 $current_post = get_post( $id );
784 $current_user = wp_get_current_user();
785
786 if( $current_user->ID != $current_post->post_author )
787 $return = false;
788
789 }
790
791 }
792
793 // Return
794 if( $return )
795 return $return;
796 else
797 return array( 'error' => __( 'You are not allowed to do this.', 'profile-builder' ), 'errorfields' => '' );
798
799 }
800
801
802 /* ajax add a reccord to the meta */
803 function wck_add_meta(){
804 check_ajax_referer( "wck-add-meta" );
805 if( !empty( $_POST['meta'] ) )
806 $meta = sanitize_text_field( $_POST['meta'] );
807 else
808 $meta = '';
809 if( !empty( $_POST['id'] ) )
810 $id = absint($_POST['id']);
811 else
812 $id = '';
813 if( !empty( $_POST['values'] ) && is_array( $_POST['values'] ) )
814 $values = array_map( 'wppb_sanitize_value', $_POST['values'] );//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
815 else
816 $values = array();
817
818 // Security checks
819 if( true !== ( $error = self::wck_verify_user_capabilities( $this->args['context'], $meta, $id ) ) ) {
820 header( 'Content-type: application/json' );
821 die( json_encode( $error ) );
822 }
823
824 $values = apply_filters( "wck_add_meta_filter_values_{$meta}", $values );
825
826 /* check required fields */
827 $errors = self::wck_test_required( $this->args['meta_array'], $meta, $values, $id );
828 if( $errors != '' ){
829 header( 'Content-type: application/json' );
830 die( json_encode( $errors ) );
831 }
832
833
834 if( $this->args['context'] == 'post_meta' )
835 $results = get_post_meta($id, $meta, true);
836 else if ( $this->args['context'] == 'option' )
837 $results = get_option( apply_filters( 'wck_option_meta' , $meta, $values ) );
838
839 /* we need an array here */
840 if( empty( $results ) && !is_array( $results ) )
841 $results = array();
842
843 /* for single metaboxes owerwrite entries each time so we have a maximum of one */
844 if( $this->args['single'] )
845 $results = array( $values );
846 else
847 $results[] = $values;
848
849 /* make sure this does not output anything so it won't break the json response below
850 will keep it do_action for compatibility reasons
851 */
852 ob_start();
853 do_action( 'wck_before_add_meta', $meta, $id, $values );
854 $wck_before_add_meta = ob_get_clean(); //don't output it
855
856
857 if( $this->args['context'] == 'post_meta' )
858 update_post_meta($id, $meta, $results);
859 else if ( $this->args['context'] == 'option' )
860 update_option( apply_filters( 'wck_option_meta' , $meta, $results ), wp_unslash( $results ) );
861
862 /* if unserialize_fields is true add for each entry separate post meta for every element of the form */
863 if( $this->args['unserialize_fields'] && $this->args['context'] == 'post_meta' ){
864
865 $meta_suffix = count( $results );
866 if( !empty( $values ) ){
867 foreach( $values as $name => $value ){
868 update_post_meta($id, $meta.'_'.$name.'_'.$meta_suffix, $value);
869 }
870 }
871 }
872
873 $entry_list = $this->wck_refresh_list( $meta, $id );
874 $add_form = $this->wck_add_form( $meta, $id );
875
876 header( 'Content-type: application/json' );
877 die( json_encode( array( 'entry_list' => $entry_list, 'add_form' => $add_form ) ) );
878
879 }
880
881 /* ajax update a reccord in the meta */
882 function wck_update_meta(){
883 check_ajax_referer( "wck-update-entry" );
884 if( !empty( $_POST['meta'] ) )
885 $meta = sanitize_text_field( $_POST['meta'] );
886 else
887 $meta = '';
888 if( !empty( $_POST['id'] ) )
889 $id = absint($_POST['id']);
890 else
891 $id = '';
892 if( isset( $_POST['element_id'] ) )
893 $element_id = absint( $_POST['element_id'] );
894 else
895 $element_id = 0;
896 if( !empty( $_POST['values'] ) && is_array( $_POST['values']) )
897 $values = array_map( 'wppb_sanitize_value', $_POST['values'] ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
898 else
899 $values = array();
900
901 // Security checks
902 if( true !== ( $error = self::wck_verify_user_capabilities( $this->args['context'], $meta, $id ) ) ) {
903 header( 'Content-type: application/json' );
904 die( json_encode( $error ) );
905 }
906
907 $values = apply_filters( "wck_update_meta_filter_values_{$meta}", $values, $element_id );
908
909 /* check required fields */
910 $errors = self::wck_test_required( $this->args['meta_array'], $meta, $values, $id );
911 if( $errors != '' ){
912 header( 'Content-type: application/json' );
913 die( json_encode( $errors ) );
914 }
915
916 if( $this->args['context'] == 'post_meta' )
917 $results = get_post_meta($id, $meta, true);
918 else if ( $this->args['context'] == 'option' )
919 $results = get_option( apply_filters( 'wck_option_meta' , $meta, $values, $element_id ) );
920
921 $results[$element_id] = $values;
922
923 /* make sure this does not output anything so it won't break the json response below
924 will keep it do_action for compatibility reasons
925 */
926 ob_start();
927 do_action( 'wck_before_update_meta', $meta, $id, $values, $element_id );
928 $wck_before_update_meta = ob_get_clean(); //don't output it
929
930
931 if( $this->args['context'] == 'post_meta' )
932 update_post_meta($id, $meta, $results);
933 else if ( $this->args['context'] == 'option' )
934 update_option( apply_filters( 'wck_option_meta' , $meta, $results, $element_id ), wp_unslash( $results ) );
935
936 /* if unserialize_fields is true update the coresponding post metas for every element of the form */
937 if( $this->args['unserialize_fields'] && $this->args['context'] == 'post_meta' ){
938
939 $meta_suffix = $element_id + 1;
940 if( !empty( $values ) ){
941 foreach( $values as $name => $value ){
942 update_post_meta($id, $meta.'_'.$name.'_'.$meta_suffix, $value);
943 }
944 }
945 }
946
947 $entry_content = $this->wck_refresh_entry( $meta, $id, $element_id );
948
949 header( 'Content-type: application/json' );
950 die( json_encode( array( 'entry_content' => $entry_content ) ) );
951 }
952
953 /* ajax to refresh the meta content | or used in other function to return the */
954 /* this is used in Repeater Fields as an ajax action so we have to keep it dual purpose */
955 function wck_refresh_list( $meta = '', $id = '' ){
956 if( isset( $_POST['meta'] ) )
957 $meta = sanitize_text_field( $_POST['meta'] );
958
959 if( isset( $_POST['id'] ) )
960 $id = absint($_POST['id']);
961
962 ob_start();
963 echo self::wck_output_meta_content($meta, $id, $this->args['meta_array']); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
964 do_action( "wck_refresh_list_{$meta}", $id );
965 $entry_list = ob_get_clean();
966
967 if( strpos( current_filter(), 'wp_ajax_wck_refresh_list') === 0 ){
968 echo $entry_list; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
969 exit;
970 }
971 else{
972 return $entry_list;
973 }
974 }
975
976 /* function that returns the content of an entry */
977 function wck_refresh_entry( $meta = '', $id = '', $element_id = '' ){
978
979 if( $this->args['context'] == 'post_meta' )
980 $results = get_post_meta($id, $meta, true);
981 else if ( $this->args['context'] == 'option' )
982 $results = get_option( apply_filters( 'wck_option_meta' , $meta, $element_id ) );
983
984 ob_start();
985 echo self::wck_output_entry_content( $meta, $id, $this->args['meta_array'], $results, $element_id ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
986 do_action( "wck_refresh_entry_{$meta}", $id );
987 $entry_content = ob_get_clean();
988
989 return $entry_content;
990 }
991
992 /* function that returns the add the form for single */
993 function wck_add_form( $meta = '', $id = '' ){
994
995 $post = get_post($id);
996
997 ob_start();
998 self::create_add_form($this->args['meta_array'], $meta, $post );
999 do_action( "wck_ajax_add_form_{$meta}", $id );
1000 $add_form = ob_get_clean();
1001
1002 return $add_form;
1003 }
1004
1005
1006 /* ajax to show the update form */
1007 function wck_show_update_form(){
1008 check_ajax_referer( "wck-edit-entry" );
1009 $meta = isset( $_POST['meta'] ) ? sanitize_text_field( $_POST['meta'] ) : '';
1010 $id = isset( $_POST['id'] ) ? absint( $_POST['id'] ) : '';
1011 $element_id = isset( $_POST['element_id'] ) ? absint( $_POST['element_id'] ) : '';
1012
1013 do_action( "wck_before_adding_form_{$meta}", $id, $element_id );
1014
1015 echo self::mb_update_form($this->args['meta_array'], $meta, $id, $element_id);//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1016
1017 do_action( "wck_after_adding_form", $meta, $id, $element_id );
1018 do_action( "wck_after_adding_form_{$meta}", $id, $element_id );
1019
1020 exit;
1021 }
1022
1023 /* ajax to remove a reccord from the meta */
1024 function wck_remove_meta(){
1025 check_ajax_referer( "wck-delete-entry" );
1026 if( !empty( $_POST['meta'] ) )
1027 $meta = sanitize_text_field( $_POST['meta'] );
1028 else
1029 $meta = '';
1030 if( !empty( $_POST['id'] ) )
1031 $id = absint( $_POST['id'] );
1032 else
1033 $id = '';
1034 if( isset( $_POST['element_id'] ) )
1035 $element_id = absint( $_POST['element_id'] );
1036 else
1037 $element_id = '';
1038
1039 // Security checks
1040 if( true !== ( $error = self::wck_verify_user_capabilities( $this->args['context'], $meta, $id ) ) ) {
1041 header( 'Content-type: application/json' );
1042 die( json_encode( $error ) );
1043 }
1044
1045 if( $this->args['context'] == 'post_meta' )
1046 $results = get_post_meta($id, $meta, true);
1047 else if ( $this->args['context'] == 'option' )
1048 $results = get_option( apply_filters( 'wck_option_meta' , $meta, $element_id ) );
1049
1050 $old_results = $results;
1051 unset($results[$element_id]);
1052 /* reset the keys for the array */
1053 $results = array_values($results);
1054
1055 /* make sure this does not output anything so it won't break the json response below
1056 will keep it do_action for compatibility reasons
1057 */
1058 ob_start();
1059 do_action( 'wck_before_remove_meta', $meta, $id, $element_id );
1060 $wck_before_remove_meta = ob_get_clean(); //don't output it
1061
1062 if( $this->args['context'] == 'post_meta' )
1063 update_post_meta($id, $meta, $results);
1064 else if ( $this->args['context'] == 'option' )
1065 update_option( apply_filters( 'wck_option_meta' , $meta, $results, $element_id ), wp_unslash( $results ) );
1066
1067
1068
1069 /* TODO: optimize so that it updates from the deleted element forward */
1070 /* if unserialize_fields is true delete the coresponding post metas */
1071 if( $this->args['unserialize_fields'] && $this->args['context'] == 'post_meta' ){
1072
1073 $meta_suffix = 1;
1074
1075 if( !empty( $results ) ){
1076 foreach( $results as $result ){
1077 foreach ( $result as $name => $value){
1078 update_post_meta($id, $meta.'_'.$name.'_'.$meta_suffix, $value);
1079 }
1080 $meta_suffix++;
1081 }
1082 }
1083
1084 if( count( $results ) == 0 )
1085 $results = $old_results;
1086
1087 if( !empty( $results ) ){
1088 foreach( $results as $result ){
1089 foreach ( $result as $name => $value){
1090 delete_post_meta( $id, $meta.'_'.$name.'_'.$meta_suffix );
1091 }
1092 break;
1093 }
1094 }
1095 }
1096
1097 $entry_list = $this->wck_refresh_list( $meta, $id );
1098 $add_form = $this->wck_add_form( $meta, $id );
1099
1100 header( 'Content-type: application/json' );
1101 die( json_encode( array( 'entry_list' => $entry_list, 'add_form' => $add_form ) ) );
1102 }
1103
1104
1105 /* ajax to reorder records */
1106 function wck_reorder_meta(){
1107 if( !empty( $_POST['meta'] ) )
1108 $meta = sanitize_text_field( $_POST['meta'] );
1109 else
1110 $meta = '';
1111 if( !empty( $_POST['id'] ) )
1112 $id = absint($_POST['id']);
1113 else
1114 $id = '';
1115 if( !empty( $_POST['values'] ) && is_array( $_POST['values'] ) )
1116 $elements_id = array_map( 'absint', $_POST['values'] );
1117 else
1118 $elements_id = array();
1119
1120 // Security checks
1121 if( true !== ( $error = self::wck_verify_user_capabilities( $this->args['context'], $meta, $id ) ) ) {
1122 header( 'Content-type: application/json' );
1123 die( json_encode( $error ) );
1124 }
1125
1126 /* make sure this does not output anything so it won't break the json response below
1127 will keep it do_action for compatibility reasons
1128 */
1129 ob_start();
1130 do_action( 'wck_before_reorder_meta', $meta, $id, $elements_id );
1131 $wck_before_reorder_meta = ob_get_clean(); //don't output it
1132
1133 if( $this->args['context'] == 'post_meta' )
1134 $results = get_post_meta($id, $meta, true);
1135 else if ( $this->args['context'] == 'option' )
1136 $results = get_option( apply_filters( 'wck_option_meta' , $meta ) );
1137
1138 $new_results = array();
1139 if( !empty( $elements_id ) ){
1140 foreach($elements_id as $element_id){
1141 $new_results[] = $results[$element_id];
1142 }
1143 }
1144
1145 $results = $new_results;
1146
1147 if( $this->args['context'] == 'post_meta' )
1148 update_post_meta($id, $meta, $results);
1149 else if ( $this->args['context'] == 'option' )
1150 update_option( apply_filters( 'wck_option_meta' , $meta, $results, $element_id ), wp_unslash( $results ) );
1151
1152
1153 /* if unserialize_fields is true reorder all the coresponding post metas */
1154 if( $this->args['unserialize_fields'] && $this->args['context'] == 'post_meta' ){
1155
1156 $meta_suffix = 1;
1157 if( !empty( $new_results ) ){
1158 foreach( $new_results as $result ){
1159 foreach ( $result as $name => $value){
1160 update_post_meta($id, $meta.'_'.$name.'_'.$meta_suffix, $value);
1161 }
1162 $meta_suffix++;
1163 }
1164 }
1165
1166 }
1167
1168 $entry_list = $this->wck_refresh_list( $meta, $id );
1169 header( 'Content-type: application/json' );
1170 die( json_encode( array( 'entry_list' => $entry_list ) ) );
1171 }
1172
1173 /**
1174 * Function that saves the entries for single forms on posts(no options). It is hooke on the 'save_post' hook
1175 * It is executed on each WCK object instance so we need to restrict it on only the ones that are present for that post
1176 */
1177 function wck_save_single_metabox( $post_id, $post ){
1178 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
1179 return $post_id;
1180
1181 /* only go through for metaboxes defined for this post type */
1182 if( get_post_type( $post_id ) != $this->args['post_type'] )
1183 return $post_id;
1184
1185 // Check the user's permissions.
1186 if ( isset( $_POST['post_type'] ) && 'page' == $_POST['post_type'] ) {
1187 if ( ! current_user_can( 'edit_page', $post_id ) ) {
1188 return $post_id;
1189 }
1190 } else {
1191 if ( ! current_user_can( 'edit_posts', $post_id ) ) {
1192 return $post_id;
1193 }
1194 }
1195
1196 if( !empty( $_POST ) ){
1197 /* for single metaboxes we save a hidden input that contains the meta_name attr as a key so we need to search for it */
1198 foreach( $_POST as $request_key => $request_value ){
1199 if( strpos( $request_key, '_wckmetaname_' ) !== false && strpos( $request_key, '#wck' ) !== false ){
1200 /* found it so now retrieve the meta_name from the key formatted _wckmetaname_actuaname#wck */
1201 $request_key = str_replace( '_wckmetaname_', '', $request_key );
1202 $meta_name = sanitize_text_field( str_replace( '#wck', '', $request_key ) );
1203 /* we have it so go through only on the WCK object instance that has this meta_name */
1204 if( $this->args['meta_name'] == $meta_name ){
1205
1206 /* get the meta values from the $_POST and store them in an array */
1207 $meta_values = array();
1208 if( !empty( $this->args['meta_array'] ) ){
1209 foreach ($this->args['meta_array'] as $meta_field){
1210 /* in the $_POST the names for the fields are prefixed with the meta_name for the single metaboxes in case there are multiple metaboxes that contain fields wit hthe same name */
1211 $single_field_name = $this->args['meta_name'] .'_'. Wordpress_Creation_Kit_PB::wck_generate_slug( $meta_field['title'],$meta_field );
1212 if (isset($_POST[$single_field_name])) {
1213 /* checkbox needs to be stored as string not array */
1214 if( $meta_field['type'] == 'checkbox' )
1215 $_POST[$single_field_name] = implode( ', ', $_POST[$single_field_name] );//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1216
1217 $meta_values[Wordpress_Creation_Kit_PB::wck_generate_slug( $meta_field['title'], $meta_field )] = wppb_sanitize_value( $_POST[$single_field_name] ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1218 }
1219 else
1220 $meta_values[Wordpress_Creation_Kit_PB::wck_generate_slug( $meta_field['title'], $meta_field )] = '';
1221 }
1222 }
1223
1224 /* test if we have errors for the required fields */
1225 $errors = self::wck_test_required( $this->args['meta_array'], $meta_name, $meta_values, $post_id );
1226 if( !empty( $errors ) ){
1227 /* if we have errors then add them in the global. We do this so we get all errors from all single metaboxes that might be on that page */
1228 global $wck_single_forms_errors;
1229 if( !empty( $errors['errorfields'] ) ){
1230 foreach( $errors['errorfields'] as $key => $field_name ){
1231 $errors['errorfields'][$key] = $this->args['meta_name']. '_' .$field_name;
1232 }
1233 }
1234 $wck_single_forms_errors[] = $errors;
1235 }
1236 else {
1237 /* no errors so we can save */
1238 update_post_meta($post_id, $meta_name, array($meta_values));
1239 /* handle unserialized fields */
1240 if ($this->args['unserialize_fields']) {
1241 if (!empty($this->args['meta_array'])) {
1242 foreach ($this->args['meta_array'] as $meta_field) {
1243 update_post_meta($post_id, $meta_name . '_' . Wordpress_Creation_Kit_PB::wck_generate_slug( $meta_field['title'], $meta_field ) . '_1', array_map( 'wppb_sanitize_value', $_POST[$this->args['meta_name'] . '_' . Wordpress_Creation_Kit_PB::wck_generate_slug( $meta_field['title'], $meta_field )] ) ); //phpcs:ignore
1244 }
1245 }
1246 }
1247 }
1248 break;
1249 }
1250 }
1251 }
1252 }
1253 }
1254
1255 /**
1256 * Function that checks if we have any errors in the required fields from the single metaboxes. It is executed on 'wp_insert_post' hook
1257 * that comes after 'save_post' so we should have the global errors by now. If we have errors perform a redirect and add the error messages and error fields
1258 * in the url
1259 */
1260 function wck_single_metabox_redirect_if_errors( $post_id, $post ){
1261 global $wck_single_forms_errors;
1262 if( !empty( $wck_single_forms_errors ) ) {
1263 $error_messages = '';
1264 $error_fields = '';
1265 foreach( $wck_single_forms_errors as $wck_single_forms_error ){
1266 $error_messages .= $wck_single_forms_error['error'];
1267 $error_fields .= implode( ',', $wck_single_forms_error['errorfields'] ).',';
1268 }
1269 if( isset( $_SERVER["HTTP_REFERER"] ) )
1270 wp_safe_redirect( add_query_arg( array( 'wckerrormessages' => base64_encode( urlencode( $error_messages ) ), 'wckerrorfields' => base64_encode( urlencode( $error_fields ) ) ), esc_url_raw( $_SERVER["HTTP_REFERER"] ) ) );
1271
1272 exit;
1273 }
1274 }
1275
1276 /** Function that displays the error messages, if we have any, as js alerts and marks the fields with red
1277 */
1278 function wck_single_metabox_errors_display(){
1279 /* only execute for the WCK objects defined for the current post type */
1280 global $post;
1281 if( get_post_type( $post ) != $this->args['post_type'] )
1282 return;
1283
1284 /* and only do it once */
1285 global $allready_saved;
1286 if( isset( $allready_saved ) && $allready_saved == true )
1287 return;
1288 $allready_saved = true;
1289
1290 /* mark the fields */
1291 if( isset( $_GET['wckerrorfields'] ) && !empty( $_GET['wckerrorfields'] ) ){
1292 echo '<script type="text/javascript">';
1293 $field_names = explode( ',', sanitize_text_field( urldecode( base64_decode( $_GET['wckerrorfields'] ) ) ) );//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1294 if( !empty( $field_names ) ) {
1295 foreach ($field_names as $field_name) {
1296 echo "jQuery( '.field-label[for=\"" . esc_js($field_name) . "\"]' ).addClass('error');";
1297 }
1298 }
1299 echo '</script>';
1300 }
1301
1302 /* alert the error messages */
1303 if( isset( $_GET['wckerrormessages'] ) ){
1304 echo '<script type="text/javascript">alert("'. str_replace( '%0A', '\n', esc_js( urldecode( base64_decode( $_GET['wckerrormessages'] ) ) ) ) .'")</script>';//phpcs:ignore
1305 }
1306 }
1307
1308
1309 /**
1310 * The function used to generate slugs in WCK
1311 *
1312 * @since 1.1.1
1313 *
1314 * @param string $string The input string from which we generate the slug
1315 * @return string $slug The henerated slug
1316 */
1317 static function wck_generate_slug( $string, $details = array() ){
1318 if( !empty( $details['slug'] ) )
1319 $slug = $details['slug'];
1320 else
1321 $slug = rawurldecode( sanitize_title_with_dashes( remove_accents( $string ) ) );
1322 return $slug;
1323 }
1324
1325 static function wck_strip_script_tags(){
1326
1327 }
1328
1329 static function wck_generate_select_option($option, $values, $i, $current_value){
1330
1331 $disabled = '';
1332
1333 if( is_array( $option ) ){
1334
1335 if( !empty( $option['field_name'] ) ){
1336 $label = $option['field_name'];
1337
1338 if( !empty( $values ) )
1339 $value_attr = $values[$i];
1340 else
1341 $value_attr = $option;
1342
1343 if( !empty( $option['disabled'] ) && $option['disabled'] == true ){
1344 $disabled = ' disabled';
1345 }
1346 }
1347
1348 } elseif( strpos( $option, '%' ) === false ){
1349 $label = $option;
1350 if( !empty( $values ) )
1351 $value_attr = $values[$i];
1352 else
1353 $value_attr = $option;
1354 } else {
1355 $option_parts = explode( '%', $option );
1356 if( !empty( $option_parts ) ){
1357 if( empty( $option_parts[0] ) && count( $option_parts ) == 3 ){
1358 $label = $option_parts[1];
1359 if( !empty( $values ) )
1360 $value_attr = $values[$i];
1361 else
1362 $value_attr = $option_parts[2];
1363 }
1364 else{
1365 $label = $option;
1366 if( !empty( $values ) )
1367 $value_attr = $values[$i];
1368 else
1369 $value_attr = $option;
1370 }
1371 }
1372 }
1373
1374 // title is set only for disabled options to let users know those fields are available in a paid version
1375 if( !empty( $disabled ) ){
1376 if( isset( $value_attr['field_name'] ) && $value_attr['field_name'] == 'Subscription Plans' )
1377 $title = esc_attr( __( 'Install the free Paid Member Subscriptions plugin to get access this field.', 'profile-builder' ) );
1378 else
1379 $title = esc_attr( __( 'This field is available in our paid plans.', 'profile-builder' ) );
1380 }
1381
1382 if( isset( $value_attr['field_name'] ) )
1383 $optionOutput = '<option value="" '. esc_attr( $disabled ) . ( !empty( $disabled ) ? ' title="'. $title .'"' : '' ) . ' >'. esc_html( $label ) .'</option>';
1384 else
1385 $optionOutput = '<option value="'. esc_attr( $value_attr ) .'" '. selected( $value_attr, $current_value, false ) . ( !empty( $disabled ) ? ' title="'. $title .'"' : '' ) . ' >'. esc_html( $label ) .'</option>';
1386
1387 return $optionOutput;
1388 }
1389
1390 static function wck_is_multi($a) {
1391 foreach ($a as $v) {
1392 if (is_array($v)) return true;
1393 }
1394 return false;
1395 }
1396 }
1397
1398
1399 /*
1400 Helper class that creates admin menu pages ( both top level menu pages and submenu pages )
1401 Default Usage:
1402
1403 $args = array(
1404 'page_type' => 'menu_page',
1405 'page_title' => '',
1406 'menu_title' => '',
1407 'capability' => '',
1408 'menu_slug' => '',
1409 'icon_url' => '',
1410 'position' => '',
1411 'parent_slug' => ''
1412 );
1413
1414 'page_type' (string) (required) The type of page you want to add. Possible values: 'menu_page', 'submenu_page'
1415 'page_title' (string) (required) The text to be displayed in the title tags and header of
1416 the page when the menu is selected
1417 'menu_title' (string) (required) The on-screen name text for the menu
1418 'capability' (string) (required) The capability required for this menu to be displayed to
1419 the user.
1420 'menu_slug' (string) (required) The slug name to refer to this menu by (should be unique
1421 for this menu).
1422 'icon_url' (string) (optional for 'page_type' => 'menu_page') The url to the icon to be used for this menu.
1423 This parameter is optional. Icons should be fairly small, around 16 x 16 pixels
1424 for best results.
1425 'position' (integer) (optional for 'page_type' => 'menu_page') The position in the menu order this menu
1426 should appear.
1427 By default, if this parameter is omitted, the menu will appear at the bottom
1428 of the menu structure. The higher the number, the lower its position in the menu.
1429 WARNING: if 2 menu items use the same position attribute, one of the items may be
1430 overwritten so that only one item displays!
1431 'parent_slug' (string) (required for 'page_type' => 'submenu_page' ) The slug name for the parent menu
1432 (or the file name of a standard WordPress admin page) For examples see http://codex.wordpress.org/Function_Reference/add_submenu_page $parent_slug parameter
1433 'priority' (int) (optional) How important your function is. Alter this to make your function
1434 be called before or after other functions. The default is 10, so (for example) setting it to 5 would make it run earlier and setting it to 12 would make it run later.
1435
1436 public $hookname ( for required for 'page_type' => 'menu_page' ) string used internally to
1437 track menu page callbacks for outputting the page inside the global $menu array
1438 ( for required for 'page_type' => 'submenu_page' ) The resulting page's hook_suffix,
1439 or false if the user does not have the capability required.
1440 */
1441
1442 class WCK_Page_Creator_PB{
1443
1444 private $defaults = array(
1445 'page_type' => 'menu_page',
1446 'page_title' => '',
1447 'menu_title' => '',
1448 'capability' => '',
1449 'menu_slug' => '',
1450 'icon_url' => '',
1451 'position' => '',
1452 'parent_slug' => '',
1453 'priority' => 10,
1454 'network_page' => false
1455 );
1456 private $args;
1457 public $hookname;
1458
1459
1460 /* Constructor method for the class. */
1461 function __construct( $args ) {
1462
1463 /* Global that will hold all the arguments for all the menu pages */
1464 global $wck_pages;
1465
1466 /* Merge the input arguments and the defaults. */
1467 $this->args = wp_parse_args( $args, $this->defaults );
1468
1469 /* Add the settings for this page to the global object */
1470 $wck_pages[$this->args['page_title']] = $this->args;
1471
1472 if( !$this->args['network_page'] ){
1473 /* Hook the page function to 'admin_menu'. */
1474 add_action( 'admin_menu', array( &$this, 'wck_page_init' ), $this->args['priority'] );
1475 }
1476 else{
1477 /* Hook the page function to 'admin_menu'. */
1478 add_action( 'network_admin_menu', array( &$this, 'wck_page_init' ), $this->args['priority'] );
1479 }
1480 }
1481
1482 /**
1483 * Function that creates the admin page
1484 */
1485 function wck_page_init(){
1486 global $pb_wck_pages_hooknames;
1487
1488 /* don't add the page at all if the user doesn't meet the capabilities */
1489 if( !empty( $this->args['capability'] ) ){
1490 if( !current_user_can( $this->args['capability'] ) )
1491 return;
1492 }
1493
1494 /* Create the page using either add_menu_page or add_submenu_page functions depending on the 'page_type' parameter. */
1495 if( $this->args['page_type'] == 'menu_page' ){
1496 $this->hookname = add_menu_page( $this->args['page_title'], $this->args['menu_title'], $this->args['capability'], $this->args['menu_slug'], array( &$this, 'wck_page_template' ), $this->args['icon_url'], $this->args['position'] );
1497
1498 $pb_wck_pages_hooknames[$this->args['menu_slug']] = $this->hookname;
1499 }
1500 else if( $this->args['page_type'] == 'submenu_page' ){
1501 $this->hookname = add_submenu_page( $this->args['parent_slug'], $this->args['page_title'], $this->args['menu_title'], $this->args['capability'], $this->args['menu_slug'], array( &$this, 'wck_page_template' ) );
1502
1503 $pb_wck_pages_hooknames[$this->args['menu_slug']] = $this->hookname;
1504 }
1505
1506 do_action( 'WCK_Page_Creator_PB_after_init', $this->hookname );
1507
1508 /* Create a hook for adding meta boxes. */
1509 add_action( "load-{$this->hookname}", array( &$this, 'wck_settings_page_add_meta_boxes' ) );
1510 /* Load the JavaScript needed for the screen. */
1511 add_action( 'admin_enqueue_scripts', array( &$this, 'wck_page_enqueue_scripts' ) );
1512 add_action( "admin_head-{$this->hookname}", array( &$this, 'wck_page_load_scripts' ) );
1513 }
1514
1515 /**
1516 * Do action 'add_meta_boxes'. This hook isn't executed by default on a admin page so we have to add it.
1517 */
1518 function wck_settings_page_add_meta_boxes() {
1519 global $post;
1520 do_action( 'add_meta_boxes', $this->hookname, $post );
1521 }
1522
1523 /**
1524 * Loads the JavaScript files required for managing the meta boxes on the theme settings
1525 * page, which allows users to arrange the boxes to their liking.
1526 *
1527 * @global string $bareskin_settings_page. The global setting page (returned by add_theme_page in function
1528 * bareskin_settings_page_init ).
1529 * @since 1.0.0
1530 * @param string $hook The current page being viewed.
1531 */
1532 function wck_page_enqueue_scripts( $hook ) {
1533 if ( $hook == $this->hookname ) {
1534 wp_enqueue_script( 'common' );
1535 wp_enqueue_script( 'wp-lists' );
1536 wp_enqueue_script( 'postbox' );
1537 }
1538 }
1539
1540 /**
1541 * Loads the JavaScript required for toggling the meta boxes on the theme settings page.
1542 *
1543 * @global string $bareskin_settings_page. The global setting page (returned by add_theme_page in function
1544 * bareskin_settings_page_init ).
1545 * @since 1.0.0
1546 */
1547 function wck_page_load_scripts() {
1548 ?>
1549 <script type="text/javascript">
1550 //<![CDATA[
1551 jQuery(document).ready( function($) {
1552 $('.if-js-closed').removeClass('if-js-closed').addClass('closed');
1553 postboxes.add_postbox_toggles( '<?php echo esc_js( $this->hookname ); ?>' );
1554 });
1555 //]]>
1556 </script><?php
1557 }
1558
1559 /**
1560 * Outputs default template for the page. It contains placeholders for metaboxes. It also
1561 * provides two action hooks 'wck_before_meta_boxes' and 'wck_after_meta_boxes'.
1562 */
1563 function wck_page_template(){
1564 ?>
1565 <div class="wrap">
1566
1567 <?php if( !empty( $this->args['page_icon'] ) ): ?>
1568 <div id="<?php echo esc_attr( $this->args['menu_slug'] );//phpcs:ignore ?>-icon" style="background: url('<?php echo $this->args['page_icon']; ?>') no-repeat;" class="icon32">
1569 <br/>
1570 </div>
1571 <?php endif; ?>
1572
1573 <h2><?php echo esc_html( $this->args['page_title'] ) ?></h2>
1574
1575 <div id="poststuff">
1576
1577 <?php wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false ); ?>
1578 <?php wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false ); ?>
1579
1580 <?php do_action( 'wck_before_meta_boxes', $this->hookname ); ?>
1581
1582 <div class="metabox-holder">
1583 <div class="wck-post-body">
1584 <div class="post-box-container column-1 normal">
1585 <?php do_action( 'wck_before_column1_metabox_content', $this->hookname ); ?>
1586 <?php do_meta_boxes( $this->hookname, 'normal', null ); ?>
1587 <?php do_action( 'wck_after_column1_metabox_content', $this->hookname ); ?>
1588 </div>
1589 <div class="post-box-container column-3 advanced">
1590 <?php do_action( 'wck_before_column3_metabox_content', $this->hookname ); ?>
1591 <?php do_meta_boxes( $this->hookname, 'advanced', null ); ?>
1592 <?php do_action( 'wck_after_column3_metabox_content', $this->hookname ); ?>
1593 </div>
1594 </div>
1595 <div class="post-box-container column-2 side"><?php do_meta_boxes( $this->hookname, 'side', null ); ?></div>
1596
1597 </div>
1598
1599 <?php do_action( 'wck_after_meta_boxes', $this->hookname ); ?>
1600
1601 </div><!-- #poststuff -->
1602
1603 </div><!-- .wrap -->
1604 <?php
1605 }
1606 }
1607
1608
1609
1610 ?>
1611