Over a million developers have joined DZone.

Use Mule to Sync WordPress Sites

DZone's Guide to

Use Mule to Sync WordPress Sites

· Integration Zone
Free Resource

The Integration Zone is brought to you in partnership with Cloud Elements. What's below the surface of an API integration? Download The Definitive Guide to API Integrations to start building an API strategy.

I recently thought about to create a process with which I could keep two instances of WordPress in sync. I wanted to see if I could do this with Mule. I came up with the following solution:

  • Receive the RSS feed of a new post in Mule flow
  • Use the content of the RSS feed to post to the other wordpress instance by using XML-RPC
  • Have it running on CloudHub so I don’t have to setup my own Muleserver

So lets start a new CloudHub project. Since I am a big fan of Netbeans I use the Maven based approach (I must admit I have tried to use MuleStudio for this but it didn’t bring me the productivityboost I hoped for).
I created the Mule project with:

<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns="http://www.mulesoft.org/schema/mule/core"
        http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/3.1/mule.xsd
        http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/3.1/mule-http.xsd
        http://www.mulesoft.org/schema/mule/rss http://www.mulesoft.org/schema/mule/rss/3.1/mule-rss.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    <spring:bean name="xmlRpcHelper" class="net.pascalalma.rss.XmlRpcHelper">
        <spring:constructor-arg value="http://www.pragmatic-integrators.com/xmlrpc.php" type="java.lang.String"/>
        <spring:constructor-arg value="UserName" type="java.lang.String"/>
        <spring:constructor-arg value="Password" type="java.lang.String"/>
    <spring:bean name="entryReceiver" class="net.pascalalma.rss.EntryReceiver">
        <spring:constructor-arg ref="xmlRpcHelper"/>
    <flow name="poll-and-post">
        <poll frequency="36000000">
            <http:outbound-endpoint address="http://www.redstream.nl/feed/" />
        <rss:feed-splitter />
            <spring-object bean="entryReceiver"/>

As you can see I poll the website ‘www.redstream.nl’ once each 10 hours. The RSS feed I receive is split and sent to my custom made component ‘entryReceiver’. It would be nice to use a XML-RPC endpoint here but this isn’t created yet (and actually I don’t feel like it neither). The EntryReceiver looks like:

package net.pascalalma.rss;

import org.mule.api.annotations.param.Payload;
import com.sun.syndication.feed.synd.SyndEntry;

public class EntryReceiver {

    XmlRpcHelper xmlRpcHelper = null;

    public EntryReceiver(XmlRpcHelper helper) {
        xmlRpcHelper = helper;
    public void readEntry(@Payload SyndEntry entry) throws Exception {

        // Get the title
        String title = entry.getTitle();

        // Check if title exist in current blogs on the new blogsite
       if (!xmlRpcHelper.titleExists(title)) {

        } else {
            // Skip this post

Disclaimer: just wanted to see if it worked, I did not try to build a robust solution that had to work for every WordPress site, so you are warned!

And the bean where the dirty work is done:

package net.pascalalma.rss;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;

import com.sun.syndication.feed.synd.SyndContentImpl;
import com.sun.syndication.feed.synd.SyndEntry;

public class XmlRpcHelper {

    private String url;
    private String userName;
    private String password;
    XmlRpcClient client = new XmlRpcClient();

    public XmlRpcHelper(String url, String u, String p) {
        this.url = url;
        this.userName = u;
        this.password = p;

        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        try {
            config.setServerURL(new URL(url));
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block

    public boolean titleExists(String title) {
        return getRecentTitles().contains(title);

    public void post(SyndEntry entry) {
        StringBuilder content = new StringBuilder("<content><title>").append(entry.getTitle()).append("</title>");
        List<SyndContentImpl> contents = entry.getContents();

        for (SyndContentImpl syndContent : contents) {
        try {
            client.execute("blogger.newPost", new Object[]{"bla", 1,
                        userName, password, content.toString(), true});
        } catch (XmlRpcException e) {
            // TODO Auto-generated catch block

    private List<String> getRecentTitles() {
        List<String> titles = new ArrayList<String>();
        try {
            Object token = client.execute("blogger.getRecentPosts", new Object[]{"bla", 1,
                        userName, password, 10});

            Object[] result = (Object[]) token;
            for (int i = 0; i < result.length; i++) {
                titles.add(getTitle((HashMap<String, Object>) result[i]));
        } catch (XmlRpcException e) {
            // TODO Auto-generated catch block
            // return null;
        return titles;

    private static String getTitle(Map response) {
        String title = null;
        String content = (String) response.get("content");

        if (content != null) {
            title = content.substring(content.indexOf("<title>") + 7,
        return title;

One thing that kept me busy for a while was that the first String in the Object array that is supplied with the XmlRpc call may contain anything as long as it contains something. An empty String “” is ignored in the call and will lead to an invalid Username/Password message.

If all this is in place you can build the project with: ‘mvn clean install’. This will create a zip file in the target directory. This zip file can then be uploaded with your dashboard to your CloudHub instance and that’s it! As you can see the two sites ‘www.redstream.nl’ and ‘www.pragmatic-integrators.com’ are know kept in sync (with a max. gap of 10 hrs). Of course the copied post is not an exact clone of the original (I am loosing info about the Author, Categories, etc. and images are referred to at the original location) but it shows that the main idea works!

Your API is not enough. Learn why (and how) leading SaaS providers are turning their products into platforms with API integration in the ebook, Build Platforms, Not Products from Cloud Elements.


Published at DZone with permission of Pascal Alma. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}