Monthly Archives: August 2016

Extending WordPress XML-RPC Functions

XML-RPC is a great, somewhat little-known feature of WordPress that is perfect for accomplishing many remote tasks with WordPress. I have found it to be a valuable asset during plugin development. While there are numerous function built in to the XML-RPC WordPress library already, we are going to focus solely on extending the XML-RPC library to accomplish almost any remote WordPress tag you wish to. The focus of this article is going to be on using XML-RPC as a communication layer between two WordPress sites on different servers. The two sites could be on the same server, but it is important to know that they do not have to be.

Basic code to extend WordPress XML-RPC

function wp_testXMLRPC() {
$returnme = "XML-RPC is working!";
return $returnme;
}//end wp_testXMLRPC extended XML-RPC function

function wp_extend_xmlrpc_methods($methods) {
    $methods['wp.testXMLRPC'] = 'wp_testXMLRPC';
    return $methods;   
}//end wp_extend_xmlrpc_methods
add_filter('xmlrpc_methods', 'wp_extend_xmlrpc_methods');

That's it! Add that code to your plugin file or theme's functions.php file and you have successfully extended WordPress' XML-RPC capabilities by adding a test function to test communication between two WordPress websites. Next I'll show you how to use this code from another WordPress site. We can call the wp_testXMLRPC function from another WordPress website and it will return "XML-RPC is working!" if the XML-RPC functions are currently working on both WordPress sites involved.

Calling an XML-RPC function from another WordPress website

To call our custom extended XML-RPC function above from another WordPress site, we would make a custom page template or plugin file and add the following code where you want to display the results of the test_XMLRPC function:

<?php

$rpcurl = "http://example.com/xmlrpc.php";//URL of site with custom XML-RPC function
$request = xmlrpc_encode_request('wp.testXMLRPC');//wp_testXMLRPC = wp.testXMLRPC
$ch = curl_init();
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_URL, $rpcurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
$results = curl_exec($ch);
curl_close($ch);

echo "<p>Results of XML-RPC wp_testXMLRPC function: $results</p>";//output results

?>

That's really all there is to it. However this is a simple function. It is also possible to create functions that accept and return parameter data and do complex WordPress actions etc.

How to pass parameters to an extended XML-RPC function and return values

The real power of XML-RPC becomes clear when you add the ability to pass values back and forth from one WordPress website to another! Soon we will examine how to pass a single parameter to an XML-RPC extended function. First, let's look at how to make the function for WordPress site one:

<?php

function wp_sayHi($arg) {
// Array of WP_User objects.
$yourName = $arg[0];
$returnme = "Hello $yourName!";
return $returnme;
}//end wp_sayHi extended XML-RPC function

?>

Then we have to add the code to extend the methods:

<php

function wp_extend_xmlrpc_methods($methods) {
    $methods['wp.sayHi'] = 'wp_sayHi';
    return $methods;   
}//end wp_extend_xmlrpc_methods
add_filter('xmlrpc_methods', 'wp_extend_xmlrpc_methods');

?>

The above two sections of code need to get added to your functions.php or plugin file on the first WordPress site, the one you want to retrieve the data from. On the second WordPress site, the one you pass the data from, you would add the following code wherever you wanted to present the results of the XML-RPC function we made:

<?php

$your_name = "Ian Lin";

$rpcurl = "http://example.com/xmlrpc.php";
$argparam = array($your_name);
$request = xmlrpc_encode_request('wp.sayHi',$argparam);
$ch = curl_init();
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_URL, $rpcurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
$results = curl_exec($ch);
curl_close($ch);

echo $results;

?>

The above code would print "Hello Ian Lin" to the screen wherever the code was called in a custom page template file or plugin file. Notice how we passed the $your_name vaiable as a parameter for the wp_sayHi function in lines 3 and 4 of the code above. $argparam puts the $your_name variable into a simple array before passing it to the $request made in the next line. Yes, XML-RPC functions accept arrays as parameters. Now let's look at what to do if you wanted to pass two or more values to an XML-RPC function.

Passing Two or More Values to an extended XML-RPC Function

