Как создать новый пост с прикрепленной фотографией в WordPress с помощью XMLRPC?

Кто-нибудь знает, как создать новый пост с прикрепленной фотографией в WordPress с помощью XMLRPC?

Я могу создать новый пост и загрузить новое изображение отдельно, но, похоже, нет возможности прикрепить загруженное фото к созданному сообщению?

Ниже приведены коды, которые я сейчас использую.

<?php
DEFINE('WP_XMLRPC_URL', 'http://www.blog.com/xmlrpc.php');
DEFINE('WP_USERNAME', 'username');
DEFINE('WP_PASSWORD', 'password');

require_once("./IXR_Library.php");
$rpc = new IXR_Client(WP_XMLRPC_URL);
$status = $rpc->query("system.listMethods"); // method name
if(!$status){
    print "Error (".$rpc->getErrorCode().") : ";
    print $rpc->getErrorMessage()."\n";
    exit;
}

$content['post_type'] = 'post'; // post title
$content['title'] = 'Post Title '.date("F j, Y, g:i a"); // post title
$content['categories'] = array($response[1]['categoryName']); // psot categories
$content['description'] = '<p>Hello World!</p>'; // post body
$content['mt_keywords'] = 'tag keyword 1, tag keyword 2, tag keyword 3'; // post tags
$content['mt_allow_comments'] = 1; // allow comments
$content['mt_allow_pings'] = 1; // allow pings
$content['custom_fields'] = array(array('key'=>'Key Name', 'value'=>'Value One')); // custom fields
$publishBool = true;

if(!$rpc->query('metaWeblog.newPost', '', WP_USERNAME, WP_PASSWORD, $content, $publishBool)){
    die('An error occurred - '.$rpc->getErrorCode().":".$rpc->getErrorMessage());
}
$postID = $rpc->getResponse();
echo 'POST ID: '.$postID.'<br/>';

if($postID){ // if post has successfully created

    $fs = filesize(dirname(__FILE__).'/image.jpg');
    $file = fopen(dirname(__FILE__).'/image.jpg', 'rb');
    $filedata = fread($file, $fs);
    fclose($file);

    $data = array(
        'name'  => 'image.jpg',
        'type'  => 'image/jpg',
        'bits'  => new IXR_Base64($filedata),
        false // overwrite
    );

    $status = $rpc->query(
        'metaWeblog.newMediaObject',
        $postID,
        WP_USERNAME,
        WP_PASSWORD,
        $data
    );
    echo print_r($rpc->getResponse()); // Array ( [file] => image.jpg [url] => http://www.blog.com/wp-content/uploads/2011/09/image.jpg [type] => image/jpg )
}
?>

person P.C.    schedule 30.09.2011    source источник


Ответы (6)


Я был вовлечен в сайты WordPress (мой нынешний работодатель использует 3 из них), и ежедневная публикация материала заставила меня использовать то, что я умею лучше всего — скрипты!

Они основаны на PHP и просты в использовании и развертывании. А безопасность? Просто используйте .htaccess для его защиты.

Согласно исследованиям, XMLRPC, когда дело доходит до файлов, — это то, в чем WordPress действительно отстой. После того как вы загрузите файл, вы не сможете связать это вложение с конкретным сообщением! Я знаю, это раздражает.

Поэтому я решил разобраться в этом сам. Мне понадобилась неделя, чтобы разобраться. Вам потребуется 100% контроль над вашим клиентом публикации, совместимым с XMLRPC, иначе это ничего не будет значить для вас!

Вам понадобится из вашей установки WordPress:

  • class-IXR.php, расположенный в /wp-admin/includes
  • class-wp-xmlrpc-server.php, расположенный в /wp-includes

class-IXR.php понадобится, если вы создадите свой собственный инструмент для публикации, как я. У них корректно работающий кодировщик base64. Не доверяйте тому, что идет с PHP.

