/**
  * Get meta type so we know where the data should be saved.
  *
  * @return string
  */
 protected function get_meta_type()
 {
     if ($current_filter = current_filter()) {
         return papi_get_meta_type(explode('_', $current_filter)[1]);
     }
     return papi_get_meta_type();
 }
 /**
  * Get meta type value.
  *
  * @param  Papi_Entry_Type $entry_type
  *
  * @return string
  */
 protected function get_meta_type_value($entry_type)
 {
     if (in_array($entry_type->get_type(), ['attachment'], true)) {
         return $entry_type->get_type();
     }
     switch (papi_get_meta_type($entry_type->get_type())) {
         case 'post':
             return implode(', ', $entry_type->post_type);
         case 'term':
             return implode(', ', $entry_type->taxonomy);
         default:
             return 'n/a';
     }
 }
Esempio n. 3
0
 /**
  * Add custom body class when it's a page type.
  *
  * @param  string $classes
  *
  * @return string
  */
 public function admin_body_class($classes)
 {
     $classes .= sprintf(' papi-meta-type-%s', papi_get_meta_type());
     if (!in_array($this->post_type, papi_get_post_types(), true)) {
         return $classes;
     }
     if ($entry_type = $this->get_entry_type()) {
         $arr = $entry_type->get_body_classes();
         $arr = is_string($arr) ? [$arr] : $arr;
         $arr = is_array($arr) ? $arr : [];
         $classes .= ' ' . implode(' ', $arr);
     }
     return $classes;
 }
Esempio n. 4
0
 /**
  * Add custom body class when it's a page type.
  *
  * @param  string $classes
  *
  * @return string
  */
 public function admin_body_class($classes)
 {
     $classes .= sprintf(' papi-meta-type-%s', papi_get_meta_type());
     // Add custom css classes from entry type.
     if ($entry_type = $this->get_entry_type()) {
         $arr = $entry_type->get_body_classes();
         $arr = is_string($arr) ? [$arr] : $arr;
         $arr = is_array($arr) ? $arr : [];
         $classes .= ' ' . implode(' ', $arr);
     }
     // Add custom css classes from query string.
     if ($css = papi_get_qs('papi_css')) {
         $css = is_array($css) ? $css : [];
         $css = array_map('sanitize_text_field', $css);
         $classes .= ' ' . implode(' ', $css);
     }
     return $classes;
 }
 /**
  * Save properties with a post id of zero.
  */
 public function save_properties()
 {
     if ($_SERVER['REQUEST_METHOD'] !== 'POST' || papi_get_meta_type() !== 'option') {
         return;
     }
     // Check if our nonce is vailed.
     if (!wp_verify_nonce(papi_get_sanitized_post('papi_meta_nonce'), 'papi_save_data')) {
         return;
     }
     // Get properties data.
     $data = $this->get_post_data();
     // Prepare properties data.
     $data = $this->prepare_properties_data($data, 0);
     foreach ($data as $key => $value) {
         papi_update_property_meta_value(['id' => 0, 'slug' => $key, 'type' => 'option', 'value' => $value]);
     }
     /**
      * Fire `save_properties` action when all is done.
      *
      * @param int    $id
      * @param string $meta_type
      */
     do_action('papi/save_properties', 0, 'option');
 }
 /**
  * Prepare properties data for saving.
  *
  * @param  array $data
  * @param  int   $post_id
  *
  * @return array
  */
 protected function prepare_properties_data(array $data = [], $post_id = 0)
 {
     // Since we are storing witch property it is in the `$data` array
     // we need to remove that and set the property type to the property
     // and make a array of the property type and the value.
     foreach ($data as $key => $value) {
         if (papi_is_property_type_key($key)) {
             continue;
         }
         $property_type_key = papify(papi_get_property_type_key($key));
         // Check if value exists.
         if (!isset($data[$key]) && !isset($data[$property_type_key])) {
             continue;
         }
         // Pair property value with property type object.
         $data[$key] = ['type' => $data[$property_type_key], 'value' => $value];
         // Remove property type object since it's not needed anymore.
         unset($data[$property_type_key]);
     }
     foreach ($data as $key => $item) {
         if (papi_is_property_type_key($key)) {
             continue;
         }
         $property = papi_get_property_type($item['type']);
         unset($data[$key]);
         if (papi_is_property($property)) {
             // Run `update_value` method on the property class.
             $data[$key] = $property->update_value($item['value'], unpapify($key), $post_id);
             // Apply `update_value` filter so this can be changed from
             // the theme for specified property type.
             $data[$key] = papi_filter_update_value($item['type']->type, $data[$key], unpapify($key), $post_id, papi_get_meta_type());
             if ($item['type']->overwrite) {
                 $slug = unpapify($key);
                 $this->overwrite[$slug] = $data[$key];
                 unset($data[$key]);
             }
         }
     }
     return $data;
 }