Here is a valuable nugget I'll pass on to my readers that allows you to reset a user's password on WordPress site one from WordPress site two! Yes, it allows you to reset a password from another site. The function takes two parameters to work. It needs the user_login name and the new password. Here's the code that would go on WordPress site one:

<?php

function wp_syncPasswords($args) {
// Array of WP_User objects.
$userArg = $args[0];//gets user_login value passed in $args
$passArg = $args[1];//gets password from $args
//get user ID by login:
$userget = get_userdatabylogin($userArg);
$usergot = $userget->ID;//gets id of passed user
//update password:
wp_set_password($passArg, $usergot);
$returnme = $usergot."~".$userArg."~".$passArg;
return $returnme;
}//end wp_syncPasswords extended XML-RPC function

?>

There you have an XML-RPC function that allows you to actually change a user's password remotely! Pretty neat huh?

Take notice of the $returnme variable in the above wp_syncPasswords function. It returns 3 values in a string separated by a tilde character. You could use any special character to separate the values, but I find the tilde to be safe and reliable, so that's what I use a lot. I do this because you cannot return an array of values in an XML-RPC response. If I'm wrong, someone please enlighten me, but that's what I've learned from my experience anyway. Then we would simply parse out the values in the response on WordPress site two when we call the function and get $results.

Of course next to have to extend the XML-RPC methods just like we did earlier. Please note that if you already have other XML-RPC functions in your functions.php or plugin file, then you wouldn't rewrite the entire block of code to add additional functions as methods, you can simply add on to your previous functions. For example, here we'll add on to our last extended XML-RPC function from above:

<php

function wp_extend_xmlrpc_methods($methods) {
    $methods['wp.sayHi'] = 'wp_sayHi';

$methods['wp.syncPasswords'] = 'wp_suncPasswords';
    return $methods;   
}//end wp_extend_xmlrpc_methods
add_filter('xmlrpc_methods', 'wp_extend_xmlrpc_methods');

?>

Notice that this time, since we already had the wp_sayHi function extending XML-RPC previously, all we had to do is add the highlighted line to the wp_extend_xmlrpc_methods function above to make our new function valid and ready to call from another website such as WordPress site two.

Calling the wp_syncPasswords Function from a Remote WordPress Site Passing Two Parameters via XML-RPC

<?php

$userlog = "admin";//set WordPress user name
$new_pass ="YOUR_PASSWORD_HERE";//set new password
$rpcurl = "http://example.com/xmlrpc.php";
$argparam = array($userlog,$new_pass);
$request = xmlrpc_encode_request('wp.syncPasswords',$argparam);
$ch = curl_init();
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
curl_setopt($ch, CURLOPT_URL, $rpcurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
$results = curl_exec($ch);
curl_close($ch);
}//end my_profile_update function by Ian L.

?>

Running the code above would change the password of the admin user to YOUR_PASSWORD_HERE, so be sure to change admin to an existing username on WordPress site one and change YOUR_PASSWORD_HERE to the value of the new password you want to set from WordPress site two. This code could go in a WordPress plugin, but probably not appropriate for a page template, however it is possible.

Notice in the above PHP code, how we passed two parameters by setting the value of $argparam to array($userlog, $new_pass). Then we pass $argparam array to WordPress site one in the XML-RPC request in the next line. It's important to note how we pass one, two, or more parameters to XML-RPC functions. Now you should know how!

Some of you might be saying, "Hey, what about the returned results?" Well, you got me, I left them out to keep the code simple. It will work as it is above, but if you wanted to show the results returned you could do so by parsing the three values from the $results variable using something like this:

<?php

$myArray = explode("~", $results);

$remoteUserID = $myArray[0];

$remoteUserLogin = $myArray[1];

$remoteUserPassword = $myArray[2];

echo "<h2>User id: $remoteUserID with user login: $remoteUserLogin has had their password reset to $remoteUserPassword on WordPress site one!</h2>";

?>

That just about covers everything you need to know about extending the XML-RPC functionality of WordPress. You can do just about anything you want with this tool of you are good with writing custom WordPress code. Happy coding!

Working with WordPress Advanced Custom Fields Image Repeater Fields

