wordpress_client 0.0.1 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +30 -0
- data/.codeclimate.yml +23 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +147 -90
- data/.yardopts +1 -0
- data/Changelog.md +16 -0
- data/Gemfile +6 -1
- data/README.md +48 -14
- data/Rakefile +37 -0
- data/lib/wordpress_client/category.rb +2 -0
- data/lib/wordpress_client/client.rb +235 -79
- data/lib/wordpress_client/connection.rb +10 -10
- data/lib/wordpress_client/errors.rb +41 -6
- data/lib/wordpress_client/media.rb +49 -1
- data/lib/wordpress_client/media_parser.rb +3 -0
- data/lib/wordpress_client/paginated_collection.rb +61 -4
- data/lib/wordpress_client/post.rb +63 -16
- data/lib/wordpress_client/post_parser.rb +12 -39
- data/lib/wordpress_client/rest_parser.rb +4 -0
- data/lib/wordpress_client/tag.rb +2 -0
- data/lib/wordpress_client/term.rb +30 -0
- data/lib/wordpress_client/version.rb +5 -1
- data/lib/wordpress_client.rb +21 -5
- data/spec/client_spec.rb +17 -181
- data/spec/connection_spec.rb +15 -14
- data/spec/docker/Dockerfile +35 -10
- data/spec/docker/README.md +53 -16
- data/spec/docker/dbdump.sql.gz +0 -0
- data/spec/docker/restore-dbdump.sh +2 -2
- data/spec/docker/yum.repos.d/CentOS-Base.repo +25 -0
- data/spec/fixtures/image-media.json +1 -1
- data/spec/fixtures/post-with-metadata.json +99 -1
- data/spec/fixtures/simple-post.json +324 -1
- data/spec/integration/attachments_crud_spec.rb +1 -1
- data/spec/integration/posts_crud_spec.rb +1 -1
- data/spec/integration/posts_finding_spec.rb +0 -69
- data/spec/integration/posts_metadata_spec.rb +11 -11
- data/spec/integration/posts_with_attachments_spec.rb +20 -6
- data/spec/media_spec.rb +14 -0
- data/spec/post_spec.rb +5 -31
- data/spec/spec_helper.rb +1 -0
- data/spec/support/docker_runner.rb +33 -13
- data/spec/support/wordpress_server.rb +112 -74
- data/wordpress_client.gemspec +17 -17
- metadata +43 -31
- data/.hound.yml +0 -2
- data/.ruby-version +0 -1
- data/circle.yml +0 -3
- data/lib/wordpress_client/replace_metadata.rb +0 -81
- data/lib/wordpress_client/replace_terms.rb +0 -62
- data/spec/fixtures/post-with-forbidden-metadata.json +0 -1
- data/spec/integration/category_assignment_spec.rb +0 -29
- data/spec/integration/tag_assignment_spec.rb +0 -29
- data/spec/replace_metadata_spec.rb +0 -56
- data/spec/replace_terms_spec.rb +0 -51
data/README.md
CHANGED
@@ -1,24 +1,31 @@
|
|
1
1
|
# WordpressClient
|
2
2
|
|
3
|
-
|
3
|
+
> :warning: **This project is in "maintenance mode" meaning that no patches will be accepted unless security related. We do not recommend using this gem, current users are recommended to migrate to another solution.**
|
4
4
|
|
5
|
-
|
5
|
+
WordpressClient is a very simple client for the Wordpress [REST API][api].
|
6
6
|
|
7
|
-
[![Circle CI](https://circleci.com/gh/hemnet/
|
7
|
+
[![Circle CI](https://circleci.com/gh/hemnet/wordpress_client.svg?style=svg)](https://circleci.com/gh/hemnet/wordpress_client) [![Code Climate](https://codeclimate.com/repos/5645938269568041da00cded/badges/5e870b57428f23c1f2ff/gpa.svg)](https://codeclimate.com/repos/5645938269568041da00cded/feed) [![Gem Version](https://badge.fury.io/rb/wordpress_client.svg)](https://badge.fury.io/rb/wordpress_client)
|
8
8
|
|
9
9
|
## Usage
|
10
10
|
|
11
|
-
|
11
|
+
**[Read the full API documentation][docs]**
|
12
|
+
|
13
|
+
Initialize a client with a user name, password and API URL. You can then search
|
14
|
+
for posts.
|
12
15
|
|
13
16
|
```ruby
|
14
|
-
client = WordpressClient.new(
|
17
|
+
client = WordpressClient.new(
|
18
|
+
url: "https://example.com/wp-json/",
|
19
|
+
username: "example",
|
20
|
+
password: "example",
|
21
|
+
)
|
15
22
|
|
16
23
|
client.posts(per_page: 5) # => [WordpressClient::Post, WordpressClient::Post]
|
17
24
|
```
|
18
25
|
|
19
26
|
### Creating a post
|
20
27
|
|
21
|
-
You can create posts by calling `create_post`.
|
28
|
+
You can create posts by calling `create_post`.
|
22
29
|
|
23
30
|
```ruby
|
24
31
|
data = {
|
@@ -29,20 +36,24 @@ data = {
|
|
29
36
|
post = client.create_post(data) # => WordpressClient::Post
|
30
37
|
updated_post = client.update_post(post.id, title: "Updated") # => WordpressClient::Post
|
31
38
|
|
39
|
+
updated_post.author # => "Name"
|
32
40
|
updated_post.title_html # => "Updated"
|
33
41
|
```
|
34
42
|
|
35
43
|
## Running tests
|
36
44
|
|
37
|
-
You need to install Docker and set it up for your machine.
|
45
|
+
You need to install Docker and set it up for your machine.
|
38
46
|
|
39
|
-
Run tests using the normal `rspec` command after installing all bundles.
|
47
|
+
Run tests using the normal `rspec` command after installing all bundles.
|
40
48
|
|
41
49
|
```
|
42
50
|
bundle exec rspec
|
43
51
|
```
|
44
52
|
|
45
|
-
You can also run `bundle exec guard` to have tests run automatically when you
|
53
|
+
You can also run `bundle exec guard` to have tests run automatically when you
|
54
|
+
change files in the repo. If you tag your examples with `focus: true`, Guard
|
55
|
+
will only run those tests. This can help when doing very focused coding, but
|
56
|
+
remember to remove the filter before you commit and let the entire suite run.
|
46
57
|
|
47
58
|
```ruby
|
48
59
|
describe Foo, focus: true do
|
@@ -50,14 +61,37 @@ describe Foo, focus: true do
|
|
50
61
|
end
|
51
62
|
```
|
52
63
|
|
53
|
-
The normal `rspec` command will *not* use this filter in case it is ever
|
64
|
+
The normal `rspec` command will *not* use this filter in case it is ever
|
65
|
+
committed accidentally, so CI can catch any problems.
|
66
|
+
|
67
|
+
## Releasing a new version
|
68
|
+
|
69
|
+
The normal gem release cycle works using `rake release`.
|
70
|
+
|
71
|
+
If you make changes to the docker image, you can release it using `rake
|
72
|
+
docker:release`.
|
54
73
|
|
55
74
|
## Copyright & License
|
56
75
|
|
57
|
-
Copyright © 2015 Hemnet Service HNS AB
|
76
|
+
Copyright © 2015-2017 Hemnet Service HNS AB
|
77
|
+
|
78
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
79
|
+
this software and associated documentation files (the "Software"), to deal in
|
80
|
+
the Software without restriction, including without limitation the rights to
|
81
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
82
|
+
of the Software, and to permit persons to whom the Software is furnished to do
|
83
|
+
so, subject to the following conditions:
|
58
84
|
|
59
|
-
|
85
|
+
The above copyright notice and this permission notice shall be included in all
|
86
|
+
copies or substantial portions of the Software.
|
60
87
|
|
61
|
-
|
88
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
89
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
90
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
91
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
92
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
93
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
94
|
+
SOFTWARE.
|
62
95
|
|
63
|
-
|
96
|
+
[api]: https://developer.wordpress.org/rest-api/
|
97
|
+
[docs]: http://www.rubydoc.info/gems/wordpress_client/
|
data/Rakefile
CHANGED
@@ -1 +1,38 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
require "yard"
|
3
|
+
require "wordpress_client/version"
|
4
|
+
|
5
|
+
YARD::Rake::YardocTask.new
|
6
|
+
|
7
|
+
namespace :docker do
|
8
|
+
DOCKER_DIR = File.expand_path("../spec/docker", __FILE__).freeze
|
9
|
+
IMAGE_NAME = "hemnet/wordpress_client_test".freeze
|
10
|
+
DEV_IMAGE = [IMAGE_NAME, "dev"].join(":").freeze
|
11
|
+
|
12
|
+
desc "Build the docker image"
|
13
|
+
task :build do
|
14
|
+
sh "docker", "build", "-t", DEV_IMAGE, DOCKER_DIR
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Release current dev build"
|
18
|
+
task release: :build do
|
19
|
+
version = prompt "Which version do you want to release"
|
20
|
+
raise "Invalid version string" unless version =~ /\A[\d.]+\z/
|
21
|
+
|
22
|
+
latest = prompt "Do you want this to be the :latest release? [Y/n]"
|
23
|
+
latest = (latest.empty? || latest.casecmp("y").zero?)
|
24
|
+
|
25
|
+
sh "docker", "tag", DEV_IMAGE, "#{IMAGE_NAME}:#{version}"
|
26
|
+
sh "docker", "push", "#{IMAGE_NAME}:#{version}"
|
27
|
+
|
28
|
+
if latest
|
29
|
+
sh "docker", "tag", DEV_IMAGE, "#{IMAGE_NAME}:latest"
|
30
|
+
sh "docker", "push", "#{IMAGE_NAME}:latest"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def prompt(message)
|
36
|
+
print "#{message} > "
|
37
|
+
STDIN.gets.strip
|
38
|
+
end
|
@@ -4,108 +4,267 @@ module WordpressClient
|
|
4
4
|
@connection = connection
|
5
5
|
end
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
# @!group Posts
|
8
|
+
|
9
|
+
# Find {Post Posts} matching given parameters.
|
10
|
+
#
|
11
|
+
# @example Finding 5 posts
|
12
|
+
# posts = client.posts(per_page: 5)
|
13
|
+
#
|
14
|
+
# @param page [Fixnum] Current page for pagination. Defaults to 1.
|
15
|
+
# @param per_page [Fixnum] Posts per page. Defaults to 10.
|
16
|
+
#
|
17
|
+
# @return {PaginatedCollection[Post]} Paginated collection of the found posts.
|
18
|
+
def posts(per_page: 10, page: 1)
|
11
19
|
connection.get_multiple(
|
12
|
-
Post,
|
20
|
+
Post,
|
21
|
+
"posts",
|
22
|
+
per_page: per_page,
|
23
|
+
page: page,
|
24
|
+
_embed: nil,
|
13
25
|
)
|
14
26
|
end
|
15
27
|
|
16
|
-
|
17
|
-
|
28
|
+
# Find the {Post} with the given ID, or raises an error if not found.
|
29
|
+
#
|
30
|
+
# @return {Post}
|
31
|
+
# @raise {NotFoundError}
|
32
|
+
# @raise {subclasses of Error} on other unexpected errors
|
33
|
+
def find_post(id)
|
34
|
+
connection.get(Post, "posts/#{id.to_i}", _embed: nil)
|
18
35
|
end
|
19
36
|
|
20
|
-
|
21
|
-
|
37
|
+
# Create a new {Post} with the given attributes in Wordpress and return it.
|
38
|
+
#
|
39
|
+
# In addition to {http://v2.wp-api.org/reference/posts/ the accepted
|
40
|
+
# parameters of the API}, this method also takes the following keys:
|
41
|
+
# * +:meta+
|
42
|
+
# * +:category_ids+
|
43
|
+
# * +:tag_ids+
|
44
|
+
#
|
45
|
+
# @see http://v2.wp-api.org/reference/posts/ List of accepted parameters
|
46
|
+
# @param attributes [Hash<Symbol,Object>] attribute list, containing
|
47
|
+
# accepted parameters or the custom parameters listed
|
48
|
+
# above.
|
49
|
+
# @option attributes [Hash<String,String>] meta Hash of meta values.
|
50
|
+
# @option attributes [Array<Fixnum>] category_ids List of category IDs the
|
51
|
+
# Post should belong to.
|
52
|
+
# @option attributes [Array<Fixnum>] tag_ids List of tag IDs the Post
|
53
|
+
# should have.
|
54
|
+
#
|
55
|
+
# @return {Post}
|
56
|
+
# @raise {ValidationError}
|
57
|
+
# @raise {subclasses of Error} on other unexpected errors
|
58
|
+
def create_post(attributes)
|
59
|
+
connection.create(Post, "posts", attributes, redirect_params: {_embed: nil})
|
22
60
|
end
|
23
61
|
|
24
|
-
|
25
|
-
|
62
|
+
# Update the {Post} with the given id, setting the supplied attributes in
|
63
|
+
# Wordpress and returning an updated Post.
|
64
|
+
#
|
65
|
+
# In addition to {http://v2.wp-api.org/reference/posts/ the accepted
|
66
|
+
# parameters of the API}, this method also takes the following keys:
|
67
|
+
# * +:meta+
|
68
|
+
# * +:category_ids+
|
69
|
+
# * +:tag_ids+
|
70
|
+
#
|
71
|
+
# @example Changing the title of a Post
|
72
|
+
# new_post = client.update_post(post.id, title: "A better title")
|
73
|
+
# new_post.title_html #=> "A better title"
|
74
|
+
#
|
75
|
+
# @see http://v2.wp-api.org/reference/posts/ List of accepted parameters
|
76
|
+
# @param id [Fixnum] ID of the post to update.
|
77
|
+
# @param attributes [Hash<Symbol,Object>] attribute list, containing
|
78
|
+
# accepted parameters or the custom parameters listed
|
79
|
+
# above.
|
80
|
+
# @option attributes [Hash<String,String>] meta Hash of meta values.
|
81
|
+
# @option attributes [Array<Fixnum>] category_ids List of category IDs the
|
82
|
+
# Post should belong to.
|
83
|
+
# @option attributes [Array<Fixnum>] tag_ids List of tag IDs the Post
|
84
|
+
# should have.
|
85
|
+
#
|
86
|
+
# @return {Post}
|
87
|
+
# @raise {NotFoundError}
|
88
|
+
# @raise {ValidationError}
|
89
|
+
# @raise {subclasses of Error} on other unexpected errors
|
90
|
+
def update_post(id, attributes)
|
91
|
+
connection.put(Post, "posts/#{id.to_i}", attributes)
|
26
92
|
end
|
27
93
|
|
28
|
-
|
29
|
-
|
94
|
+
# Deletes the {Post} with the given ID.
|
95
|
+
#
|
96
|
+
# @param id [Fixnum] The {Post} ID.
|
97
|
+
# @param force [Boolean] When +false+, the Post will be put in the "Trash"
|
98
|
+
# of Wordpress. +true+ causes the Post to be irrevocably deleted.
|
99
|
+
#
|
100
|
+
# @return true always
|
101
|
+
def delete_post(id, force: false)
|
102
|
+
connection.delete("posts/#{id.to_i}", {"force" => force})
|
30
103
|
end
|
31
104
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
raise NotFoundError, "Could not find post with slug #{slug.to_s.inspect}"
|
40
|
-
end
|
105
|
+
# @!group Categories
|
106
|
+
|
107
|
+
# Find {Category Categories} in the Wordpress install.
|
108
|
+
#
|
109
|
+
# @return {PaginatedCollection[Category]}
|
110
|
+
def categories(per_page: 10, page: 1)
|
111
|
+
connection.get_multiple(Category, "categories", page: page, per_page: per_page)
|
41
112
|
end
|
42
113
|
|
114
|
+
# Find {Category} with the given ID.
|
115
|
+
#
|
116
|
+
# @return {Category}
|
117
|
+
# @raise {NotFoundError}
|
118
|
+
# @raise {subclasses of Error} on other unexpected errors
|
43
119
|
def find_category(id)
|
44
|
-
connection.get(Category, "
|
120
|
+
connection.get(Category, "categories/#{id.to_i}")
|
45
121
|
end
|
46
122
|
|
47
|
-
|
48
|
-
|
123
|
+
# Create a new {Category} with the given attributes.
|
124
|
+
#
|
125
|
+
# @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
|
126
|
+
# @param attributes [Hash<Symbol,Object>] attribute list, containing
|
127
|
+
# parameters accepted by the API.
|
128
|
+
# @option attributes [String] name Name of the category (required).
|
129
|
+
# @option attributes [String] slug Slug of the category (optional).
|
130
|
+
# @option attributes [String] description Description of the category (optional).
|
131
|
+
#
|
132
|
+
# @return {Category} the new Category
|
133
|
+
# @raise {ValidationError}
|
134
|
+
# @raise {subclasses of Error} on other unexpected errors
|
135
|
+
def create_category(attributes)
|
136
|
+
connection.create(Category, "categories", attributes)
|
49
137
|
end
|
50
138
|
|
51
|
-
|
52
|
-
|
139
|
+
# Update the {Category} with the given id, setting the supplied attributes.
|
140
|
+
#
|
141
|
+
# @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
|
142
|
+
# @param attributes [Hash<Symbol,Object>] attribute list, containing
|
143
|
+
# parameters accepted by the API.
|
144
|
+
# @option attributes [String] name Name of the category.
|
145
|
+
# @option attributes [String] slug Slug of the category.
|
146
|
+
# @option attributes [String] description Description of the category.
|
147
|
+
#
|
148
|
+
# @return {Category} the updated Category
|
149
|
+
# @raise {NotFoundError}
|
150
|
+
# @raise {ValidationError}
|
151
|
+
# @raise {subclasses of Error} on other unexpected errors
|
152
|
+
def update_category(id, attributes)
|
153
|
+
connection.put(Category, "categories/#{id.to_i}", attributes)
|
53
154
|
end
|
54
155
|
|
55
|
-
|
56
|
-
post = connection.create(Post, "posts", attributes, redirect_params: {_embed: nil})
|
57
|
-
|
58
|
-
changes = 0
|
59
|
-
changes += assign_meta(post, attributes[:meta])
|
60
|
-
changes += assign_categories(post, attributes[:category_ids])
|
61
|
-
changes += assign_tags(post, attributes[:tag_ids])
|
156
|
+
# @!group Tags
|
62
157
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
158
|
+
# Find {Tag Tags} in the Wordpress install.
|
159
|
+
#
|
160
|
+
# @return {PaginatedCollection[Tag]}
|
161
|
+
def tags(per_page: 10, page: 1)
|
162
|
+
connection.get_multiple(Tag, "tags", page: page, per_page: per_page)
|
68
163
|
end
|
69
164
|
|
70
|
-
|
71
|
-
|
165
|
+
# Find {Tag} with the given ID.
|
166
|
+
#
|
167
|
+
# @return {Tag}
|
168
|
+
# @raise {NotFoundError}
|
169
|
+
# @raise {subclasses of Error} on other unexpected errors
|
170
|
+
def find_tag(id)
|
171
|
+
connection.get(Tag, "tags/#{id.to_i}")
|
72
172
|
end
|
73
173
|
|
174
|
+
# Create a new {Tag} with the given attributes.
|
175
|
+
#
|
176
|
+
# @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
|
177
|
+
# @param attributes [Hash<Symbol,Object>] attribute list, containing
|
178
|
+
# parameters accepted by the API.
|
179
|
+
# @option attributes [String] name Name of the tag (required).
|
180
|
+
# @option attributes [String] slug Slug of the tag (optional).
|
181
|
+
# @option attributes [String] description Description of the tag (optional).
|
182
|
+
#
|
183
|
+
# @return {Tag} the new Tag
|
184
|
+
# @raise {ValidationError}
|
185
|
+
# @raise {subclasses of Error} on other unexpected errors
|
74
186
|
def create_tag(attributes)
|
75
|
-
connection.create(Tag, "
|
187
|
+
connection.create(Tag, "tags", attributes)
|
76
188
|
end
|
77
189
|
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
190
|
+
# Update the {Tag} with the given id, setting the supplied attributes.
|
191
|
+
#
|
192
|
+
# @see http://v2.wp-api.org/reference/taxonomies/ List of accepted parameters
|
193
|
+
# @param attributes [Hash<Symbol,Object>] attribute list, containing
|
194
|
+
# parameters accepted by the API.
|
195
|
+
# @option attributes [String] name Name of the tag.
|
196
|
+
# @option attributes [String] slug Slug of the tag.
|
197
|
+
# @option attributes [String] description Description of the tag.
|
198
|
+
#
|
199
|
+
# @return {Tag} the updated Tag
|
200
|
+
# @raise {NotFoundError}
|
201
|
+
# @raise {ValidationError}
|
202
|
+
# @raise {subclasses of Error} on other unexpected errors
|
203
|
+
def update_tag(id, attributes)
|
204
|
+
connection.put(Tag, "tags/#{id.to_i}", attributes)
|
91
205
|
end
|
92
206
|
|
93
|
-
|
94
|
-
connection.patch(Category, "terms/category/#{id.to_i}", attributes)
|
95
|
-
end
|
207
|
+
# @!group Media
|
96
208
|
|
97
|
-
|
98
|
-
|
209
|
+
# Find {Media} in the Wordpress install.
|
210
|
+
#
|
211
|
+
# @return {PaginatedCollection[Media]}
|
212
|
+
def media(per_page: 10, page: 1)
|
213
|
+
connection.get_multiple(Media, "media", page: page, per_page: per_page)
|
99
214
|
end
|
100
215
|
|
101
|
-
|
102
|
-
|
216
|
+
# Find {Media} with the given ID.
|
217
|
+
#
|
218
|
+
# @return {Media}
|
219
|
+
# @raise {NotFoundError}
|
220
|
+
# @raise {subclasses of Error} on other unexpected errors
|
221
|
+
def find_media(id)
|
222
|
+
connection.get(Media, "media/#{id.to_i}")
|
103
223
|
end
|
104
224
|
|
225
|
+
# Create a new {Media} by uploading a IO stream.
|
226
|
+
#
|
227
|
+
# You need to provide both MIME type and filename for Wordpress to accept
|
228
|
+
# the file.
|
229
|
+
#
|
230
|
+
# @example Uploading a JPEG from a request
|
231
|
+
# media = client.upload(
|
232
|
+
# request.body_stream, filename: "foo.jpg", mime_type: "image/jpeg"
|
233
|
+
# )
|
234
|
+
#
|
235
|
+
# @param io [IO-like object] IO stream (for example an open file) that will
|
236
|
+
# be the body of the media.
|
237
|
+
# @param mime_type [String] the MIME type of the IO stream
|
238
|
+
# @param filename [String] the filename that Wordpress should see. Requires
|
239
|
+
# a file extension to make Wordpress happy.
|
240
|
+
#
|
241
|
+
# @return {Media} the new Media
|
242
|
+
# @raise {ValidationError}
|
243
|
+
# @raise {subclasses of Error} on other unexpected errors
|
244
|
+
# @see #upload_file #upload_file - a shortcut for uploading files on disk
|
105
245
|
def upload(io, mime_type:, filename:)
|
106
246
|
connection.upload(Media, "media", io, mime_type: mime_type, filename: filename)
|
107
247
|
end
|
108
248
|
|
249
|
+
# Create a new {Media} by uploading a file from disk.
|
250
|
+
#
|
251
|
+
# You need to provide MIME type for Wordpress to accept the file. The
|
252
|
+
# filename that Wordpress sees will automatically be derived from the
|
253
|
+
# passed path.
|
254
|
+
#
|
255
|
+
# @example Uploading a JPEG from disk
|
256
|
+
# media = client.upload_file(
|
257
|
+
# "assets/ocean.jpg", mime_type: "image/jpeg"
|
258
|
+
# )
|
259
|
+
#
|
260
|
+
# @param filename [String] a path to a readable file.
|
261
|
+
# @param mime_type [String] the MIME type of the file.
|
262
|
+
#
|
263
|
+
# @return {Media} the new Media
|
264
|
+
# @raise {ValidationError}
|
265
|
+
# @raise {subclasses of Error} on other unexpected errors
|
266
|
+
# @see #upload #upload - for when you want to upload something that isn't a
|
267
|
+
# file on disk, or need extra flexibility
|
109
268
|
def upload_file(filename, mime_type:)
|
110
269
|
path = filename.to_s
|
111
270
|
File.open(path, 'r') do |file|
|
@@ -113,30 +272,27 @@ module WordpressClient
|
|
113
272
|
end
|
114
273
|
end
|
115
274
|
|
116
|
-
|
117
|
-
|
275
|
+
# Update the {Media} with the given id, setting the supplied attributes.
|
276
|
+
#
|
277
|
+
# @see http://v2.wp-api.org/reference/media/ List of accepted parameters
|
278
|
+
# @param attributes [Hash<Symbol,Object>] attribute list, containing
|
279
|
+
# parameters accepted by the API.
|
280
|
+
#
|
281
|
+
# @return {Media} The updated Media
|
282
|
+
# @raise {NotFoundError}
|
283
|
+
# @raise {ValidationError}
|
284
|
+
# @raise {subclasses of Error} on other unexpected errors
|
285
|
+
def update_media(id, attributes)
|
286
|
+
connection.put(Media, "media/#{id.to_i}", attributes)
|
118
287
|
end
|
119
288
|
|
289
|
+
# @!endgroup
|
290
|
+
|
120
291
|
def inspect
|
121
292
|
"#<WordpressClient::Client #{connection.inspect}>"
|
122
293
|
end
|
123
294
|
|
124
295
|
private
|
125
296
|
attr_reader :connection
|
126
|
-
|
127
|
-
def assign_categories(post, ids)
|
128
|
-
return 0 unless ids
|
129
|
-
ReplaceTerms.apply_categories(connection, post, ids)
|
130
|
-
end
|
131
|
-
|
132
|
-
def assign_tags(post, ids)
|
133
|
-
return 0 unless ids
|
134
|
-
ReplaceTerms.apply_tags(connection, post, ids)
|
135
|
-
end
|
136
|
-
|
137
|
-
def assign_meta(post, meta)
|
138
|
-
return 0 unless meta
|
139
|
-
ReplaceMetadata.apply(connection, post, meta)
|
140
|
-
end
|
141
297
|
end
|
142
298
|
end
|
@@ -2,6 +2,7 @@ require "faraday"
|
|
2
2
|
require "json"
|
3
3
|
|
4
4
|
module WordpressClient
|
5
|
+
# @private
|
5
6
|
class Connection
|
6
7
|
attr_reader :url, :username
|
7
8
|
|
@@ -49,14 +50,14 @@ module WordpressClient
|
|
49
50
|
true
|
50
51
|
end
|
51
52
|
|
52
|
-
def
|
53
|
+
def put(model, path, attributes)
|
53
54
|
model.parse(
|
54
|
-
parse_json_response(send_json(path, attributes, method: :
|
55
|
+
parse_json_response(send_json(path, attributes, method: :put))
|
55
56
|
)
|
56
57
|
end
|
57
58
|
|
58
|
-
def
|
59
|
-
handle_status_code(send_json(path, attributes, method: :
|
59
|
+
def put_without_response(path, attributes)
|
60
|
+
handle_status_code(send_json(path, attributes, method: :put))
|
60
61
|
true
|
61
62
|
end
|
62
63
|
|
@@ -65,9 +66,7 @@ module WordpressClient
|
|
65
66
|
response = post_data(path, body, {
|
66
67
|
"Content-Length" => body.size.to_s,
|
67
68
|
"Content-Type" => mime_type,
|
68
|
-
|
69
|
-
# https://github.com/WP-API/WP-API/issues/1744
|
70
|
-
"Content-Disposition" => "filename=#{filename || "unnamed"}",
|
69
|
+
"Content-Disposition" => 'attachment; filename="' + (filename || "unnamed") + '"',
|
71
70
|
})
|
72
71
|
|
73
72
|
if response.status == 201 # Created
|
@@ -88,7 +87,7 @@ module WordpressClient
|
|
88
87
|
end
|
89
88
|
|
90
89
|
def setup_network_connection
|
91
|
-
Faraday.new(url: "
|
90
|
+
Faraday.new(url: File.join(url, "wp/v2")) do |conn|
|
92
91
|
conn.request :basic_auth, username, @password
|
93
92
|
conn.adapter :net_http
|
94
93
|
end
|
@@ -111,8 +110,9 @@ module WordpressClient
|
|
111
110
|
def get_json_and_response(path, params = {})
|
112
111
|
response = net.get(path, params)
|
113
112
|
[parse_json_response(response), response]
|
114
|
-
rescue Faraday::
|
115
|
-
raise TimeoutError
|
113
|
+
rescue Faraday::ConnectionFailed => error
|
114
|
+
raise TimeoutError if error.cause.class == Net::OpenTimeout
|
115
|
+
raise
|
116
116
|
end
|
117
117
|
|
118
118
|
def send_json(path, data, method: :post)
|
@@ -1,10 +1,45 @@
|
|
1
1
|
module WordpressClient
|
2
|
-
|
2
|
+
# Base class for all errors emitted from this gem. Rescue this in order to
|
3
|
+
# catch everything.
|
4
|
+
#
|
5
|
+
# See the list of subclasses for more specific error types.
|
6
|
+
class Error < ::StandardError; end
|
3
7
|
|
4
|
-
|
8
|
+
# Raised when the clients attempt to do something that the user isn't
|
9
|
+
# authorized to do.
|
10
|
+
#
|
11
|
+
# This could happen if you try to delete a post and the user only has
|
12
|
+
# read-only access, for example.
|
13
|
+
# It would also happen if you provide bad authentication details.
|
14
|
+
#
|
15
|
+
# @see Error
|
16
|
+
class UnauthorizedError < Error; end
|
5
17
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
18
|
+
# Raised when a request times out.
|
19
|
+
#
|
20
|
+
# @see Error
|
21
|
+
class TimeoutError < Error; end
|
22
|
+
|
23
|
+
# Raised when the server had an error, or when the server returned something
|
24
|
+
# unexpected, despite saying everything went okay. It's the most generic
|
25
|
+
# "Something went wrong with the request" error.
|
26
|
+
#
|
27
|
+
# @see Error
|
28
|
+
class ServerError < Error; end
|
29
|
+
|
30
|
+
# Raised when trying to find a resource that doesn't exist. It will also
|
31
|
+
# happen when you try to update a resource that doesn't exist.
|
32
|
+
#
|
33
|
+
# Lack of authorization can also mask actual resources so it appears that
|
34
|
+
# they don't exist.
|
35
|
+
#
|
36
|
+
# @see Error
|
37
|
+
class NotFoundError < Error; end
|
38
|
+
|
39
|
+
# Raised when the server rejects the body of a request. The error message
|
40
|
+
# will often include information about why the body was rejected, but it is
|
41
|
+
# not guaranteed.
|
42
|
+
#
|
43
|
+
# @see Error
|
44
|
+
class ValidationError < Error; end
|
10
45
|
end
|