Esempio n. 7
0
/**
 * Update property values on the post with the given post id
 * or update property values on the option page.
 *
 * @param  array $meta
 *
 * @return bool
 */
function papi_update_property_meta_value(array $meta = [])
{
    $meta = array_merge(['id' => 0, 'slug' => '', 'type' => 'post', 'value' => ''], $meta);
    $meta = (object) $meta;
    $meta->type = papi_get_meta_type($meta->type);
    $save_value = true;
    // Set the right update value function for the type.
    $update_value_fn = $meta->type === 'option' ? 'update_option' : 'update_metadata';
    /**
     * Change update function.
     *
     * @param string $update_value_fn
     */
    $update_value_fn = apply_filters('papi/core/update_value_fn', $update_value_fn);
    // Check so the function is callable before using it.
    if (!is_callable($update_value_fn)) {
        return;
    }
    // Check for string keys in the array if any.
    foreach (papi_to_array($meta->value) as $key => $value) {
        if (is_string($key)) {
            $save_value = false;
            break;
        }
    }
    // If main value shouldn't be saved it should be array.
    if (!$save_value && is_array($meta->value)) {
        $meta->value = [$meta->value];
    }
    // Delete saved value if empty.
    if (papi_is_empty($meta->value)) {
        return papi_delete_property_meta_value($meta->id, $meta->slug, $meta->type);
    }
    $result = true;
    foreach (papi_to_array($meta->value) as $key => $value) {
        // Delete saved value if value is empty.
        if (papi_is_empty($value) || $value === '[]' || $value === '{}') {
            return papi_delete_property_meta_value($meta->id, $meta->slug, $meta->type);
        }
        // Delete main value cache.
        papi_cache_delete($meta->slug, $meta->id, $meta->type);
        // If not a array we can save the value.
        if (!is_array($value)) {
            if ($save_value) {
                $value = $meta->value;
            }
            if (papi_get_meta_type($meta->type) === 'option') {
                $out = call_user_func_array($update_value_fn, [unpapify($meta->slug), $value]);
                $result = $out ? $result : $out;
            } else {
                $out = call_user_func_array($update_value_fn, [$meta->type, $meta->id, unpapify($meta->slug), $value]);
                $result = $out ? $result : $out;
            }
            continue;
        }
        // Delete all child value caches.
        papi_update_property_meta_value_cache_delete($meta, $value);
        // Update metadata or option value for all child values.
        foreach ($value as $child_key => $child_value) {
            if (papi_is_empty($child_value)) {
                papi_delete_property_meta_value($meta->id, $child_key, $meta->type);
            } else {
                if (papi_get_meta_type($meta->type) === 'option') {
                    call_user_func_array($update_value_fn, [unpapify($child_key), $child_value]);
                } else {
                    call_user_func_array($update_value_fn, [$meta->type, $meta->id, unpapify($child_key), $child_value]);
                }
            }
        }
    }
    return $result;
}
 /**
  * Update value before it's saved to the database.
  *
  * @param mixed  $values
  * @param string $repeater_slug
  * @param int    $post_id
  *
  * @return array
  */
 public function update_value($values, $repeater_slug, $post_id)
 {
     $rows = intval(papi_get_property_meta_value($post_id, $repeater_slug));
     if (!is_array($values)) {
         $values = [];
     }
     list($results, $trash) = $this->get_results($rows, $repeater_slug, $post_id);
     // Delete trash values.
     foreach ($trash as $meta) {
         papi_delete_property_meta_value($post_id, $meta->meta_key);
     }
     $values = papi_to_property_array_slugs($values, $repeater_slug);
     foreach ($values as $slug => $value) {
         if (papi_is_property_type_key($slug)) {
             continue;
         }
         $property_type_slug = papi_get_property_type_key_f($slug);
         if (!isset($values[$property_type_slug])) {
             continue;
         }
         // Get real property slug
         $property_slug = $this->get_child_slug($repeater_slug, $slug);
         // Get property type
         $property_type_value = $values[$property_type_slug]->type;
         $property_type = papi_get_property_type($property_type_value);
         // Unserialize if needed.
         $value = papi_maybe_json_decode(maybe_unserialize($value));
         // Run update value on each property type class.
         $value = $property_type->update_value($value, $property_slug, $post_id);
         // Run update value on each property type filter.
         $values[$slug] = papi_filter_update_value($property_type_value, $value, $property_slug, $post_id, papi_get_meta_type());
         if (is_array($values[$slug])) {
             foreach ($values[$slug] as $key => $val) {
                 if (!is_string($key)) {
                     continue;
                 }
                 unset($values[$slug][$key]);
                 $key = preg_replace('/^\\_/', '', $key);
                 $values[$slug][$key] = $val;
             }
         }
     }
     // Find out which keys that should be deleted.
     $trash = array_diff(array_keys(papi_to_array($results)), array_keys(papi_to_array($values)));
     // Delete unwanted (trash) values.
     foreach (array_keys($trash) as $trash_key) {
         papi_delete_property_meta_value($post_id, $trash_key);
     }
     // It's safe to remove all rows in the database here.
     $this->remove_repeater_rows($post_id, $repeater_slug);
     // Remove unnecessary property type keys if any is left.
     foreach (array_keys($values) as $slug) {
         if (papi_is_property_type_key($slug)) {
             unset($values[$slug]);
         }
     }
     return $values;
 }
 /**
  * Switch page type if all checks pass.
  *
  * @param  int     $post_id
  * @param  WP_post $post
  */
 public function save_post($post_id, $post)
 {
     // Check if post id and post object is empty or not.
     if (empty($post_id) || empty($post)) {
         return false;
     }
     // Check if our nonce is vailed.
     if (!wp_verify_nonce(papi_get_sanitized_post('papi_meta_nonce'), 'papi_save_data')) {
         return false;
     }
     // Check if so both page type keys exists.
     if (empty($_POST[papi_get_page_type_key()]) || empty($_POST[papi_get_page_type_key('switch')])) {
         return false;
     }
     // Page type information.
     $page_type_id = sanitize_text_field($_POST[papi_get_page_type_key()]);
     $page_type_switch_id = sanitize_text_field($_POST[papi_get_page_type_key('switch')]);
     // Don't update if the same ids.
     if ($page_type_id === $page_type_switch_id) {
         return false;
     }
     $page_type = papi_get_entry_type_by_id($page_type_id);
     $page_type_switch = papi_get_entry_type_by_id($page_type_switch_id);
     $post_type_object = get_post_type_object(papi_get_post_type());
     // Check if page type and post type is not empty.
     if (empty($page_type_switch) || empty($post_type_object)) {
         return false;
     }
     // Check if autosave.
     if (wp_is_post_autosave($post_id)) {
         return false;
     }
     // Check if revision.
     if (wp_is_post_revision($post_id)) {
         return false;
     }
     // Check if revision post type.
     if (in_array($post->post_type, ['revision', 'nav_menu_item'], true)) {
         return false;
     }
     // Check so page type has the post type.
     if (!$page_type->has_post_type($post->post_type) || !$page_type_switch->has_post_type($post->post_type)) {
         return false;
     }
     // Check page type capabilities.
     if (!papi_current_user_is_allowed($page_type_switch->capabilities)) {
         return false;
     }
     // Check so user can edit posts and that the user can publish posts on the post type.
     if (!current_user_can('edit_post', $post_id) || !current_user_can($post_type_object->cap->publish_posts)) {
         return false;
     }
     // Get properties.
     $properties = $page_type->get_properties();
     $properties_switch = $page_type_switch->get_properties();
     // Delete only properties that don't have the same type and slug.
     foreach ($properties as $property) {
         $delete = true;
         // Check if the properties are the same or not.
         foreach ($properties_switch as $property_switch) {
             if ($property_switch->type === $property->type && $property_switch->match_slug($property->get_slug())) {
                 $delete = false;
                 break;
             }
         }
         if (!$delete) {
             continue;
         }
         // Delete property values.
         $property->delete_value($property->get_slug(true), $post_id, papi_get_meta_type());
     }
     // Update page type id.
     return papi_set_page_type_id($post_id, $page_type_switch_id);
 }