My latest WordPress project deals with remote updating of custom post types that use the Advanced Custom Fields Plugin. From here on out, I'll simply refer to this plugin as ACF since it is such a long name and ACF is the generally accepted name among WordPress developers...

I am writing this post mostly because when working with ACF and repeater fields that have a sub field type of image, I wasn't able to find sufficient documentation on the subject to complete my project. I did complete the project with a lot of trial and error and piecing together of bits of info from many sources. My goal is to document the subject as much as possible here in order to make life easier for anyone attempting to do similar tasks as I have done.

The Challenge:

My particular challenge was that I had to create a WordPress plugin that would sync posts that used a custom post type and ACF. The basic requirement was that the plugin would update several client sites with posts from a single master site. So, the master site had a custom post type named "farms" that had several ACF fields including a couple repeater fields, one of which used the "image" sub-field type which is the focus of this article. The main challenge for me was basically writing code to insert images into a post that used a repeater field that had two sub-fields(image and alt_tag) the image sub-field stored image data in an array and the alt_tag sub-field stored custom alt tag content for the image tag. Some of you might already be thinking: Why do you have an alt_tag sub-field when alt tag content is already stored in the image data array. Well, that is true. However, it was a requirement of the project, so that's what I did.

 

The solution:

How to add WordPress Advanced Custom Fields(ACF) Image Repeater Fields with PHP Code

Today's challenge is to add values to an ACF image repeater field from within a plugin or theme file using PHP code. I had a difficult time figuring this out myself due to not being able to find enough documentation on the subject, so I decided to document my findings here. I used a custom post type named "farms" with my example. You can use a regular post, page or any custom post type for your own project. Just note that wherever you see "farms" it is my custom post type and should be replaced with your own value.

Export one or more of the posts in question

A logical first step to solving this problem for me was to create an XML export file of one of the posts that I wanted to add repeater field values to. in order to accomplish this, first create a test post of the custom post type you will be working with and make sure that the repeater field is all set up using the ACF plugin. Be sure to add a minimum of two images under the repeater field so you can examine the data via the XML export file. See the image below for an example of my own test custom post type which was set up with proper data to export:

post

Now it's time to export the post you just edited. To do this from wp-admin, click on "tools/export" and select the name of your custom post type. In my case, I select "farms" and click to export the posts as in the following image:

export

Open your XML file you downloaded and search for the post by title. Once you find the title, you could extract just that one post's data by copying everything in between <item> and </item> and pasting it in a new  XML file. That makes it easier to read just the one post you are concerned with if you have a lot of posts and a long XML file to work with. Of course, this is an optional step. I have extracted my relevant post and also deleted some of the XML that wasn't relevant to the task and here are the results:

<item>
...
<wp:postmeta>
<wp:meta_key><![CDATA[your_own_farm_pics]]></wp:meta_key>
<wp:meta_value><![CDATA[2]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[_your_own_farm_pics]]></wp:meta_key>
<wp:meta_value><![CDATA[field_57ab934d407ed]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[your_own_farm_pics_0_image]]></wp:meta_key>
<wp:meta_value><![CDATA[1862]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[_your_own_farm_pics_0_image]]></wp:meta_key>
<wp:meta_value><![CDATA[field_57ab934d407ee]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[your_own_farm_pics_0_alt_tag]]></wp:meta_key>
<wp:meta_value><![CDATA[first alt tag]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[_your_own_farm_pics_0_alt_tag]]></wp:meta_key>
<wp:meta_value><![CDATA[field_57ab934d407ef]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[your_own_farm_pics_1_image]]></wp:meta_key>
<wp:meta_value><![CDATA[1861]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[_your_own_farm_pics_1_image]]></wp:meta_key>
<wp:meta_value><![CDATA[field_57ab934d407ee]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[your_own_farm_pics_1_alt_tag]]></wp:meta_key>
<wp:meta_value><![CDATA[second alt tag]]></wp:meta_value>
</wp:postmeta>
<wp:postmeta>
<wp:meta_key><![CDATA[_your_own_farm_pics_1_alt_tag]]></wp:meta_key>
<wp:meta_value><![CDATA[field_57ab934d407ef]]></wp:meta_value>
</wp:postmeta>
</item>

Once you've located your post's XML, you will want to find the portion that is relevant to your particular ACF repeater field. To do this, simply do a search for the repeater field slug name. My field was named "your own farm pics", so the slug name I would search for would be "your_own_farm_pics". The first instance you find of the repeater field name/slug will look something like this:

<wp:postmeta>
<wp:meta_key><![CDATA[your_own_farm_pics]]></wp:meta_key>
<wp:meta_value><![CDATA[2]]></wp:meta_value>
</wp:postmeta>

Due to the use of CDATA , the above may look a little more complex than it really is. For what we are doing, we can simply ignore all of the CDATA stuff so that the above would become more like this:

<wp:postmeta>
<wp:meta_key>your_own_farm_pics</wp:meta_key>
<wp:meta_value>2</wp:meta_value>
</wp:postmeta>

Basically what's in between the XML tags is this:
<![CDATA[your_own_farm_pics]]>
The part you want is in between the opening and closing brackets after the word, CDATA. The rest can be ignored. In this case, all we want is: your_own_farm_pics.

Then, to show one more example of extractig data from CDATA, the next line looks like:
<wp:meta_value><![CDATA[2]]></wp:meta_value>
and the only part we want is the part after "CDATA[", which is simply: 2

So examining the first poroption of relevent .xml code we can gather that the value of "your_own_farm_pics" is "2".

Lets look at the next portion of XML that reads:
<wp:postmeta>
<wp:meta_key><![CDATA[_your_own_farm_pics]]></wp:meta_key>
<wp:meta_value><![CDATA[field_57ab934d407ed]]></wp:meta_value>
</wp:postmeta>
...okay, from what we've learned, this is what you should extract from the above XML:
field name(or key): _your_own_farm_pics
value: field_57ab934d407ed
I hope this part is clear to you. If it is not, then you'll probably need to study an XML tutorial first to understand. But one thing you need to notice here is that the field name or key starts with an underscore, therefore it is different from the first meta key(_your_own_farm_pics instead of your_own_farm_pics).

Let's go ahead and extract all of the relevant data from the .xml file. Basically you should be able to extract something similar to the following key/value pairs from the relevant portion of XML code:

your_own_farm_pics
2

_your_own_farm_pics
field_57ab934d407ed

your_own_farm_pics_0_image
1862

_your_own_farm_pics_0_image
field_57ab934d407ee

your_own_farm_pics_0_alt_tag
first alt tag

_your_own_farm_pics_0_alt_tag
field_57ab934d407ef

your_own_farm_pics_1_image
1861

_your_own_farm_pics_1_image
field_57ab934d407ee

your_own_farm_pics_1_alt_tag
second alt tag

_your_own_farm_pics_1_alt_tag
field_57ab934d407ef

As you can see there are 4 pieces of data for each image in the repeater field. This is because there are two sub-fields in this repeater field and each sub-field uses two key/value pairs. Notice the incremented numbers starting at 0. There is only a 0 and a 1 in this example because there are two images stored in our repeater field. so all the key names containing _0_ are one image's data and then all the ones with key names containing _1_ are the second image's data.

There are three parts to each key name. Each key either starts with the repeater slug or the repeater slug preceded by an underscore. Then there is a incremented number starting at zero. Finally we have the sub-field name. Here's the pattern these sub-field key names follow:

repeater_field_name + incremented number + sub-field name

Above is the pattern for the data key. Below is the very similar patter for the field key:

underscore + repeater_field_name + incremented number + sub-field name

So knowing that, you should be able to know exactly how to read these XML files now. This also gives you a huge clue on how data is stored in the database as the key/value pairs in the XML file are exactly what is stored in the database. Therefore the values are exactly what needs to be written to the database in order to insert repeater images into a post or custom post type.

Let's examine some PHP code now. Knowing what we do about the XML file, we know what data needs inserted into the database now, so our PHP code for the example XML file above should look like this in order to insert two images into a repeater field for a single post:

