This is what the API says:

wp.uploadFile

Upload a file.
Parameters

  • int blog_id
  • string username
  • string password
  • struct data
    • string name
    • string type
    • base64 bits
    • bool overwrite

Return Values

  • struct
    • string file
    • string url
    • string type

Sounds quite easy, doesn’t it? The gotcha I ran into was about the Base64 encoding.

Wrong: XMLRPC with Base64.encode64

require 'xmlrpc/client'
...
post_data = {
        :name => image.original_filename,
        :type => image.content_type,
        :bits => Base64.encode64(File.open("#{image.path}").read),
        :overwrite => 1
      }
...

First, everything seemed to be ok. The answer from the server was charming, but looking into the wordpress media-section: the image had no content. Allright, time for a PacketSniffer – I like EavesDrop.

<?xml version="1.0" ?>
<methodCall>
  <methodName>wp.uploadFile</methodName>
  <params>
    <param><value><i4>0</i4></value></param>
    <param><value><string>username</string></value></param>
    <param><value><string>password</string></value></param>
    <param><value>
      <struct>
        <member><name>type</name><value><string>image/jpeg</string></value></member>
        <member><name>bits</name><value><string>the Base64 encoded file content</string></value></member>
        <member><name>name</name><value><string>image.jpg</string></value></member>
        <member><name>overwrite</name><value><i4>1</i4></value></member>
      </struct>
    </value></param>
  </params>
</methodCall>

Yak! There it was. The Base64 encoded section was assigned as a string. Grabbing a bit deeper brought the solution:

Right: XMLRPC with XMLRPC::Base64

require 'xmlrpc/client'
...
post_data = {
        :name => image.original_filename,
        :type => image.content_type,
        :bits => XMLRPC::Base64.new(File.open("#{image.path}").read),
        :overwrite => 1
      }
...

This worked and the PacketSniffer shows why – now the Base64 encoded section is assigned to a <base64> tag:

<?xml version="1.0" ?>
<methodCall>
  <methodName>wp.uploadFile</methodName>
  <params>
    <param><value><i4>0</i4></value></param>
    <param><value><string>username</string></value></param>
    <param><value><string>password</string></value></param>
    <param><value>
      <struct>
        <member><name>type</name><value><string>image/jpeg</string></value></member>
        <member><name>bits</name><value><base64>the Base64 encoded file content</base64></value></member>
        <member><name>name</name><value><string>image.jpg</string></value></member>
        <member><name>overwrite</name><value><i4>1</i4></value></member>
      </struct>
    </value></param>
  </params>
</methodCall>