Skip to content

Instantly share code, notes, and snippets.

@gmazzap
Created June 19, 2015 00:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gmazzap/e45bb38565e221876958 to your computer and use it in GitHub Desktop.
Save gmazzap/e45bb38565e221876958 to your computer and use it in GitHub Desktop.
<?php
/**
* @author Giuseppe Mazzapica <giuseppe.mazzapica@gmail.com>
* @license http://opensource.org/licenses/MIT MIT
*/
class MetaboxStealer
{
/**
* @var bool
*/
private static $stealing;
/**
* @var string
*/
private $post_type;
/**
* @var array
*/
private $boxes = [];
/**
* When the request contain special variable, this function will make it
* return a serialized version of $wp_meta_boxes array and die.
*/
public static function init()
{
add_filter('post_updated_messages', function ($messages) {
if (MetaboxStealer::stealing()) {
ob_start();
return [];
}
return $messages;
});
add_action('do_meta_boxes', function () {
if (MetaboxStealer::stealing()) {
ob_end_clean();
global $wp_meta_boxes;
echo serialize($wp_meta_boxes);
die();
}
});
}
/**
* Checks that the request contain a special variable that will make request
* return a serialized version of $wp_meta_boxes array and die.
*
* @return bool
*/
public static function stealing()
{
if (is_null(self::$stealing)) {
$screen = function_exists('get_current_screen') ? get_current_screen() : null;
$stealing = filter_input(INPUT_GET, 'stealing-boxes', FILTER_SANITIZE_STRING);
self::$stealing =
$screen instanceof \WP_Screen
&& $stealing
&& wp_verify_nonce($stealing, $screen->post_type);
}
return self::$stealing;
}
/**
* @param string $post_type Current post type
*/
public function __construct($post_type)
{
$this->post_type = $post_type;
}
/**
* Send a HTTP request to post edit page of a given CPT setting a special
* variable that will make that page return serialized $wp_meta_boxes array.
* After that, so obtained boxes are merged with the boxes for current post type.
*
* @param string $cpt CPT to steal metaboxes from
*/
public function steal($cpt)
{
$vars = [
'post_type' => $cpt,
'stealing-boxes' => wp_create_nonce($cpt),
];
$url = add_query_arg($vars, admin_url('/post-new.php'));
$cookies = [];
foreach ($_COOKIE as $name => $value) {
if ('PHPSESSID' !== strtoupper($name)) {
$cookies[] = new \WP_Http_Cookie([
'name' => $name,
'value' => $value,
]);
}
}
$response = wp_remote_get($url, ['cookies' => $cookies]);
if (! is_wp_error($response)) {
$body = wp_remote_retrieve_body($response);
if (is_serialized($body)) {
$boxes = unserialize($body);
$this->boxes = isset($boxes[$cpt]) ? $boxes[$cpt] : [];
empty($this->boxes) or $this->merge();
}
}
}
/**
* Merge meta boxes from current request with boxes obtained from HTTP request to another CPT.
*/
private function merge()
{
global $wp_meta_boxes;
isset($wp_meta_boxes[$this->post_type]) or $wp_meta_boxes[$this->post_type] = [];
foreach ($this->boxes as $context => $priorities) {
foreach ($priorities as $priority => $boxes) {
if (! isset($wp_meta_boxes[$this->post_type][$context])) {
$wp_meta_boxes[$this->post_type][$context] = [];
}
if (! isset($wp_meta_boxes[$this->post_type][$context][$priority])) {
$wp_meta_boxes[$this->post_type][$context][$priority] = [];
}
$wp_meta_boxes[$this->post_type][$context][$priority] = array_merge(
$wp_meta_boxes[$this->post_type][$context][$priority],
$boxes
);
}
}
}
}
@gmazzap
Copy link
Author

gmazzap commented Jun 19, 2015

How To Use

// init the class
add_action('admin_init', ['MetaboxStealer', 'init']);

// use the class to merge boxes for current CPT with boxes for another CPT
add_action('edit_form_after_editor', function ($post) {
    $stealer_cpt = 'post';
    $steal_from = 'page';
    if ($post->post_type === $stealer_cpt) {
        $stealer = new MetaboxStealer($post_type, $post);
        $stealer->steal($steal_from);
    }
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment