How can I create a new wordpress post from within NodeJS?

686 Views Asked by At

I'm trying to access my WordPress site from a NodeJS program. Specifically, I'm trying to create a draft post from within a NodeJS program. I've never done this before, and I can't get it work.

I've tried a few ways of doing this. First I used WPAPI and went through the documentation for that. It seemed to connect and get a response from my site but no post was created.

WPAPI method and response log

I've gotten an application password through the Wordpress control panel and I'm using it in the program. The username is from the same page on my panel.

I had installed the JSON Basic Authentication plugin while working with WPAPI, but I deactivated it when I switched to another method.

(Following the documentation on GitHub for WPAPI, I thought I would need to install the superagent bundle so I could use create() I tried installing superagent, requiring wpapi/superagent, and changing the type to module in the package, but when I tried to run it I got an error message saying the module "wpapi/superagent" could not be found. After that I just went back to the general import.)

import WPAPI from "wpapi"

const wp = new WPAPI({
    endpoint: 'https://www.example.com/wp-json',
    username: 'username',
    password: 'application_password'
})

wp.posts().create({
    title: 'test post',
    content: 'will this work?'
}).then((res) => {
    console.log(res)
})

The log:

[
  {
    id: 1,
    date: '2022-09-11T22:33:39',
    date_gmt: '2022-09-11T22:33:39',
    guid: { rendered: 'https://example.com/?p=1' },
    modified: '2022-09-11T22:33:39',
    modified_gmt: '2022-09-11T22:33:39',
    slug: 'hello-world',
    status: 'publish',
    type: 'post',
    link: 'https://example.com/2022/09/11/hello-world/',
    title: { rendered: 'Hello world!' },
    content: {
      rendered: '\n' +
        '<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>\n', 
      protected: false
    },
    excerpt: {
      rendered: '<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>\n',
      protected: false
    },
    author: 1,
    featured_media: 0,
    comment_status: 'open',
    ping_status: 'open',
    sticky: false,
    template: '',
    format: 'standard',
    meta: {
      bgseo_title: '',
      bgseo_description: '',
      bgseo_robots_index: '',
      bgseo_robots_follow: ''
    },
    categories: [ 1 ],
    tags: [],
    aioseo_notices: [],
    _links: {
      self: [Array],
      collection: [Array],
      about: [Array],
      author: [Array],
      replies: [Array],
      'version-history': [Array],
      'wp:attachment': [Array],
      'wp:term': [Array],
      curies: [Array]
    }
  },
  _paging: {
    total: 1,
    totalPages: 1,
    links: { 'https://api.w.org/': 'https://example.com/wp-json/' }
  }
]

Using Fetch to send the post

Now I'm trying code from a guide I found on Medium, and I'm having pretty much the same problem. I receive a response that I believe means the connection was successful, but no posts have been created on my site, draft or otherwise.

Here's the code:

import fetch from "node-fetch"


const createdPost = await fetch(`https://www.example.com/wp-json/wp/v2/posts`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Basic ${Buffer.from("username:application_password", "utf-8").toString("base64")}`
    },
    body: JSON.stringify({
      title: 'New post title',
      content: 'New content'
    })
  })
  console.log(createdPost)

And this is what is logged:

Response {
  size: 0,
  [Symbol(Body internals)]: {
    body: PassThrough {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 6,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      [Symbol(kCapture)]: false,
      [Symbol(kCallback)]: null
    },
    stream: PassThrough {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 6,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      [Symbol(kCapture)]: false,
      [Symbol(kCallback)]: null
    },
    boundary: null,
    disturbed: false,
    error: null
  },
  [Symbol(Response internals)]: {
    type: 'default',
    url: 'https://example.com/wp-json/wp/v2/posts',
    status: 200,
    statusText: 'OK',
    headers: {
      'access-control-allow-headers': 'Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type',
      'access-control-expose-headers': 'X-WP-Total, X-WP-TotalPages, Link',
      allow: 'GET',
      'cache-control': 'max-age=172800',
      connection: 'Upgrade, close',
      'content-type': 'application/json; charset=UTF-8',
      date: 'Mon, 03 Oct 2022 14:43:35 GMT',
      expires: 'Wed, 05 Oct 2022 14:43:35 GMT',
      link: '<https://example.com/wp-json/>; rel="https://api.w.org/"',
      server: 'Apache',
      'transfer-encoding': 'chunked',
      upgrade: 'h2',
      vary: 'Accept-Encoding,Cookie,Origin,User-Agent',
      'x-content-type-options': 'nosniff',
      'x-robots-tag': 'noindex',
      'x-wp-total': '1',
      'x-wp-totalpages': '1'
    },
    counter: 1,
    highWaterMark: 16384
  }
}

Summary

Both methods seem to connect but no post is created on my site. Can anyone help? I'm stuck and would really appreciate it.

1

There are 1 best solutions below

0
CSEO On

I'm not sure if you were able to figure this out but I had success creating a new post using node-fetch so attaching a snippet of my code here:

import fetch from 'node-fetch';

const url = 'https://MY_HOSTNAME/wp-json/wp/v2/posts';

export const uploadWP = async ({ title, content }: {title: string, content: string}) => {
  // token is a combination of username and application password which was generated from the wp admin dashboard (in my user profile)
  const token = Buffer.from('cseo:XXXX XXXX XXXX XXXX XXXX XXXX', 'utf-8').toString('base64');
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Basic ${token}`
    },
    body: JSON.stringify({
        title,
        content,
        status: 'draft'
      })
  });

  const responseBody = await response.text();
  console.log('response', responseBody);
}

if (require.main === module) {
  const articles = require('../migration/json/articles.json');
  const article = articles.articles?.[0];
  uploadWP({ title: article.title, content: article.htmlBody });
}

It's baffling as my code is nearly identical to yours..? I'm not sure if not having a status in the content body ('published', 'draft' etc. docs here) was your issue? (I'm assuming you use an actual username and password combo in the your real code). But just leaving this here for your reference.