Вы также должны иметь некоторый опыт в программировании, чтобы иметь возможность относиться к этому. Я постараюсь быть яснее.

  1. Изменить class-wp-xmlrpc-server.php

    • Download this to your computer, through ftp. Backup a copy, just in case.
    • Откройте файл в текстовом редакторе. Если он не отформатирован (как правило, он должен, иначе они используют разрывы каретки типа unix), откройте его в другом месте или используйте что-то вроде ultraedit.
    • Обратите внимание на функцию mw_newMediaObject. Это наша цель. Небольшое примечание здесь; WordPress заимствует функциональность у blogger и movabletype. Хотя WordPress также имеет уникальные наборы классов для xmlrpc, они решили сохранить общую функциональность, чтобы они работали независимо от используемой платформы.
    • Найдите функцию mw_newMediaObject($args). Как правило, это должна быть строка 2948. Обратите внимание на строку состояния вашего текстового редактора, чтобы узнать номер строки, в которой вы находитесь. Если вы все еще не можете найти ее, найдите ее, используя функцию поиска/найти вашего текстового редактора.
    • Прокрутите немного вниз, и у вас должно получиться что-то вроде этого:

       $name = sanitize_file_name( $data['name'] );
       $type = $data['type'];
       $bits = $data['bits'];
      
    • После переменной $name мы что-то добавим. Смотри ниже.

       $name = sanitize_file_name( $data['name'] );
       $post = $data['post']; //the post ID to attach to.
       $type = $data['type'];
       $bits = $data['bits'];
      

      Обратите внимание на новую переменную $post. Это означает, что всякий раз, когда вы будете делать новый запрос на загрузку файла, теперь вам будет доступен аргумент «post», который вы можете прикрепить.

      Как найти номер сообщения, зависит от того, как вы добавляете сообщения с помощью клиента, совместимого с xmlrpc. Как правило, вы должны получить это в результате публикации. Это числовое значение.

      После того, как вы отредактировали вышеприведенное, пришло время перейти к строке 3000.

      // Construct the attachment array
      // attach to post_id 0
      $post_id = 0;
      $attachment = array(
          'post_title' => $name,
          'post_content' => '',
          'post_type' => 'attachment',
          'post_parent' => $post_id,
          'post_mime_type' => $type,
          'guid' => $upload[ 'url' ]
      );
      
    • Так вот почему ни одно изображение не связано ни с одним постом! По умолчанию для аргумента post_parent всегда установлено значение 0! Так больше не будет.

      // Construct the attachment array
      // attach to post_id 0
      $post_id = $post;
      $attachment = array(
          'post_title' => $name,
          'post_content' => '',
          'post_type' => 'attachment',
          'post_parent' => $post_id,
          'post_mime_type' => $type,
          'guid' => $upload[ 'url' ]
      );
      

      $post_id теперь принимает значение $post, полученное из запроса xmlrpc. Как только это будет зафиксировано во вложении, оно будет связано с любой публикацией, которую вы пожелаете!

      Это можно улучшить. Можно назначить значение по умолчанию, чтобы ничего не сломалось, если значение не будет введено. Хотя, на моей стороне, я поставил значение по умолчанию на своем клиенте, и никто кроме меня не обращается к интерфейсу XMLRPC.

    • После внесения изменений сохраните файл и повторно загрузите его по тому же пути, по которому вы его нашли. Опять же, не забудьте сделать резервные копии.

      Будьте осторожны с обновлениями WordPress, которые влияют на этот модуль. Если это произойдет, вам нужно снова применить это редактирование!

  2. Включите class-IXR.php в свой редактор типа PHP. Если вы используете что-то другое, я не могу вам помочь. :(

Надеюсь, это поможет некоторым людям.

person O_H    schedule 31.12.2011
comment
Взлом основных файлов никогда не рекомендуется, и в настоящее время можно добиться решения без хаков. - person brasofilo; 11.06.2014

Когда вы публикуете, WordPress сканирует пост на наличие тегов IMG. Если WP находит изображение, оно загружается в его медиатеку. Если в теле есть изображение, оно автоматически прикрепится к сообщению.

В основном вы должны:

  • опубликовать медиа (изображение) первым
  • Возьмите его URL
  • включите URL-адрес изображения с тегом IMG в текст вашего сообщения.
  • затем создайте пост

Вот пример кода. Требуется обработка ошибок и дополнительная документация.

$admin ="***";
$userid ="****";
$xmlrpc = 'http://localhost/web/blog/xmlrpc.php';
include '../blog/wp-includes/class-IXR.php';
$client = new IXR_Client($xmlrpc);

$author         =   "test";    
$title          =   "Test Posting";
$categories     =   "chess,coolbeans";
$body           =   "This is only a test disregard </br>";

$tempImagesfolder = "tempImages";
$img = "1338494719chessBoard.jpg";


$attachImage = uploadImage($tempImagesfolder,$img);
$body .= "<img src='$attachImage' width='256' height='256' /></a>";

createPost($title,$body,$categories,$author);

/*
*/
function createPost($title,$body,$categories,$author){
    global $username, $password,$client;
    $authorID =  findAuthor($author); //lookup id of author

    /*$categories is a list seperated by ,*/
    $cats = preg_split('/,/', $categories, -1, PREG_SPLIT_NO_EMPTY);
    foreach ($cats as $key => $data){
        createCategory($data,"","");
    }

    //$time = time();
    //$time += 86400;
    $data = array(
        'title' => $title,
        'description' => $body,
        'dateCreated' => (new IXR_Date(time())),
        //'dateCreated' => (new IXR_Date($time)),  //publish in the future
        'mt_allow_comments' => 0, // 1 to allow comments
        'mt_allow_pings' => 0,// 1 to allow trackbacks
        'categories' => $cats,
        'wp_author_id' => $authorID     //id of the author if set       
    );
    $published = 0; // 0 - draft, 1 - published
    $res = $client->query('metaWeblog.newPost', '', $username, $password, $data, $published);
}

/*
*/
function uploadImage($tempImagesfolder,$img){
    global $username, $password,$client;
    $filename = $tempImagesfolder ."/" . $img;

    $fs = filesize($filename);   
    $file = fopen($filename, 'rb');  
    $filedata = fread($file, $fs);    
    fclose($file); 

    $data = array(
        'name'  => $img, 
        'type'  => 'image/jpg',  
        'bits'  => new IXR_Base64($filedata), 
        false //overwrite
    );

    $res = $client->query('wp.uploadFile',1,$username, $password,$data);
    $returnInfo = $client->getResponse();

    return $returnInfo['url'];     //return the url of the posted Image
}

/*
*/
function findAuthor($author){
    global $username, $password,$client;
    $client->query('wp.getAuthors ', 0, $username, $password);
    $authors = $client->getResponse();
    foreach ($authors as $key => $data){
        //  echo $authors[$key]['user_login'] . $authors[$key]['user_id'] ."</br>";
        if($authors[$key]['user_login'] == $author){
            return $authors[$key]['user_id'];
        }
    }
    return "not found";
}

/*
*/
function createCategory($catName,$catSlug,$catDescription){
    global $username, $password,$client;
    $res = $client->query('wp.newCategory', '', $username, $password,
        array(
            'name' => $catName,
            'slug' => $catSlug,
            'parent_id' => 0,
            'description' => $catDescription
        )
    );
}
person subterfuge    schedule 05.06.2012

После вызова метода metaWeblog.newMediaObject нам нужно отредактировать запись изображения в базе данных, чтобы добавить родителя (ранее созданный пост с metaWeblog.newPost).

Если мы попробуем с metaWeblog.editPost, он выдает ошибку 401, что указывает на то, что

// Use wp.editPost to edit post types other than post and page.
if ( ! in_array( $postdata[ 'post_type' ], array( 'post', 'page' ) ) )
    return new IXR_Error( 401, __( 'Invalid post type' ) );

Решение состоит в вызове wp.editPost, который принимает следующие аргументы:

$blog_id        = (int) $args[0];
$username       = $args[1];
$password       = $args[2];
$post_id        = (int) $args[3];
$content_struct = $args[4];

Итак, сразу после newMediaObject делаем:

$status = $rpc->query(
    'metaWeblog.newMediaObject',
    $postID,
    WP_USERNAME,
    WP_PASSWORD,
    $data
);
$response = $rpc->getResponse();
if( isset($response['id']) ) {
    // ATTACH IMAGE TO POST
    $image['post_parent'] = $postID;
    if( !$rpc->query('wp.editPost', '1', WP_USERNAME, WP_PASSWORD, $response['id'], $image)) {
        die( 'An error occurred - ' . $rpc->getErrorCode() . ":" . $rpc->getErrorMessage() );
    }
    echo 'image: ' . $rpc->getResponse();

    // SET FEATURED IMAGE
    $updatePost['custom_fields'] = array( array( 'key' => '_thumbnail_id', 'value' => $response['id'] ) );
    if( !$rpc->query( 'metaWeblog.editPost', $postID, WP_USERNAME, WP_PASSWORD, $updatePost, $publishBool ) ) {
        die( 'An error occurred - ' . $rpc->getErrorCode() . ":" . $rpc->getErrorMessage() );
    }
    echo 'update: ' . $rpc->getResponse();
}

Я использовал библиотеку Incutio XML-RPC для PHP для тестирования, а остальные код точно такой же, как в вопросе.

person brasofilo    schedule 07.06.2014

Вот пример кода для прикрепления изображения из пути, не поддерживаемого WordPress (wp-content)

<?php
function attach_wordpress_images($productpicture,$newid)
{
    include('../../../../wp-load.php');
    $upload_dir = wp_upload_dir();
    $dirr = $upload_dir['path'].'/';

    $filename = $dirr . $productpicture;                    
    # print "the path is : $filename \n";                    
    # print "Filnamn: $filename \n";                
    $uploads = wp_upload_dir(); // Array of key => value pairs
    # echo $uploads['basedir'] . '<br />';
    $productpicture = str_replace('/uploads','',$productpicture);
    $localfile =  $uploads['basedir'] .'/' .$productpicture;
    #  echo "Local path = $localfile \n";         

    if (!file_exists($filename))
    {
        echo "hittade inte $filename !";
        die ("no image for flaska $id $newid !");                                                   
    }
    if (!copy($filename, $localfile)) 
    {
        wp_delete_post($newid);
        echo  "Failed to copy the file $filename to $localfile ";
        die("Failed to copy the file $filename to $localfile ");
    }

    $wp_filetype = wp_check_filetype(basename($localfile), null );
    $attachment = array(
        'post_mime_type' => $wp_filetype['type'],
        'post_title' => preg_replace('/\.[^.]+$/', '', basename($localfile)),
        'post_content' => '',
        'post_status' => 'inherit'
        );
    $attach_id = wp_insert_attachment( $attachment, $localfile, $newid );

    // you must first include the image.php file
    // for the function wp_generate_attachment_metadata() to work

    require_once(ABSPATH . 'wp-admin/includes/image.php');        
    $attach_data = wp_generate_attachment_metadata( $attach_id, $localfile );
    wp_update_attachment_metadata( $attach_id, $attach_data );  
}
?>
person moffepoffe    schedule 30.09.2011
comment
Мне жаль. Я ценю ваши образцы кода, но я ищу методы, которые можно реализовать в XML-RPC. - person P.C.; 01.10.2011

Мне пришлось сделать это несколько месяцев назад. Это возможно, но это не только взломано и недокументировано, мне пришлось копаться в исходниках WordPress, чтобы понять это. Что я написал еще тогда:

Одной вещью, которая была абсолютно недокументирована, был метод прикрепления изображения к сообщению. Немного покопавшись, я нашел attach_uploads() — функцию, которую WordPress вызывает каждый раз, когда сообщение создается или редактируется через xml-rpc. Что он делает, так это просматривает список неприкрепленных медиа-объектов и смотрит, содержит ли новый/отредактированный пост ссылку на них. Поскольку я пытался прикрепить изображения, чтобы их использовала галерея темы, я не обязательно хотел ссылаться на изображения в сообщении и не хотел редактировать WordPress. Итак, в итоге я включил URL-адрес изображения в html-комментарий. -- danieru.com

Как я уже сказал, грязно, но я искал лучший метод повсюду, и я достаточно уверен, что его не существует.

person Daniel    schedule 04.11.2011

Начиная с Wordpress 3.5, newmediaobject теперь частично распознает взлом.

больше нет необходимости взламывать class-wp-xmlrpc-server.php.

Вместо этого ваш клиент xml-rpc должен отправить номер сообщения в переменную с именем post_id. (Ранее это была просто переменная 'post')

Надеюсь, это поможет кому-то.

person O_H    schedule 29.12.2012
comment
Привет, так можно ли сделать все это в XMLRPC без редактирования wordpress? и если да, то какие шаги? Я задал здесь новый вопрос .com/questions/17722743/ Спасибо. - person simion314; 18.07.2013