Note that the below code is for adding two sets of repeater field values. The repeater field is set up with two sub fields, one image sub-field and one simple text sub-field named alt_tag.

<?php

$post_id = "1902";
//first two key/value pairs are for the repeater field name:
$key = "your_own_farm_pics";
$value = "2";
add_post_meta($post_id, $key, $value);

$key = "_your_own_farm_pics";
$value = "field_57ab934d407ee";
add_post_meta($post_id, $key, $value);

//next eight key/value pairs are for the two repeater field sub-field names:
//There are four key/value pairs for the first image and four more for the second:
//Start image one data:
$key = "your_own_farm_pics_0_image";
$value = "1867";
add_post_meta($post_id, $key, $value);

$key = "_your_own_farm_pics_0_image";
$value = "field_57ab934d407ee";
add_post_meta($post_id, $key, $value);

$key = "your_own_farm_pics_0_alt_tag";
$value = "Alt tag content for image 1";
add_post_meta($post_id, $key, $value);

$key = "_your_own_farm_pics_0_alt_tag";
$value = "field_57ab934d407ef";
add_post_meta($post_id, $key, $value);

//Start image two data:
$key = "your_own_farm_pics_1_image";
$value = "1869";
add_post_meta($post_id, $key, $value);

$key = "_your_own_farm_pics_1_image";
$value = "field_57ab934d407ee";
add_post_meta($post_id, $key, $value);

$key = "your_own_farm_pics_1_alt_tag";
$value = "Alt tag content for image 2";
add_post_meta($post_id, $key, $value);

$key = "_your_own_farm_pics_1_alt_tag";
$value = "field_57ab934d407ef";
add_post_meta($post_id, $key, $value);

?>

Of course the above PHP code would go in a custom plugin and wouldn't work as standalone php code, but you should get that if you have any experience with writing WordPress plugins and if you do not, then this topic is far to advanced for you anyway. Try one of my starter tutorials for WordPress plugin developers instead.

 

Code explained:

First, you should notice the $postid variable that gets set to the post id you want to update with repeater fields.

Then you see three lines of code setting the $key variable to "your_own_farm_pics" which you will change to the name of your own repeater field name. The value of this needs to be equal to the number of repeaters you want to add. In this case, we are adding 2 images, so we set the value to 2.

Next you see the key of _your_own_farm_pics. This is the field value that is set in the database and is crucial in identifying the repeater field correctly, so be sure to get this right. Do an export of the database and search for the repeater field name to find the value for this if you have to. All you have to do it export the database as  XML and do a text search for the field name and you'll see the value right below it. The code above uses the XML example code posted above in this post.

The next important section of code, where the comment says "//next eight key/value pairs are for the two repeater field sub-field names:", is where you will have eight  sections with 3 lines of code each for the two image repeaters you add.  The important part to notice here is the numbering system used. Notice that the the first four sections of code have a zero in the keys, for example:

$key = "your_own_farm_pics_0_image";

So the value of the $key variable in the above example is made up of three parts:

  1. repeater field name: your_own_farm_pics
  2. incremented number: 0
  3. sub-field name: image

In this example, my repeater field name is "your_own_farm_pics",  the numbers start at 0 and go as high as the total number of repeater fields you add, the sub-field name in this case is "image".

Then, skip down three more lines to where you see the code:

$key = "your_own_farm_pics_0_alt_tag";

this is the second sub-field for the first repeater. so we follow the same principle as we did with the first sub-field which was image. The second sub-field name in this case is alt_tag, so we have:

  1. repeater field name: your_own_farm_pics
  2. number: 0
  3. sub-field name: alt_tag

That covers the first repeater field with it's two sub-fields. Then we want to add another repeater field with the code starting at the comment that reads: "//Start image two data:".

Notice that the number in the two $key variables has incremented to 1 in the second image's code because the numbering starts at 0 and this is the second repeater or image added.

 Summary

I hope this article sheds some light on this dimly illuminated topic dealing with Advanced Custom Fields plugin and programming your own plugin to work with it. I had a very difficult time digging up enough information to piece the above code together myself, so I truly hope this helps someone attempting to do the same thing.