Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
afbbcf4
fix media compatibility
Dec 11, 2017
34228a9
Add full media size
robbiet480 Dec 25, 2017
1ba8ba0
Implement custom time formatting
robbiet480 Dec 25, 2017
abb4033
Add URL discovery functions
robbiet480 Dec 25, 2017
e8fe629
Add settings
robbiet480 Dec 25, 2017
ffc021e
support jwt/ bearer token auth
dannynash Jan 17, 2018
7bd6de0
Make registered date a Time field
robbiet480 Jan 27, 2018
15a7d06
Add Locale field to User
robbiet480 Jan 27, 2018
cea3b97
Support time with zone info for Users.RegisteredDate
robbiet480 Jan 27, 2018
92103ad
Merge remote-tracking branch 'dannynash/master'
robbiet480 Jan 27, 2018
39b92b7
Expose time formats
robbiet480 Jan 28, 2018
6a80e88
Fill in post struct more
robbiet480 Jan 28, 2018
4f91da2
Change package URL
robbiet480 Jan 28, 2018
2f93c3c
go vet cleanup
robbiet480 Jan 28, 2018
5b3b89d
Remove duplicate ModifiedGMT field
robbiet480 Jan 28, 2018
d178d45
Add categories and tags support
robbiet480 Jan 28, 2018
f3e2853
Minor styling fixes
robbiet480 Feb 3, 2018
89c602e
Support getting root API info
robbiet480 Feb 3, 2018
6a4824c
Support decoding timestamps to timezone of site
robbiet480 Feb 4, 2018
4bf43ea
Add basic info support to DiscoverAPI function
robbiet480 Feb 4, 2018
e179b32
Wrap responses to get pagination data
robbiet480 Feb 4, 2018
d373e10
Overhaul library to be a bit more stable, add features like paging, u…
robbiet480 Feb 4, 2018
5e973a8
Update README.md
robbiet480 Feb 4, 2018
782b5bd
Stop using new as a variable as it is a reserved keyword
robbiet480 Feb 5, 2018
1e265be
cleanup entityURLs
robbiet480 Feb 5, 2018
c80cf64
Remove authentication information from the client, cleanup the README…
robbiet480 Feb 5, 2018
78ee0a2
Remove options in favor of just a base URL + http.Client
robbiet480 Feb 5, 2018
e273270
Remove _warning
robbiet480 Feb 5, 2018
6bd4049
Update .gitignore
robbiet480 Feb 5, 2018
257a8d9
Fix bad struct name usage
robbiet480 Feb 5, 2018
69a2216
Fix pagination
robbiet480 Feb 5, 2018
3aec9d8
Remove TLS skip verify
robbiet480 Feb 5, 2018
bb88296
log.Print -> log.Println
robbiet480 Feb 5, 2018
073fdaf
Improve comments on struct fields
robbiet480 Feb 5, 2018
638b589
Make error data a struct
robbiet480 Feb 5, 2018
4403ab3
Encode slices in URLs with brackets
robbiet480 Feb 5, 2018
c542a22
Dynamically generate structs with pretty comments and all possible pr…
robbiet480 Feb 5, 2018
d24ae11
Users uses ListOptions now
robbiet480 Feb 5, 2018
3acbc10
Move common list fields to ListOptions
robbiet480 Feb 5, 2018
1968354
Fix tests
robbiet480 Feb 5, 2018
01b6fbf
minor README.md tweaks
robbiet480 Feb 5, 2018
d2de05b
Remove WordPressRESTAPI struct
robbiet480 Feb 5, 2018
9c30e55
fix user comments
robbiet480 Feb 5, 2018
0ff8aa3
Update README.md
robbiet480 Feb 5, 2018
5d516a1
Use time.Time for before/after
robbiet480 Feb 5, 2018
1726f02
Fix BasicInfo request
robbiet480 Feb 6, 2018
3b8369f
Authentication can be an array instead of map
robbiet480 Feb 6, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out

# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
Expand All @@ -19,7 +32,7 @@ _cgo_export.*

_testmain.go

*.exe
*.test
*.prof
credential.txt