Esempio n. 10
0
/**
 * Get entry type id.
 *
 * @param  int $id
 * @param  string $type
 *
 * @return string
 */
function papi_get_entry_type_id($id = 0, $type = null)
{
    $type = papi_get_meta_type($type);
    $id = papi_get_meta_id($type, $id);
    if ($id > 0) {
        if ($meta_value = get_metadata($type, $id, papi_get_page_type_key(), true)) {
            return $meta_value;
        }
    }
    $entry_type_id = papi_get_qs('entry_type');
    /**
     * Change entry type id.
     *
     * @param  string $entry_type_id
     * @param  string $type
     *
     * @return string
     */
    return apply_filters('papi/entry_type_id', $entry_type_id, $type);
}
Esempio n. 11
0
 /**
  * Register property with:
  *
  * - `register_meta` (WP 4.6+)
  *
  * @param  string $type
  *
  * @return bool
  */
 public function register($type = 'post')
 {
     if (version_compare(get_bloginfo('version'), '4.6', '<')) {
         return false;
     }
     $type = papi_get_meta_type($type);
     // Register option fields with the new `register_setting` function and only for WordPress 4.7.
     if ($type === 'option' && version_compare(get_bloginfo('version'), '4.7', '>=')) {
         // The `type` will be the same for each fields, this is just to get it out
         // to the REST API, the output will be different for different fields and are
         // handled later on.
         return register_setting('papi', $this->get_slug(true), ['sanitize_callback' => [$this, 'register_meta_sanitize_callback'], 'show_in_rest' => $this->get_option('show_in_rest'), 'type' => 'string']);
     }
     // Register meta fields with the new `register_meta` function.
     // The `type` will be the same for each fields, this is just to get it out
     // to the REST API, the output will be different for different fields and are
     // handled later on.
     return register_meta($type, $this->get_slug(true), ['auth_callback' => $this->get_option('auth_callback'), 'description' => $this->get_option('description'), 'sanitize_callback' => [$this, 'register_meta_sanitize_callback'], 'show_in_rest' => $this->get_option('show_in_rest'), 'single' => $this->get_convert_type() !== 'array', 'type' => 'string']);
 }
 /**
  * Format the value of the property before it's returned
  * to WordPress admin or the site.
  *
  * @param  mixed  $values
  * @param  string $repeater_slug
  * @param  int    $post_id
  *
  * @return array
  */
 public function format_value($values, $repeater_slug, $post_id)
 {
     if (!is_array($values)) {
         return [];
     }
     foreach ($values as $index => $layout) {
         foreach ($layout as $slug => $value) {
             if (is_string($value) && preg_match($this->layout_value_regex, $value)) {
                 if (isset($values[$index][$this->layout_key])) {
                     unset($values[$index][$slug]);
                     continue;
                 }
                 $values[$index][$this->layout_key] = $value;
                 unset($values[$index][$slug]);
                 continue;
             }
             if (papi_is_property_type_key($slug)) {
                 continue;
             }
             $property_type_slug = papi_get_property_type_key_f($slug);
             if (!isset($values[$index][$property_type_slug])) {
                 continue;
             }
             $property_type_value = $values[$index][$property_type_slug];
             $property_type = papi_get_property_type($property_type_value);
             if (!is_object($property_type)) {
                 continue;
             }
             // Get property child slug.
             $child_slug = $this->get_child_slug($repeater_slug, $slug);
             // Create cache key.
             $cache_key = sprintf('%s_%d_%s', $repeater_slug, $index, $slug);
             // Get raw value from cache if enabled.
             if ($this->cache) {
                 $raw_value = papi_cache_get($cache_key, $post_id, $this->get_meta_type());
             } else {
                 $raw_value = false;
             }
             // Load the value.
             if ($raw_value === null || $raw_value === false) {
                 $values[$index][$slug] = $property_type->load_value($value, $child_slug, $post_id);
                 $values[$index][$slug] = papi_filter_load_value($property_type->type, $values[$index][$slug], $child_slug, $post_id, papi_get_meta_type());
                 if (!papi_is_empty($values[$index][$slug]) && $this->cache) {
                     papi_cache_set($cache_key, $post_id, $values[$index][$slug], $this->get_meta_type());
                 }
             } else {
                 $values[$index][$slug] = $raw_value;
             }
             if (strtolower($property_type->type) === 'repeater') {
                 $property_type->cache = false;
             }
             // Format the value from the property class.
             $values[$index][$slug] = $property_type->format_value($values[$index][$slug], $child_slug, $post_id);
             if (!is_admin()) {
                 $values[$index][$slug] = papi_filter_format_value($property_type->type, $values[$index][$slug], $child_slug, $post_id, papi_get_meta_type());
             }
             $values[$index][$property_type_slug] = $property_type_value;
         }
     }
     if (!is_admin()) {
         foreach ($values as $index => $row) {
             foreach ($row as $slug => $value) {
                 if (is_string($value) && preg_match($this->layout_value_regex, $value)) {
                     unset($values[$index][$slug]);
                     $values[$index]['_layout'] = preg_replace($this->layout_value_regex, '', $value);
                 }
                 if (papi_is_property_type_key($slug)) {
                     unset($values[$index][$slug]);
                 }
                 if (papi_is_empty($value)) {
                     unset($values[$index][$slug]);
                 }
             }
         }
     }
     return $values;
 }
