According to (great) Frank Bueltge, there are three methods to do this:
- WP API (JSON)
- Feed (XML)
- XMLRPC API
And, also according to Bueltge, we should prioritize the WP JSON API because it is the most modern way and is about to be incorporated into the basic code of Wordpress. However, my answer is via XMLRPC, a classic WP method (to make trackbacks and pingbacks, publish from web or desktop apps), and that normally is recommended disable because it opens the door to several attempts of attack [see "safety" at the end].
Remarks:
this code is only a proof of concept; the source post is reproduced on the destination site, but this information is not stored on the source site;
a complete code would have to store the "mirror" post ID on the source site. And, when called again, instead of creating a new post again, would have to update the post "mirror" that was created first and whose ID we store as add_post_meta
by making the reproduction;
the target site returns the ID of the mirror post that was created, so the above functionality is not too difficult, a little jQuery and AJAX are needed.
Destination Plugin
Installed on the site that will receive the duplicate post.
<?php
/**
* Plugin Name: (SOpt) Plugin de Destino
* Description: Publicações DE outro site
* Plugin URI: /questions/66280
* Version: 1.0
* Author: brasofilo
*/
add_filter( 'xmlrpc_methods', 'xmlrpc_sopt_66280' );
function xmlrpc_sopt_66280( $methods ) {
/* BLOQUEIO DE TODOS OS MÉTODOS, remova a seguinte linha para habilitar todos os métodos padão do WP */
$methods = array();
$methods['postFromOutside'] = 'outside_sopt_66280';
return $methods;
}
function outside_sopt_66280( $args ) {
// A ordem dos argumentos é importante!
$username = $args[0];
$password = $args[1];
$data = $args[2];
global $wp_xmlrpc_server;
// Usuário correto?
if ( !$user = $wp_xmlrpc_server->login( $username, $password ) ) {
return $wp_xmlrpc_server->error;
}
// Titulo e custom fields do post
$title = $data["title"];
$custom_fields = $data["custom_fields"];
// Formatar o novo post
$new_post = array(
'post_status' => 'draft',
'post_title' => $title,
'post_type' => 'post',
);
// Faz o insert do novo post
$new_post_id = wp_insert_post( $new_post );
foreach( $custom_fields as $meta_key => $values )
foreach ( $values as $meta_value )
add_post_meta( $new_post_id, $meta_key, $meta_value );
// Devolve ID do novo post
return $new_post_id;
}
Origin Plugin
Installed on the site that will create duplicate post.
/wp-content/plugins/xml-post/xml-post.php
<?php
/**
* Plugin Name: (SOpt) Plugin de Origem
* Description: Publicações PARA outro site. CONFIGURAR 'user' e 'password' do Site Destino.
* Plugin URI: https://wordpress.stackexchange.com/a/54875/12615
* Version: 1.0
* Author: brasofilo
*/
add_action( 'add_meta_boxes', 'wpse_54822_add_custom_box' );
add_action( 'admin_head', 'wpse_54822_script_enqueuer' );
add_action( 'wp_ajax_wpse_54822_custom_query', 'wpse_54822_custom_query' );
add_action( 'wp_ajax_nopriv_wpse_54822_custom_query', 'wpse_54822_custom_query' );
function wpse_54822_add_custom_box() {
add_meta_box(
'wpse_54822_sectionid',
__( 'Page Attachments' ),
'wpse_54822_inner_custom_box',
'page'
);
}
function wpse_54822_inner_custom_box() {
global $post;
?>
<a href="#" id="post-me" class="dettach" title="Cross post" >Post Me</a>
<?php
}
function wpse_54822_script_enqueuer() {
global $current_screen;
if( 'page' != $current_screen->id )
return;
wp_register_script( 'my-js', plugin_dir_url(__FILE__) . '/ajax-xmlrpc.js' );
wp_enqueue_script( 'my-js' );
wp_localize_script( 'my-js', 'wp_ajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
}
function wpse_54822_custom_query() {
// Dados a enviar na chamada XML-RPC
$data = array(
"title" => 'titulo',
"custom_fields" => 'custom_fields'
);
// Considerando que user e password são "admin" e "admin"
// E que o método postFromOutside é o que está definido no Plugin Destino
$params = array( 'admin', 'admin', $data );
$params = xmlrpc_encode_request( 'postFromOutside', $params );
// Iniciar a requisição HTTP
$request = new WP_Http;
$result = $request->request(
'http://plugins.dev/xmlrpc.php',
array('method' => 'POST', 'body' => $params )
);
// O retorno XML é EXTREMAMENTE ESPECÍFICO e depende do Plugin de Origem
$xml = simplexml_load_string( $result['body'] );
wp_send_json_success( $xml->params->param->value->int );
}
/wp-content/plugins/xml-post/ajax-xmlrpc.js
/**
* Arquivo JS que acompanha o plugin XML-POST.PHP
* O objeto wp_ajax é enviado pelo wp_localize_script
* A propriedade the_id é somente ilustrativa
*/
jQuery(document).ready(function($) {
$('#post-me').click(function(){
$.post(
wp_ajax.ajaxurl,
{
action: 'wpse_54822_custom_query',
the_id: 'toast'
},
function(data){
console.log('Novo Post:',data.data[0]);
}
);
});
});
[Security]
- Create a user on the Target Site only for the XMLRPC connection; can use name and password type 128bits; ie, very complicated.
- You might want to store
user
and password
in a configuration file outside the folder public_html
and make a require/include
to pull this .
- From what I’ve seen, there are some methods specific which are preferred targets of Ddos attacks and prevention is to do the
unset()
of these methods. With the line $methods = array();
in the Target Plugin we are deleting all the standard methods and adding only our soon after.
- I suggest two security tools: the plugin Wordfence and the rules of
.htaccess
5G Blacklist 2013.
References:
managed to solve this problem? I was curious
– Caio Felipe Pereira
No, @Caiofelipepereira, but I’ll look at your answer. I just saw.
– Lollipop
Are you talking about Multisite or two independent WP?
– brasofilo
WP independent.
– Lollipop