.idea
13 changes: 13 additions & 0 deletions .gometalinter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"Disable": [
"aligncheck",
"gocyclo",
"maligned"
],
"Deadline": "5m",
"Sort": [
"path",
"linter"
],
"Vendor": true
}
156 changes: 119 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# go-wp-api
Golang client library for WP-API (Wordpress REST API)
# go-wordpress
[![GoDoc](https://godoc.org/github.com/robbiet480/go-wordpress?status.svg)](https://godoc.org/github.com/robbiet480/go-wordpress)

A Go client library for the [Wordpress REST API](https://developer.wordpress.org/rest-api/)


## Installation

```bash
go get github.com/sogko/go-wordpress

go get github.com/robbiet480/go-wordpress
```

## Usage
Expand All @@ -16,76 +17,157 @@ go get github.com/sogko/go-wordpress
package main

import (
"github.com/sogko/go-wordpress"
"net/http"
"context"
"fmt"
"net/http"

"github.com/robbiet480/go-wordpress"
)

func main() {

tp := wordpress.BasicAuthTransport{
Username: USER,
Password: PASSWORD,
}

// create wp-api client
client := wordpress.NewClient(&wordpress.Options{
BaseAPIURL: API_BASE_URL, // example: `http://192.168.99.100:32777/wp-json/wp/v2`
Username: USER,
Password: PASSWORD,
})

client, _ := wordpress.NewClient(API_BASE_URL, tp.Client())

ctx := context.Background()

// for eg, to get current user (GET /users/me)
currentUser, resp, body, _ := client.Users().Me()
if resp.StatusCode != http.StatusOK {
currentUser, resp, _ := client.Users.Me(ctx, nil)
if resp != nil && resp.StatusCode != http.StatusOK {
// handle error
}

// `body` will contain raw JSON body in []bytes


// Or you can use your own structs (for custom endpoints, for example)
// Below is the equivalent of `client.Posts().Get(100, nil)`
// Below is the equivalent of `client.Posts.Get(ctx, 100, nil)`
var obj MyCustomPostStruct
resp, body, err := client.Get("/posts/100", nil, &obj)
resp, err := client.Get(ctx, "/posts/100", nil, &obj)
// ...

log.Println("Current user", currentUser)
}

fmt.Printf("Current user %+v", currentUser)
}
```

For more examples, see package tests.

For list of supported/implemented endpoints, see [Endpoints.md](./endpoints.md)

### Authentication

The go-wordpress library does not directly handle authentication. Instead, when
creating a new client, pass an `http.Client` that can handle authentication for
you.

Note that when using an authenticated Client, all calls made by the client will
include the specified authentication transport token. Therefore, authenticated clients should
almost never be shared between different users.

#### Username/Password or Application Password

A basic authentication (username/password) client for use with
the [WP-API BasicAuth plugin](https://github.com/WP-API/Basic-Auth)
or [Application Passwords plugin](https://wordpress.org/plugins/application-passwords/)
is included with the library.
An example implementation can be found in [example/basicauth/main.go](example/basicauth/main.go).

#### OAuth 1.0a

If you use the [OAuth 1.0a Server](https://github.com/WP-API/OAuth1) for authentication,
you can find an example implementation in [example/oauth2/main.go](example/oauth2/main.go) using the oauth1 library
(which is very similar to the official OAuth 2.0 library).
See the [oauth1 docs](https://godoc.org/dghubble/oauth1) for complete instructions on using that library.

#### OAuth 2.0 and JWT

If you are using the [JWT](https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/) plug-in for authentication,
you can use the [oauth2](https://github.com/golang/oauth2) library's `StaticTokenSource`.
An example implementation can be found in [example/oauth2/main.go](example/oauth2/main.go).
See the [oauth2 docs](https://godoc.org/golang.org/x/oauth2) for complete instructions on using that library.

#### Other authentication styles

For any other authentication methods, you should only need to provide a custom `http.Client` when creating a new WordPress client.

### Pagination

All requests for resource collections (posts, pages, media, revisions, etc.)
support pagination. Pagination options are described in the
`wordpress.ListOptions` struct and passed to the list methods directly or as an
embedded type of a more specific list options struct (for example
`wordpress.PostListOptions`). Pages information is available via the
`wordpress.Response` struct.

```go
package main

import (
"context"

"github.com/robbiet480/go-wordpress"
)

func main() {
tp := wordpress.BasicAuthTransport{
Username: USER,
Password: PASSWORD,
}

// create wp-api client
client, _ := wordpress.NewClient(API_BASE_URL, tp.Client())

ctx := context.Background()

opt := &wordpress.PostListOptions{
ListOptions: wordpress.ListOptions{PerPage: 10},
}
// get all pages of results
var allPosts []*wordpress.Post
for {
posts, resp, err := client.Posts.List(ctx, opt)
if err != nil {
return err
}
allPosts = append(allPosts, posts...)
if resp.NextPage == 0 {
break
}
opt.Page = resp.NextPage
}
}
```

## Test

__Note:__
Before running the tests, ensure that you have set up your test environment


### Prerequisites
- Wordpress 4.x
- WP-API plugin
- WP-API's BasicAuth plugin (for authentication)
- [WP REST API Meta Endpoints plugin](https://github.com/WP-API/wp-api-meta-endpoints) (for Meta endpoints)
- [WP-API's BasicAuth plugin (for authentication)](https://github.com/WP-API/Basic-Auth)

### Setting up test environment
- Install prequisits (see above)
- Install prequisites (see above)
- Import [./test-data/go-wordpress.wordpress.2015-08-23.xml](./test-data/go-wordpress.wordpress.2015-08-23.xml) to your local test Wordpress installation
- Upload at least one media to your Wordpress installation (Admin > Media > Upload)
- Edit one (1) most recent Post to create a revision
- Edit one (1) most recent Page to create a revision

## Running test

## Running tests

```bash

# Set test enviroment
export WP_API_URL=http://192.168.99.100:32777/wp-json/wp/v2
export WP_API_URL=http://192.168.99.100:32777/wp-json/
export WP_USER=<user>
export WP_PASSWD=<password>

cd <path_to_package>/github.com/sogko/go-wordpress
cd $GOPATH/src/github.com/robbiet480/go-wordpress
go test

```

## TODO
- [ ] `godoc` documentation, so its easier for library users to map the REST APIs to library calls
- [ ] Test `comments` API endpoint. (Currently, already implemented but not tested due to WP-API issues with creating comments reliably)
- [ ] Support OAuth authentication
## Thanks

Large parts of this library were inspired if not outright copied from Google's excellent [`go-github`](https://github.com/google/go-github) library.
72 changes: 72 additions & 0 deletions categories.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package wordpress

import (
"context"
"fmt"
)

// Category represents a WordPress post/page category.
type Category struct {
ID int `json:"id"`
Count int `json:"count"`
Description string `json:"description"`
Link string `json:"link"`
Name string `json:"name"`
Slug string `json:"slug"`
Taxonomy string `json:"taxonomy"`
Parent int `json:"parent"`
}

// CategoriesService provides access to the category related functions in the WordPress REST API.
type CategoriesService service

// List returns a list of categories.
func (c *CategoriesService) List(ctx context.Context, opts *CategoryListOptions) ([]*Category, *Response, error) {
u, err := addOptions("categories", opts)
if err != nil {
return nil, nil, err
}

req, err := c.client.NewRequest("GET", u, nil)
if err != nil {
return nil, nil, err
}

categories := []*Category{}
resp, err := c.client.Do(ctx, req, &categories)
if err != nil {
return nil, resp, err
}
return categories, resp, nil
}

// Create creates a new category.
func (c *CategoriesService) Create(ctx context.Context, newCategory *Category) (*Category, *Response, error) {
var created Category
resp, err := c.client.Create(ctx, "categories", newCategory, &created)
return &created, resp, err
}

// Get returns a single category for the given id.
func (c *CategoriesService) Get(ctx context.Context, id int, params interface{}) (*Category, *Response, error) {
var entity Category
entityURL := fmt.Sprintf("categories/%v", id)
resp, err := c.client.Get(ctx, entityURL, params, &entity)
return &entity, resp, err
}

// Update updates a single category with the given id.
func (c *CategoriesService) Update(ctx context.Context, id int, post *Category) (*Category, *Response, error) {
var updated Category
entityURL := fmt.Sprintf("categories/%v", id)
resp, err := c.client.Update(ctx, entityURL, post, &updated)
return &updated, resp, err
}

// Delete removes the category with the given id.
func (c *CategoriesService) Delete(ctx context.Context, id int, params interface{}) (*Category, *Response, error) {
var deleted Category
entityURL := fmt.Sprintf("categories/%v", id)
resp, err := c.client.Delete(ctx, entityURL, params, &deleted)
return &deleted, resp, err
}
Loading