Esempio n. 13
0
 /**
  * Check if it's a option page or not.
  *
  * @return bool
  */
 public function is_option_page()
 {
     return $this->get_store() instanceof Papi_Option_Store || papi_get_meta_type() === 'option';
 }
Esempio n. 14
0
 /**
  * Setup action hooks.
  */
 protected function setup_actions()
 {
     if (post_type_exists($this->get_post_type()) && papi_get_meta_type() === 'post') {
         add_action('add_meta_boxes', [$this, 'setup_meta_box']);
         if ($this->box->context === 'after_title') {
             add_action('edit_form_after_title', [$this, 'move_meta_box_after_title']);
         }
     } else {
         $this->setup_meta_box();
     }
     // Will be called on when you call do_meta_boxes
     // even without a real post type.
     add_action(sprintf('postbox_classes_%s_%s', strtolower($this->get_post_type()), $this->box->id), [$this, 'meta_box_css_classes']);
 }
 /**
  * Get property value.
  *
  * @param  Papi_Core_Conditional_Rule $rule
  *
  * @return mixed
  */
 private function get_value(Papi_Core_Conditional_Rule $rule)
 {
     if (papi_doing_ajax()) {
         $source = $rule->get_source();
         $meta_id = papi_get_meta_id();
         $entry_type = papi_get_entry_type_by_meta_id($meta_id);
         if (!papi_is_empty($source) && $entry_type instanceof Papi_Entry_Type !== false) {
             if (papi_is_property($entry_type->get_property($rule->slug))) {
                 return $this->get_deep_value($rule->slug, $source);
             }
         }
     }
     if (!papi_is_empty($rule->get_source())) {
         return $this->get_deep_value($rule->slug, $rule->get_source());
     }
     $slug = $rule->get_field_slug();
     $type = papi_get_meta_type();
     $value = papi_get_field($slug, null, $type);
     return $this->get_deep_value($slug, $value);
 }
Esempio n. 16
0
 /**
  * Get store from factory.
  *
  * @param  int    $post_id
  * @param  string $type
  *
  * @return mixed
  */
 public static function factory($post_id, $type = 'post')
 {
     $type = papi_get_meta_type($type);
     $class_suffix = '_' . ucfirst($type) . '_Store';
     $class_name = 'Papi' . $class_suffix;
     if (!class_exists($class_name)) {
         return;
     }
     $post_id = papi_get_post_id($post_id);
     $page = new $class_name($post_id);
     if (!$page->valid()) {
         return;
     }
     return $page;
 }
Esempio n. 17
0
 /**
  * Add custom table column to page or taxonomy type.
  *
  * @param string $column_name
  * @param int    $post_id
  * @param int    $term_id
  */
 public function manage_page_type_posts_custom_column($column_name, $post_id, $term_id = null)
 {
     if (!in_array($this->post_type, papi_get_post_types(), true) && !in_array($this->taxonomy, papi_get_taxonomies(), true)) {
         return;
     }
     /**
      * Hide column for post type. Default is false.
      *
      * @param string $post_type
      */
     if (apply_filters('papi/settings/column_hide_' . $this->get_meta_type_value(), false)) {
         return;
     }
     // Column name most be `entry_type`. On taxomy the column name is `post_id` variable.
     if ($column_name !== 'entry_type' && $post_id !== 'entry_type') {
         return;
     }
     // Get the entry type for the post or term.
     $entry_type = papi_get_entry_type_by_meta_id(is_numeric($post_id) ? $post_id : $term_id, papi_get_meta_type());
     if (!is_null($entry_type)) {
         echo esc_html($entry_type->name);
     } else {
         $post = !empty($this->post_type) && empty($this->taxonomy);
         $arg = $post ? papi_get_post_type() : papi_get_taxonomy();
         $type = $post ? 'page' : 'taxonomy';
         echo esc_html(call_user_func_array("papi_filter_settings_standard_{$type}_type_name", [$arg]));
     }
 }
Esempio n. 18
0
 /**
  * Get meta type from the store or the default one.
  *
  * @return string
  */
 public function get_meta_type()
 {
     $store = $this->get_store();
     return $store ? $store->get_type() : papi_get_meta_type();
 }
Esempio n. 19
0
/**
 * Get right meta id column for a meta type.
 *
 * @param  string $type
 *
 * @return string|null
 */
function papi_get_meta_id_column($type = 'post')
{
    if ($type = papi_get_meta_type($type)) {
        return sprintf('%s_id', $type);
    }
}