/** * Get the purpose of the page that is being displayed, depending on provided data and user capabilities. * * @return string 'add'|'edit'|'view'. Note that 'edit' is also returned when the new group is about to be created, * but it doesn't exist yet (has no ID). */ public function get_page_purpose() { $role_type = 'term-field'; $group_id = wpcf_getget('group_id'); $is_group_specified = 0 != $group_id; if ($is_group_specified) { if (WPCF_Roles::user_can_edit($role_type, array('id' => $group_id))) { $purpose = 'edit'; } else { $purpose = 'view'; } } else { if ($this->is_there_something_to_save()) { if (WPCF_Roles::user_can_create($role_type)) { // We're creating a group now, the page will be used for editing it. $purpose = 'edit'; } else { $purpose = 'view'; } } else { if (WPCF_Roles::user_can_create($role_type)) { $purpose = 'add'; } else { $purpose = 'view'; // Invalid state } } } return $purpose; }
/** * Call this only if you are actually showing the page. */ public function initialize() { $page_hook = wpcf_admin_add_submenu_page(array('menu_title' => $this->get_title(), 'function' => array($this, 'page_handler'), 'capability_filter' => 'wpcf_tfc_view'), wpcf_getget('page')); // I hate having to do this. Refactor! require_once WPCF_INC_ABSPATH . '/fields.php'; wpcf_fields_contol_common_resources(); add_action("load-{$page_hook}", array($this, 'add_screen_options')); }
/** * Add all Types submenus and jumpstart a specific page controller if needed. * * Toolset shared menu usage is described here: * @link https://git.onthegosystems.com/toolset/toolset-common/wikis/toolset-shared-menu * * @param array $pages Array of menu item definitions. * @return array Updated item definition array. * @since 2.0 */ public function on_admin_menu($pages) { // Add legacy pages $pages = wpcf_admin_toolset_register_menu_pages($pages); $page_name = sanitize_text_field(wpcf_getget('page')); if (!empty($page_name)) { $pages = $this->maybe_add_ondemand_submenu($pages, $page_name); } return $pages; }
/** * Call this only if you are actually showing the page. */ public function initialize() { $hook = wpcf_admin_add_submenu_page(array('menu_title' => $this->get_menu_title(), 'function' => array($this, 'page_handler'), 'capability' => WPCF_TERM_FIELD_EDIT), wpcf_getget('page')); $load_page_action = 'load-' . $hook; // Prepare form, which includes saving data and optionally redirecting to the edit page with group ID // as GET parameter. That's why it must be executed earlier than as a menu page callback. add_action($load_page_action, array($this, 'prepare_form_maybe_redirect')); // This one handles enqueuing script and styles. Originally it is meant for post fields and it also probably // does some things that are not needed now. add_action($load_page_action, 'wpcf_admin_enqueue_group_edit_page_assets'); wpcf_admin_plugin_help($hook, self::PAGE_NAME); }
function prepare_items() { $per_page = $this->get_items_per_page(WPCF_Page_Control_Termmeta::SCREEN_OPTION_PER_PAGE_NAME, 10); $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array($columns, $hidden, $sortable); $this->process_bulk_action(); $search_string = mb_strtolower(trim(wpcf_getpost('s'))); $query_args = array('filter' => 'all', 'orderby' => sanitize_text_field(wpcf_getget('orderby', 'name')), 'order' => sanitize_text_field(wpcf_getget('order', 'asc')), 'search' => $search_string); $definitions = WPCF_Field_Term_Definition_Factory::get_instance()->query_definitions($query_args); $current_page = $this->get_pagenum(); $total_items = count($definitions); $definitions = array_slice($definitions, ($current_page - 1) * $per_page, $per_page); $this->items = $definitions; $this->set_pagination_args(array('total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil($total_items / $per_page))); }
/** * Add help tabs to current screen. * * Used as a hook for 'contextual_help_hook' in the shared Toolset menu. * * @since 2.0 */ public function add_help_tab() { $screen = get_current_screen(); if (is_null($screen)) { return; } $current_page = sanitize_text_field(wpcf_getget('page', null)); if (null == $current_page) { return; } $help_content = $this->get_help_content($current_page); if (null == $help_content) { return; } $args = array('title' => wpcf_getarr($help_content, 'title'), 'id' => 'wpcf', 'content' => wpcf_getarr($help_content, 'content'), 'callback' => false); $screen->add_help_tab($args); $this->add_need_help_tab(); }
function prepare_items() { $per_page = $this->get_items_per_page(WPCF_Page_Listing_Termmeta::SCREEN_OPTION_PER_PAGE_NAME, WPCF_Page_Listing_Termmeta::SCREEN_OPTION_PER_PAGE_DEFAULT_VALUE); $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array($columns, $hidden, $sortable); $this->process_bulk_action(); $search_string = isset($_POST['s']) ? mb_strtolower(trim($_POST['s'])) : null; $query_args = array('orderby' => sanitize_text_field(wpcf_getget('orderby', 'post_title')), 'order' => sanitize_text_field(wpcf_getget('order', 'asc'))); $groups = WPCF_Field_Group_Term_Factory::get_instance()->query_groups($query_args, $search_string); /** * REQUIRED for pagination. Let's figure out what page the user is currently * looking at. We'll need this later, so you should always include it in * your own package classes. */ $current_page = $this->get_pagenum(); /** * REQUIRED for pagination. Let's check how many items are in our data array. * In real-world use, this would be the total number of items in your database, * without filtering. We'll need this later, so you should always include it * in your own package classes. */ $total_items = count($groups); /** * The WP_List_Table class does not handle pagination for us, so we need * to ensure that the data is trimmed to only the current page. We can use * array_slice() to */ $groups = array_slice($groups, ($current_page - 1) * $per_page, $per_page); /** * REQUIRED. Now we can add our *sorted* data to the items property, where * it can be used by the rest of the class. */ $this->items = $groups; /** * REQUIRED. We also have to register our pagination options & calculations. */ $this->set_pagination_args(array('total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil($total_items / $per_page))); }
/** * Add/edit form */ public function form() { $this->save(); // Flush rewrite rules if we're asked to do so. // // This must be done after all post types and taxonomies are registered, and they can be registered properly // only on 'init'. So after making changes, we need to reload the page and THEN flush. if ('1' == wpcf_getget('flush', '0')) { flush_rewrite_rules(); } global $wpcf; $id = false; $update = false; if (isset($_GET[$this->get_id])) { $id = sanitize_text_field($_GET[$this->get_id]); } elseif (isset($_POST[$this->get_id])) { $id = sanitize_text_field($_POST[$this->get_id]); } /** * get current post type */ require_once WPCF_INC_ABSPATH . '/classes/class.types.admin.post-type.php'; $wpcf_post_type = new Types_Admin_Post_Type(); $custom_post_type = $wpcf_post_type->get_post_type($id); if (empty($custom_post_type)) { wpcf_admin_message(__('Please save new Post Type first.', 'wpcf'), 'error'); die; } $this->ct = $custom_post_type; $current_user_can_edit = WPCF_Roles::user_can_edit('custom-post-type', $this->ct); /** * sanitize _builtin */ if (!isset($this->ct['_builtin'])) { $this->ct['_builtin'] = false; } /** * fix taxonomies assigment for builitin post types */ if ($this->ct['_builtin']) { $taxonomies = get_taxonomies('', 'objects'); foreach ($taxonomies as $slug => $tax) { foreach ($tax->object_type as $post_slug) { if ($this->ct['slug'] == $post_slug) { $this->ct['taxonomies'][$slug] = 1; } } } } $form = $this->prepare_screen(); if ($current_user_can_edit && $this->ct['update']) { $form['id'] = array('#type' => 'hidden', '#value' => $id, '#name' => 'ct[wpcf-post-type]', '_builtin' => true); /** * update Taxonomy too */ $custom_taxonomies = get_option(WPCF_OPTION_NAME_CUSTOM_TAXONOMIES, array()); foreach ($custom_taxonomies as $slug => $data) { if (!array_key_exists('supports', $data)) { continue; } if (!array_key_exists($id, $data['supports'])) { continue; } if (array_key_exists('taxonomies', $this->ct) && array_key_exists($slug, $this->ct['taxonomies'])) { continue; } unset($custom_taxonomies[$slug]['supports'][$id]); } update_option(WPCF_OPTION_NAME_CUSTOM_TAXONOMIES, $custom_taxonomies); } /* * menu icon */ switch ($this->ct['slug']) { case 'page': $menu_icon = 'admin-page'; break; case 'attachment': $menu_icon = 'admin-media'; break; default: $menu_icon = isset($this->ct['icon']) && !empty($this->ct['icon']) ? $this->ct['icon'] : 'admin-post'; break; } /** * post icon field */ $form['icon'] = array('#type' => 'hidden', '#name' => 'ct[icon]', '#value' => $menu_icon, '#id' => 'wpcf-types-icon'); $form['form-open'] = array('#type' => 'markup', '#markup' => sprintf('<div id="post-body-content" class="%s">', $current_user_can_edit ? '' : 'wpcf-types-read-only'), '_builtin' => true); $form['table-1-open'] = array('#type' => 'markup', '#markup' => '<table id="wpcf-types-form-name-table" class="wpcf-types-form-table widefat js-wpcf-slugize-container"><thead><tr><th colspan="2">' . __('Post Type name and description', 'wpcf') . '</th></tr></thead><tbody>', '_builtin' => true); $table_row = '<tr><td><LABEL></td><td><ERROR><BEFORE><ELEMENT><AFTER></td></tr>'; $form['name'] = array('#type' => 'textfield', '#name' => 'ct[labels][name]', '#title' => __('Post Type name plural', 'wpcf') . ' (<strong>' . __('required', 'wpcf') . '</strong>)', '#description' => '<strong>' . __('Enter in plural!', 'wpcf') . '.', '#value' => isset($this->ct['labels']['name']) ? $this->ct['labels']['name'] : '', '#validate' => array('required' => array('value' => 'true')), '#pattern' => $table_row, '#inline' => true, '#id' => 'name-plural', '#attributes' => array('data-wpcf_warning_same_as_slug' => $wpcf->post_types->message('warning_singular_plural_match'), 'data-wpcf_warning_same_as_slug_ignore' => $wpcf->post_types->message('warning_singular_plural_match_ignore'), 'placeholder' => __('Enter Post Type name plural', 'wpcf'), 'class' => 'large-text'), '_builtin' => true); $form['name-singular'] = array('#type' => 'textfield', '#name' => 'ct[labels][singular_name]', '#title' => __('Post Type name singular', 'wpcf') . ' (<strong>' . __('required', 'wpcf') . '</strong>)', '#description' => '<strong>' . __('Enter in singular!', 'wpcf') . '</strong><br />' . '.', '#value' => isset($this->ct['labels']['singular_name']) ? $this->ct['labels']['singular_name'] : '', '#validate' => array('required' => array('value' => 'true')), '#pattern' => $table_row, '#inline' => true, '#id' => 'name-singular', '#attributes' => array('placeholder' => __('Enter Post Type name singular', 'wpcf'), 'class' => 'js-wpcf-slugize-source large-text'), '_builtin' => true); /** * IF isset $_POST['slug'] it means form is not submitted */ $attributes = array(); if (!empty($_POST['ct']['slug'])) { $reserved = wpcf_is_reserved_name(sanitize_text_field($_POST['ct']['slug']), 'post_type'); if (is_wp_error($reserved)) { $attributes = array('class' => 'wpcf-form-error', 'onclick' => 'jQuery(this).removeClass(\'wpcf-form-error\');'); } } $form['slug'] = array('#type' => 'textfield', '#name' => 'ct[slug]', '#title' => __('Slug', 'wpcf') . ' (<strong>' . __('required', 'wpcf') . '</strong>)', '#value' => isset($this->ct['slug']) ? $this->ct['slug'] : '', '#pattern' => $table_row, '#inline' => true, '#validate' => array('required' => array('value' => 'true'), 'nospecialchars' => array('value' => 'true'), 'maxlength' => array('value' => '20')), '#attributes' => $attributes + array('maxlength' => '20', 'placeholder' => __('Enter Post Type slug', 'wpcf'), 'class' => 'js-wpcf-slugize large-text'), '#id' => 'slug', '_builtin' => true); // disable for inbuilt if ($this->ct['_builtin']) { $form['slug']['#disable'] = 1; $form['slug']['#pattern'] = '<tr><td><LABEL></td><td><ERROR><BEFORE><ELEMENT><DESCRIPTION><AFTER></td></tr>'; $form['slug']['#description'] = __('This option is not available for built-in post types.', 'wpcf'); } $form['description'] = array('#type' => 'textarea', '#name' => 'ct[description]', '#title' => __('Description', 'wpcf'), '#value' => isset($this->ct['description']) ? $this->ct['description'] : '', '#attributes' => array('rows' => 4, 'cols' => 60, 'placeholder' => __('Enter Post Type description', 'wpcf'), 'class' => 'hidden js-wpcf-description'), '#pattern' => $table_row, '#inline' => true, '#after' => sprintf('<a class="js-wpcf-toggle-description hidden" href="#">%s</a>', __('Add description', 'wpcf'))); /** * icons only for version 3.8 up */ global $wp_version; if (version_compare('3.8', $wp_version) < 1) { $form['choose-icon'] = array('#name' => 'choose-icon', '#type' => 'button', '#value' => esc_attr__('Change icon', 'wpcf'), '#inline' => true, '#title' => __('Icon', 'wpcf'), '#pattern' => '<tr><td><LABEL></td><td><ERROR><BEFORE><ELEMENT><DESCRIPTION><AFTER></td></tr>', '#attributes' => array('data-wpcf-nonce' => wp_create_nonce('post-type-dashicons-list'), 'data-wpcf-post-type' => esc_attr($this->ct['slug']), 'data-wpcf-message-loading' => esc_attr__('Please Wait, Loading…', 'wpcf'), 'data-wpcf-title' => esc_attr__('Choose icon', 'wpcf'), 'data-wpcf-cancel' => esc_attr__('Cancel', 'wpcf'), 'data-wpcf-value' => esc_attr($menu_icon), 'class' => 'js-wpcf-choose-icon'), '#before' => sprintf('<div class="wpcf-types-menu-image dashicons-before dashicons-%s"><br></div>', esc_attr($menu_icon))); /** * clear ability to change for builitin post types */ if ($this->ct['_builtin']) { $form['choose-icon']['#disable'] = 1; $form['choose-icon']['#description'] = __('This option is not available for built-in post types.', 'wpcf'); } } $form['table-1-close'] = array('#type' => 'markup', '#markup' => '</tbody></table>', '_builtin' => true); $form['box-1-close'] = array('#type' => 'markup', '#markup' => '</div>', '_builtin' => true); /** * return form if current_user_can edit */ if ($current_user_can_edit) { return $form; } return wpcf_admin_common_only_show($form); }
protected function button_add_new($clasess = array()) { $clasess[] = 'wpcf-fields-add-new'; $clasess[] = 'js-wpcf-fields-add-new'; return array('fields-button-add-' . rand() => array('#type' => 'button', '#value' => '<span class="dashicons dashicons-plus"></span> ' . __('Add New Field', 'wpcf'), '#attributes' => array('class' => esc_attr(implode(' ', $clasess)), 'data-wpcf-dialog-title' => esc_attr__('Add New Field', 'wpcf'), 'data-wpcf-id' => esc_attr($this->ct['id']), 'data-wpcf-message-loading' => esc_attr__('Please Wait, Loading…', 'wpcf'), 'data-wpcf-nonce' => wp_create_nonce('wpcf-edit-' . $this->ct['id']), 'data-wpcf-type' => $this->type, 'data-wpcf-page' => wpcf_getget('page')), '_builtin' => true, '#name' => 'fields-button-add')); }
/** * Add a column for each term field on the term listing page. * * @param string[string] $columns Column definitions (column name => display name). * @return string[string] Updated column definitions. * @link https://make.wordpress.org/docs/plugin-developer-handbook/10-plugin-components/custom-list-table-columns/ * @since 1.9.1 */ public function manage_term_listing_columns($columns) { $factory = Types_Field_Group_Term_Factory::get_instance(); $taxonomy_slug = sanitize_text_field(wpcf_getget('taxonomy')); $groups = $factory->get_groups_by_taxonomy($taxonomy_slug); $columns_to_insert = array(); foreach ($groups as $group) { foreach ($group->get_field_definitions() as $field_definition) { $columns_to_insert[self::LISTING_COLUMN_PREFIX . $field_definition->get_slug()] = $field_definition->get_display_name(); } } $this->added_listing_columns = $columns_to_insert; // Insert before the last column, which displays counts of posts using the term (that's probably why column // has the label "Count" and name "posts" :-P). // If there is no "posts"=>"Count" column, insert at the end. if (isset($columns['posts']) && 'Count' == $columns['posts']) { $columns = Types_Utils::insert_at_position($columns, $columns_to_insert, array('key' => 'posts', 'where' => 'before')); } else { $columns = Types_Utils::insert_at_position($columns, $columns_to_insert, -1); } return $columns; }
/** * Important save_post hook. * * Core function. Works and stable. Do not move or change. * If required, add hooks only. * * @param int $post_ID * @param WP_Post $post * * @return bool */ function wpcf_admin_post_save_post_hook($post_ID, $post) { if (defined('WPTOOLSET_FORMS_VERSION')) { // Apparently, some things are *slightly* different when saving a child post in the Post relationships metabox. // Ugly hack that will go away with m2m. // // Note: The types_updating_child_post filter is needed for a situation when user clicks on the Update button // for the parent post. In that case we don't get enough information to determine if a child post is being updated. $is_child_post_update = 'wpcf_ajax' == wpcf_getget('action') && 'pr_save_child_post' == wpcf_getget('wpcf_action') || apply_filters('types_updating_child_post', false); global $wpcf; $errors = false; // Do not save post if is type of if (in_array($post->post_type, array('revision', 'view', 'view-template', 'cred-form', 'cred-user-form', 'nav_menu_item', 'mediapage'))) { return false; } $_post_wpcf = array(); if (!empty($_POST['wpcf'])) { $_post_wpcf = $_POST['wpcf']; } // handle checkbox if (array_key_exists('_wptoolset_checkbox', $_POST) && is_array($_POST['_wptoolset_checkbox'])) { foreach ($_POST['_wptoolset_checkbox'] as $key => $field_value) { $field_slug = preg_replace('/^wpcf\\-/', '', $key); if (array_key_exists($field_slug, $_post_wpcf)) { continue; } $_post_wpcf[$field_slug] = false; } } // handle radios if (array_key_exists('_wptoolset_radios', $_POST) && is_array($_POST['_wptoolset_radios'])) { foreach ($_POST['_wptoolset_radios'] as $key => $field_value) { $field_slug = preg_replace('/^wpcf\\-/', '', $key); if (array_key_exists($field_slug, $_post_wpcf)) { continue; } $_post_wpcf[$field_slug] = false; } } if (count($_post_wpcf)) { $add_error_message = true; if (isset($_POST['post_id']) && $_POST['post_id'] != $post_ID) { $add_error_message = false; } /** * check some attachment to delete */ $delete_attachments = apply_filters('wpcf_delete_attachments', true); $images_to_delete = array(); if ($delete_attachments && isset($_POST['wpcf']) && array_key_exists('delete-image', $_POST['wpcf']) && is_array($_POST['wpcf']['delete-image'])) { foreach ($_POST['wpcf']['delete-image'] as $image) { $images_to_delete[$image] = 1; } } foreach ($_post_wpcf as $field_slug => $field_value) { // Get field by slug $field = wpcf_fields_get_field_by_slug($field_slug); if (empty($field)) { continue; } // Skip copied fields if (isset($_POST['wpcf_repetitive_copy'][$field['slug']])) { continue; } // This is (apparently) expected for repetitive fields... if ($is_child_post_update && types_is_repetitive($field)) { $field_value = array($field_value); } $_field_value = !types_is_repetitive($field) ? array($field_value) : $field_value; // Set config $config = wptoolset_form_filter_types_field($field, $post_ID, $_post_wpcf); /** * remove from images_to_delete if user add again */ if ($delete_attachments && 'image' == $config['type']) { $images = $_field_value; if (!is_array($images)) { $images = array($images); } foreach ($images as $image) { if (array_key_exists($image, $images_to_delete)) { unset($images_to_delete[$image]); } } } /** * add filter to remove field name from error message */ /** This filter is toolset-common/toolset-forms/classes/class.validation.php */ add_filter('toolset_common_validation_add_field_name_to_error', '__return_false', 1234, 1); foreach ($_field_value as $_k => $_val) { // Check if valid $validation = wptoolset_form_validate_field('post', $config, $_val); $conditional = wptoolset_form_conditional_check($config); $not_valid = is_wp_error($validation) || !$conditional; if ($add_error_message && is_wp_error($validation)) { $errors = true; $_errors = $validation->get_error_data(); $_msg = sprintf(__('Field "%s" not updated:', 'wpcf'), $field['name']); wpcf_admin_message_store($_msg . ' ' . implode(', ', $_errors), 'error'); } if ($not_valid) { if (types_is_repetitive($field)) { unset($field_value[$_k]); } else { break; } } } remove_filter('toolset_common_validation_add_field_name_to_error', '__return_false', 1234, 1); // Save field if (types_is_repetitive($field)) { $wpcf->repeater->set($post_ID, $field); $wpcf->repeater->save($field_value); } else { if (!$not_valid) { $wpcf->field->set($post_ID, $field); $wpcf->field->save($field_value); } } do_action('wpcf_post_field_saved', $post_ID, $field); // TODO Move to checkboxes if ($field['type'] == 'checkboxes') { if (!empty($field['data']['options'])) { $update_data = array(); foreach ($field['data']['options'] as $option_id => $option_data) { if (!isset($_POST['wpcf'][$field['id']][$option_id])) { if (isset($field['data']['save_empty']) && $field['data']['save_empty'] == 'yes') { $update_data[$option_id] = 0; } } else { $update_data[$option_id] = $_POST['wpcf'][$field['id']][$option_id]; } } update_post_meta($post_ID, $field['meta_key'], $update_data); } } } /** * delete images */ if ($delete_attachments && !empty($images_to_delete)) { $args = array('post_parent' => $post_ID, 'posts_per_page' => -1); $children_array = get_children($args); foreach ($children_array as $child) { if (!array_key_exists($child->guid, $images_to_delete)) { continue; } wp_delete_attachment($child->ID); } } } if ($errors) { update_post_meta($post_ID, '__wpcf-invalid-fields', true); } do_action('wpcf_post_saved', $post_ID); return; } // OLD global $wpcf; // Basic cheks /* * Allow this hook to be triggered only if Types form is submitted */ // if ( !isset( $_POST['_wpcf_post_wpnonce'] ) || !wp_verify_nonce( $_POST['_wpcf_post_wpnonce'], // 'update-' . $post->post_type . '_' . $post_ID ) ) { // return false; // } /* * Do not save post if is type of: * revision * attachment * wp-types-group * view * view-template * cred-form */ if (in_array($post->post_type, $wpcf->excluded_post_types)) { return false; } /* * * * Get all groups connected to this $post */ $groups = wpcf_admin_post_get_post_groups_fields($post); if (empty($groups)) { return false; } $all_fields = array(); $_not_valid = array(); $_error = false; /* * * * Loop over each group * * TODO Document this * Connect 'wpcf-invalid-fields' with all fields */ foreach ($groups as $group) { if (isset($group['fields'])) { // Process fields $fields = wpcf_admin_post_process_fields($post, $group['fields'], true, false, 'validation'); // Validate fields $form = wpcf_form_simple_validate($fields); $all_fields = $all_fields + $fields; // Collect all not valid fields if ($form->isError()) { $_error = true; // Set error only to true $_not_valid = array_merge($_not_valid, (array) $form->get_not_valid()); } } } // Set fields foreach ($all_fields as $k => $v) { // only Types field if (empty($v['wpcf-id'])) { continue; } $_temp = new WPCF_Field(); $_temp->set($wpcf->post, $v['wpcf-id']); $all_fields[$k]['_field'] = $_temp; } foreach ($_not_valid as $k => $v) { // only Types field if (empty($v['wpcf-id'])) { continue; } $_temp = new WPCF_Field(); $_temp->set($wpcf->post, $v['wpcf-id']); $_not_valid[$k]['_field'] = $_temp; } /* * * Allow interaction here. * Conditional will set $error to false if field is conditional * and not submitted. */ $error = apply_filters('wpcf_post_form_error', $_error, $_not_valid, $all_fields); $not_valid = apply_filters('wpcf_post_form_not_valid', $_not_valid, $_error, $all_fields); // Notify user about error if ($error) { wpcf_admin_message_store(__('Please check your input data', 'wpcf'), 'error'); } /* * Save invalid elements so user can be informed after redirect. */ if (!empty($not_valid)) { update_post_meta($post_ID, 'wpcf-invalid-fields', $not_valid); } /* * * * * * Save meta fields */ if (!empty($_POST['wpcf'])) { foreach ($_POST['wpcf'] as $field_slug => $field_value) { // Get field by slug $field = wpcf_fields_get_field_by_slug($field_slug); if (empty($field)) { continue; } // Set field $wpcf->field->set($post_ID, $field); // Skip copied fields // CHECKPOINT if (isset($_POST['wpcf_repetitive_copy'][$field['slug']])) { continue; } // Don't save invalid // CHECKPOINT if (isset($not_valid[$field['slug']])) { continue; } /* * * * Saving fields * @since 1.2 * * We changed way repetitive fields are saved. * On each save fields are rewritten and order is saved in * '_$slug-sort-order' meta field. */ /* * * We marked fields as repetitive in POST['__wpcf_repetitive'] * Without this check we won't save any. * @see WPCF_Repeater::get_fields_form() */ if (isset($_POST['__wpcf_repetitive'][$wpcf->field->slug])) { /* * Use here WPCF_Repeater class. * WPCF_Repeater::set() - switches to current post * WPCF_Repeater::save() - saves repetitive field */ $wpcf->repeater->set($post_ID, $field); $wpcf->repeater->save(); } else { /* * Use WPCF_Field::save() */ $wpcf->field->save(); } do_action('wpcf_post_field_saved', $post_ID, $field); } } /* * Process checkboxes * * TODO Revise and remove * Since Types 1.1.5 we moved this check to embedded/includes/checkbox.php * checkbox.php added permanently to bootstrap. */ foreach ($all_fields as $field) { if (!isset($field['#type'])) { continue; } // if ( $field['#type'] == 'checkbox' // && !isset( $_POST['wpcf'][$field['wpcf-slug']] ) ) { // $field_data = wpcf_admin_fields_get_field( $field['wpcf-id'] ); // if ( isset( $field_data['data']['save_empty'] ) // && $field_data['data']['save_empty'] == 'yes' ) { // update_post_meta( $post_ID, // wpcf_types_get_meta_prefix( $field ) . $field['wpcf-slug'], // 0 ); // } else { // delete_post_meta( $post_ID, // wpcf_types_get_meta_prefix( $field ) . $field['wpcf-slug'] ); // } // } if ($field['#type'] == 'checkboxes') { $field_data = wpcf_admin_fields_get_field($field['wpcf-id']); if (!empty($field_data['data']['options'])) { $update_data = array(); foreach ($field_data['data']['options'] as $option_id => $option_data) { if (!isset($_POST['wpcf'][$field['wpcf-slug']][$option_id])) { if (isset($field_data['data']['save_empty']) && $field_data['data']['save_empty'] == 'yes') { $update_data[$option_id] = 0; } } else { $update_data[$option_id] = $_POST['wpcf'][$field['wpcf-slug']][$option_id]; } } update_post_meta($post_ID, wpcf_types_get_meta_prefix($field) . $field['wpcf-slug'], $update_data); } } } do_action('wpcf_post_saved', $post_ID); }
/** * Generate wrapper around form setup data. * * @param string $type * @param array $data * @param bool $render_closing_hr If true, render a hr tag at the end of the form section. * * @return array */ protected function filter_wrap($type, $data = array(), $button_only = false, $render_closing_hr = true) { $data = wp_parse_args($data, array('nonce' => '', 'title' => '', 'value' => '', 'value_default' => '')); $form = array(); $unique_id = wpcf_unique_id(serialize(func_get_args())); /** * form open */ $form[$unique_id . '-open'] = array('#type' => 'markup', '#markup' => sprintf('<div id="%s" class="wpcf-filter-container js-wpcf-filter-container">', esc_attr($unique_id))); /** * header */ if (!$button_only) { $form[$unique_id . '-header'] = array('#type' => 'markup', '#markup' => sprintf('<h3>%s</h3>', $data['title'])); } /** * Description */ if (!$button_only && isset($data['description'])) { $form[$unique_id . '-description'] = array('#type' => 'markup', '#markup' => wpautop($data['description'])); } /** * content */ if (!$button_only) { $form[$unique_id . '-content'] = array('#type' => 'markup', '#markup' => sprintf('<span class="js-wpcf-filter-ajax-response">%s</span>', empty($data['value']) ? $data['value_default'] : $data['value']), '#inline' => true); } /** * button */ if ($this->current_user_can_edit) { $form[$unique_id . '-button'] = array('#type' => 'button', '#name' => esc_attr($unique_id . '-button'), '#value' => __('Edit', 'wpcf'), '#attributes' => array('class' => 'js-wpcf-filter-button-edit wpcf-filter-button-edit', 'data-wpcf-type' => esc_attr($type), 'data-wpcf-page' => esc_attr(wpcf_getget('page')), 'data-wpcf-nonce' => wp_create_nonce($type)), '#inline' => true, '#before' => '<div class="wpcf-filter-button-edit-container">', '#after' => '</div>'); foreach ($data as $key => $value) { if (preg_match('/^data\\-wpcf\\-/', $key)) { $form[$unique_id . '-button']['#attributes'][$key] = esc_attr($value); } } } /** * form close */ $close_clear = $button_only || !$render_closing_hr ? '' : '<hr class="clear" />'; $form[$unique_id . '-close'] = array('#type' => 'markup', '#markup' => $close_clear . '</div>'); return $form; }
/** * The save_post hook. * * @param int $post_ID * @param WP_Post $post * @since unknown */ function wpcf_admin_post_save_post_hook($post_ID, $post) { // Apparently, some things are *slightly* different when saving a child post in the Post relationships metabox. // Ugly hack that will go away with m2m. // // Note: The types_updating_child_post filter is needed for a situation when user clicks on the Update button // for the parent post. In that case we don't get enough information to determine if a child post is being updated. $is_child_post_update = 'wpcf_ajax' == wpcf_getget('action') && 'pr_save_child_post' == wpcf_getget('wpcf_action') || apply_filters('types_updating_child_post', false); global $wpcf; $errors = false; // Do not save post if is type of if (in_array($post->post_type, array('revision', 'view', 'view-template', 'cred-form', 'cred-user-form', 'nav_menu_item', 'mediapage'))) { return; } $_post_wpcf = array(); if (!empty($_POST['wpcf'])) { $_post_wpcf = $_POST['wpcf']; } // handle checkbox if (array_key_exists('_wptoolset_checkbox', $_POST) && is_array($_POST['_wptoolset_checkbox'])) { foreach ($_POST['_wptoolset_checkbox'] as $key => $field_value) { $field_slug = preg_replace('/^wpcf\\-/', '', $key); if (array_key_exists($field_slug, $_post_wpcf)) { continue; } $_post_wpcf[$field_slug] = false; } } // handle radios if (array_key_exists('_wptoolset_radios', $_POST) && is_array($_POST['_wptoolset_radios'])) { foreach ($_POST['_wptoolset_radios'] as $key => $field_value) { $field_slug = preg_replace('/^wpcf\\-/', '', $key); if (array_key_exists($field_slug, $_post_wpcf)) { continue; } $_post_wpcf[$field_slug] = false; } } if (count($_post_wpcf)) { $add_error_message = true; if (isset($_POST['post_id']) && $_POST['post_id'] != $post_ID) { $add_error_message = false; } // check some attachment to delete $delete_attachments = apply_filters('wpcf_delete_attachments', true); $images_to_delete = array(); if ($delete_attachments && isset($_POST['wpcf']) && array_key_exists('delete-image', $_POST['wpcf']) && is_array($_POST['wpcf']['delete-image'])) { foreach ($_POST['wpcf']['delete-image'] as $image) { $images_to_delete[$image] = 1; } } foreach ($_post_wpcf as $field_slug => $field_value) { // Get field by slug $field = wpcf_fields_get_field_by_slug($field_slug); if (empty($field)) { continue; } // Skip copied fields if (isset($_POST['wpcf_repetitive_copy'][$field['slug']])) { continue; } // This is (apparently) expected for repetitive fields... if ($is_child_post_update && types_is_repetitive($field)) { $field_value = array($field_value); } $_field_value = !types_is_repetitive($field) ? array($field_value) : $field_value; // Set config $config = wptoolset_form_filter_types_field($field, $post_ID, $_post_wpcf); // remove from images_to_delete if user add again if ($delete_attachments && 'image' == $config['type']) { $images = $_field_value; if (!is_array($images)) { $images = array($images); } foreach ($images as $image) { if (array_key_exists($image, $images_to_delete)) { unset($images_to_delete[$image]); } } } // add filter to remove field name from error message // This filter is toolset-common/toolset-forms/classes/class.validation.php add_filter('toolset_common_validation_add_field_name_to_error', '__return_false', 1234, 1); foreach ($_field_value as $_k => $_val) { // Check if valid $validation = wptoolset_form_validate_field('post', $config, $_val); $conditional = wptoolset_form_conditional_check($config); $not_valid = is_wp_error($validation) || !$conditional; if ($add_error_message && is_wp_error($validation)) { $errors = true; $_errors = $validation->get_error_data(); $_msg = sprintf(__('Field "%s" not updated:', 'wpcf'), $field['name']); wpcf_admin_message_store($_msg . ' ' . implode(', ', $_errors), 'error'); } if ($not_valid) { if (types_is_repetitive($field)) { unset($field_value[$_k]); } else { break; } } } remove_filter('toolset_common_validation_add_field_name_to_error', '__return_false', 1234, 1); // Save field if (types_is_repetitive($field)) { $wpcf->repeater->set($post_ID, $field); $wpcf->repeater->save($field_value); } else { if (!$not_valid) { $wpcf->field->set($post_ID, $field); $wpcf->field->save($field_value); } } do_action('wpcf_post_field_saved', $post_ID, $field); // TODO Move to checkboxes if ($field['type'] == 'checkboxes') { if (!empty($field['data']['options'])) { $update_data = array(); foreach ($field['data']['options'] as $option_id => $option_data) { if (!isset($_POST['wpcf'][$field['id']][$option_id])) { if (isset($field['data']['save_empty']) && $field['data']['save_empty'] == 'yes') { $update_data[$option_id] = 0; } } else { $update_data[$option_id] = $_POST['wpcf'][$field['id']][$option_id]; } } update_post_meta($post_ID, $field['meta_key'], $update_data); } } } // delete images if ($delete_attachments && !empty($images_to_delete)) { $args = array('post_parent' => $post_ID, 'posts_per_page' => -1); $children_array = get_children($args); foreach ($children_array as $child) { if (!array_key_exists($child->guid, $images_to_delete)) { continue; } wp_delete_attachment($child->ID); } } } if ($errors) { update_post_meta($post_ID, '__wpcf-invalid-fields', true); } do_action('wpcf_post_saved', $post_ID); return; }
/** * Add a column for each term field on the term listing page. * * @param string[string] $columns Column definitions (column name => display name). * @return string[string] Updated column definitions. * @link https://make.wordpress.org/docs/plugin-developer-handbook/10-plugin-components/custom-list-table-columns/ * @since 1.9.1 */ public function manage_term_listing_columns($columns) { $taxonomy_slug = wpcf_getget('taxonomy'); $groups = WPCF_Field_Group_Term_Factory::get_instance()->get_groups_by_taxonomy($taxonomy_slug); $columns_to_insert = array(); foreach ($groups as $group) { foreach ($group->get_field_definitions() as $field_definition) { $columns_to_insert[self::LISTING_COLUMN_PREFIX . $field_definition->get_slug()] = $field_definition->get_display_name(); } } // Insert before the last column, which displays counts of posts using the term (that's probably why column // has the label "Count" and name "posts" :-P). $columns = WPCF_Utils::insert_at_position($columns, $columns_to_insert, array('key' => 'posts', 'where' => 'before')); return $columns; }
/** * Current field domain. * * @return string|null * @since 2.0 */ private function get_current_domain() { if (null == $this->current_domain) { $this->current_domain = wpcf_getget(self::PARAM_DOMAIN, null, Types_Field_Utils::get_domains()); } return $this->current_domain; }
/** * Summary. * * Description. * * @since x.x.x * @access (for functions: only use if private) * * @see Function/method/class relied on * @link URL * @global type $varname Description. * @global type $varname Description. * * @param type $var Description. * @param type $var Optional. Description. * @return type Description. */ public function form() { $this->save(); // Flush rewrite rules if we're asked to do so. // // This must be done after all post types and taxonomies are registered, and they can be registered properly // only on 'init'. So after making changes, we need to reload the page and THEN flush. if ('1' == wpcf_getget('flush', '0')) { flush_rewrite_rules(); } global $wpcf; $id = false; $update = false; $taxonomies = array(); if (isset($_GET[$this->get_id])) { $id = sanitize_text_field($_GET[$this->get_id]); } elseif (isset($_POST[$this->get_id])) { $id = sanitize_text_field($_POST[$this->get_id]); } if ($id) { $taxonomies = $this->taxonomies->get(); if (isset($taxonomies[$id])) { $this->ct = $taxonomies[$id]; $update = true; } else { wpcf_admin_message(__('Wrong Taxonomy specified.', 'wpcf'), 'error'); return false; } } else { $this->ct = wpcf_custom_taxonomies_default(); } $current_user_can_edit = WPCF_Roles::user_can_edit('custom-taxonomy', $this->ct); /** * sanitize _builtin */ if (!isset($this->ct['_builtin'])) { $this->ct['_builtin'] = false; } $form = $this->prepare_screen(); if ($current_user_can_edit && $update) { $form['id'] = array('#type' => 'hidden', '#value' => $id, '#name' => 'ct[wpcf-tax]'); $form['slug_conflict_check_nonce'] = array('#type' => 'hidden', '#value' => wp_create_nonce(Types_Ajax::CALLBACK_CHECK_SLUG_CONFLICTS), '#name' => 'types_check_slug_conflicts_nonce', '_builtin' => true); } /** * post icon field */ $menu_icon = isset($this->ct['icon']) && !empty($this->ct['icon']) ? $this->ct['icon'] : 'admin-post'; $form['icon'] = array('#type' => 'hidden', '#name' => 'ct[icon]', '#value' => $menu_icon, '#id' => 'wpcf-types-icon'); $form['form-open'] = array('#type' => 'markup', '#markup' => sprintf('<div id="post-body-content" class="%s">', $current_user_can_edit ? '' : 'wpcf-types-read-only'), '_builtin' => true); $form['table-1-open'] = array('#type' => 'markup', '#markup' => '<table id="wpcf-types-form-name-table" class="wpcf-types-form-table widefat js-wpcf-slugize-container"><thead><tr><th colspan="2">' . __('Name and description', 'wpcf') . '</th></tr></thead><tbody>'); $table_row = '<tr><td><LABEL></td><td><ERROR><BEFORE><ELEMENT><AFTER></td></tr>'; $form['name'] = array('#type' => 'textfield', '#name' => 'ct[labels][name]', '#title' => __('Name plural', 'wpcf') . ' (<strong>' . __('required', 'wpcf') . '</strong>)', '#description' => '<strong>' . __('Enter in plural!', 'wpcf') . '.', '#value' => isset($this->ct['labels']['name']) ? $this->ct['labels']['name'] : '', '#validate' => array('required' => array('value' => true), 'maxlength' => array('value' => 30)), '#pattern' => $table_row, '#inline' => true, '#attributes' => array('placeholder' => __('Enter Taxonomy name plural', 'wpcf'), 'class' => 'widefat')); $form['name-singular'] = array('#type' => 'textfield', '#name' => 'ct[labels][singular_name]', '#title' => __('Name singular', 'wpcf') . ' (<strong>' . __('required', 'wpcf') . '</strong>)', '#description' => '<strong>' . __('Enter in singular!', 'wpcf') . '</strong><br />' . '.', '#value' => isset($this->ct['labels']['singular_name']) ? $this->ct['labels']['singular_name'] : '', '#validate' => array('required' => array('value' => true), 'maxlength' => array('value' => 30)), '#pattern' => $table_row, '#inline' => true, '#attributes' => array('placeholder' => __('Enter Taxonomy name singular', 'wpcf'), 'class' => 'widefat js-wpcf-slugize-source')); /* * * IF isset $_POST['slug'] it means form is not submitted */ $attributes = array(); if (!empty($_POST['ct']['slug'])) { $reserved = wpcf_is_reserved_name(sanitize_text_field($_POST['ct']['slug']), 'taxonomy'); if (is_wp_error($reserved)) { $attributes = array('class' => 'wpcf-form-error', 'onclick' => 'jQuery(this).removeClass(\'wpcf-form-error\');'); } } $form['slug'] = array('#type' => 'textfield', '#name' => 'ct[slug]', '#title' => __('Slug', 'wpcf') . ' (<strong>' . __('required', 'wpcf') . '</strong>)', '#description' => '<strong>' . __('Enter in singular!', 'wpcf') . '</strong><br />' . __('Machine readable name.', 'wpcf') . '<br />' . __('If not provided - will be created from singular name.', 'wpcf') . '<br />', '#value' => isset($this->ct['slug']) ? $this->ct['slug'] : '', '#pattern' => $table_row, '#inline' => true, '#validate' => array('required' => array('value' => true), 'nospecialchars' => array('value' => true), 'maxlength' => array('value' => 30)), '#attributes' => $attributes + array('maxlength' => '30', 'placeholder' => __('Enter Taxonomy slug', 'wpcf'), 'class' => 'widefat js-wpcf-slugize')); $form['description'] = array('#type' => 'textarea', '#name' => 'ct[description]', '#title' => __('Description', 'wpcf'), '#value' => isset($this->ct['description']) ? $this->ct['description'] : '', '#attributes' => array('rows' => 4, 'cols' => 60, 'placeholder' => __('Enter Taxonomy description', 'wpcf'), 'class' => 'hidden js-wpcf-description'), '#pattern' => $table_row, '#inline' => true, '#after' => $this->ct['_builtin'] ? __('This is built-in WordPress Taxonomy.', 'wpcf') : sprintf('<a class="js-wpcf-toggle-description hidden" href="#">%s</a>', __('Add description', 'wpcf'))); $form['table-1-close'] = array('#type' => 'markup', '#markup' => '</tbody></table>'); $form['box-1-close'] = array('#type' => 'markup', '#markup' => '</div>', '_builtin' => true); if ($this->ct['_builtin']) { $form['name']['#attributes']['readonly'] = 'readonly'; $form['name-singular']['#attributes']['readonly'] = 'readonly'; $form['slug']['#attributes']['readonly'] = 'readonly'; $form['description']['#attributes']['readonly'] = 'readonly'; } /** * return form if current_user_can edit */ if ($current_user_can_edit) { return $form; } return wpcf_admin_common_only_show($form); }