ruby-wordpress 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 38f5112cc2886be6398ae4573f806025b0b8b6c9
4
- data.tar.gz: 3e4dbf0b9de205b21e7f33407d01b62985e02675
3
+ metadata.gz: 70e9d73a18077c70dd4974d042ecc80a068a97d4
4
+ data.tar.gz: fc64bc3a3c5e0d77a861c5c0180a4c76f58e973a
5
5
  SHA512:
6
- metadata.gz: 9f379fd8208d157b17811e2192a9101ebd54584177ddbbb517e8a4b8aaf4d88be76e2611ae95c11468997accaab6ed0b04f95dd779148a5d5ffd78e4d7b44ca3
7
- data.tar.gz: 8d095d6e1475059603430adebc374e8162946a85c0e835960a90c426d1ddbc6576c7aab288383c0b21d13ee5ee08e5348e018613b3eaf4404d787803aeccc62e
6
+ metadata.gz: fbeae0d88a1d4701ba0dcce78111342f674a673f4c14f40437e25b78fe3c38f80005465f83badb7721637cefc11cba0956cbc78b3d9405b9e69b14b7f80ce693
7
+ data.tar.gz: e54c1d9e11a1e3f421412a743d685084f48f602e0c9ecbaf5b4ff3195b950e67b62009ca98bf368ed10906a9ca47e0b6ffcdd5ae4c1f88f68b6d9f71a8135105
data/lib/wordpress.rb CHANGED
@@ -1,5 +1,11 @@
1
1
  require "wordpress/version"
2
2
 
3
+ require "wordpress/error"
4
+ require "wordpress/base"
5
+ require "wordpress/options"
6
+ require "wordpress/post"
7
+ require "wordpress/post/meta"
8
+
3
9
  require 'mysql2'
4
10
  require 'php_serialize'
5
11
  require 'cgi'
@@ -23,9 +29,124 @@ class WordPress
23
29
  @conn = Mysql2::Client.new options
24
30
  @conn.query_options.merge!(symbolize_keys: true)
25
31
 
32
+ @configuration = options
33
+
26
34
  # The WordPress options table
27
- @options = WP::Options.new @conn, @tbl
35
+ @options = WordPress::Options.new self
28
36
  end
29
37
 
30
38
  attr_reader :options
39
+
40
+ attr_reader :tbl
41
+ attr_reader :conn
42
+
43
+ attr_accessor :configuration
44
+
45
+ def query args
46
+ # Main query function.
47
+ # The goal is to support as much as the original WP_Query API as possible.
48
+ raise ArgumentError.new('Hash arguments are supported.') unless args.kind_of?(Hash)
49
+
50
+ # Defaults
51
+ args = {
52
+ post_type: 'post',
53
+ post_status: 'publish'
54
+ }.merge(args)
55
+
56
+ wheres_and = []
57
+ inner_joins = []
58
+
59
+ # Page finders
60
+
61
+ if args[:page_id]
62
+ args[:p] = args[:page_id]
63
+ args[:post_type] = 'page'
64
+ end
65
+
66
+ if args[:pagename]
67
+ args[:name] = args[:pagename]
68
+ args[:post_type] = 'page'
69
+ end
70
+
71
+ # Post finders
72
+
73
+ if args[:post_type]
74
+ wheres_and << "`#{@tbl[:posts]}`.`post_type`='#{ @conn.escape args[:post_type] }'"
75
+ end
76
+
77
+ if args[:p]
78
+ wheres_and << "`#{@tbl[:posts]}`.`ID`='#{ args[:p].to_i }'"
79
+ end
80
+
81
+ if args[:post_parent]
82
+ wheres_and << "`#{@tbl[:posts]}`.`post_parent`='#{ args[:post_parent].to_i }'"
83
+ end
84
+
85
+ if args[:name]
86
+ wheres_and << "`#{@tbl[:posts]}`.`post_name`='#{ @conn.escape args[:name] }'"
87
+ end
88
+
89
+ if args[:post_status]
90
+ wheres_and << "`#{@tbl[:posts]}`.`post_status`='#{ @conn.escape args[:post_status] }'"
91
+ end
92
+
93
+ if args[:post__in]
94
+ raise ArgumentError.new(':post__in should be an array.') unless args[:post__in].kind_of?(Array)
95
+ wheres_and << "`#{@tbl[:posts]}`.`ID` IN (#{ args[:post__in].map { |e| "'#{ e.to_i }'" }.join ', ' })"
96
+ end
97
+
98
+ if args[:post__not_in]
99
+ raise ArgumentError.new(':post__not_in should be an array.') unless args[:post__not_in].kind_of?(Array)
100
+ wheres_and << "`#{@tbl[:posts]}`.`ID` NOT IN (#{ args[:post__not_in].map { |e| "'#{ e.to_i }'" }.join ', ' })"
101
+ end
102
+
103
+ # Meta finders
104
+
105
+ if (mqs = args[:meta_query]) and mqs.kind_of?(Array)
106
+ inner_joins << "`#{@tbl[:postmeta]}` ON `#{@tbl[:posts]}`.`ID`=`#{@tbl[:postmeta]}`.`post_id`"
107
+ mqs.each do |mq|
108
+ mq_params = {
109
+ compare: '=',
110
+ type: 'CHAR' # Ignored for now
111
+ }.merge(mq)
112
+
113
+ # Allowed compares
114
+ mq_params[:compare] = '=' unless ['=', '!=', '>', '>=', '<', '<=', 'LIKE', 'NOT LIKE', 'IN', 'NOT IN', 'BETWEEN', 'NOT BETWEEN'].include?(mq_params[:compare])
115
+
116
+ wheres_and << "(`#{@tbl[:postmeta]}`.`meta_key`='#{@conn.escape mq_params[:key].to_s}' AND `#{@tbl[:postmeta]}`.`meta_value`='#{@conn.escape mq_params[:value].to_s}')"
117
+ end
118
+ end
119
+
120
+ query = "SELECT `#{@tbl[:posts]}`.* FROM `#{@tbl[:posts]}` "
121
+ if inner_joins.length > 0
122
+ query += "INNER JOIN #{inner_joins.join ', '} "
123
+ end
124
+
125
+ query += "WHERE #{ wheres_and.join ' AND ' }"
126
+
127
+ @conn.query(query).map do |row|
128
+ WordPress::Post.build self, row
129
+ end
130
+ end
131
+
132
+ def new_post args
133
+ # 'args' is a hash of attributes that WordPress::Post responds to
134
+ # See wordpress/post.rb
135
+ WordPress::Post.build self, args
136
+ end
137
+
138
+ def update_taxonomy_counts *taxes
139
+ taxes.each do |taxonomy|
140
+ @conn.query("SELECT `term_taxonomy_id`, `count` FROM `#{@tbl[:termtax]}` WHERE `taxonomy`='#{@conn.escape taxonomy.to_s}'").each do |term_tax|
141
+ termtax_id = term_tax[:term_taxonomy_id]
142
+ count = 0
143
+ @conn.query("SELECT COUNT(*) as `c` FROM `#{@tbl[:posts]}`, `#{@tbl[:termrel]}` WHERE `#{@tbl[:posts]}`.`ID`=`#{@tbl[:termrel]}`.`object_id` AND `#{@tbl[:termrel]}`.`term_taxonomy_id`='#{ termtax_id.to_i }'").each do |x|
144
+ count = x[:c]
145
+ end
146
+ if count != term_tax[:count]
147
+ @conn.query("UPDATE `#{@tbl[:termtax]}` SET `count`='#{count.to_i}' WHERE `term_taxonomy_id`='#{ termtax_id.to_i }'")
148
+ end
149
+ end
150
+ end
151
+ end
31
152
  end
@@ -3,9 +3,15 @@
3
3
  require 'unicode_utils/nfc'
4
4
 
5
5
  class WordPress::Base
6
- def initialize(connection, wp_tables)
7
- @tbl = wp_tables
8
- @conn = connection
6
+ def initialize root
7
+ @wp = root
8
+
9
+ @conn = @wp.conn
10
+ @tbl = @wp.tbl
11
+ end
12
+
13
+ def inspect
14
+ nil
9
15
  end
10
16
 
11
17
  def insert(table, content)
@@ -67,7 +73,6 @@ class WordPress::Base
67
73
  end
68
74
 
69
75
  def set_post_terms(post_id, terms, taxonomy, append=false)
70
- terms.map! { |e| UnicodeUtils.nfc(e) }
71
76
  terms_esc = terms.map { |e| "'#{@conn.escape e.to_s}'" }
72
77
  terms_slugs = terms.map { |e| "'#{@conn.escape(CGI::escape e.to_s)}'"}
73
78
  raise ArgumentError, 'Terms must be an array with more than zero elements' unless terms_esc.count > 0
@@ -0,0 +1,4 @@
1
+ # Encoding: UTF-8
2
+
3
+ class WordPress::Error < RuntimeError
4
+ end
@@ -0,0 +1,266 @@
1
+ # Encoding: UTF-8
2
+
3
+ require 'cgi'
4
+ require 'mime/types'
5
+ require 'RMagick'
6
+
7
+ class WordPress::Post < WordPress::Base
8
+ # Left: DB, right: our symbol
9
+ DB_MAP = {
10
+ :ID => :post_id
11
+ }
12
+
13
+ READONLY_ATTRIBUTES = [
14
+ :post_id
15
+ ]
16
+
17
+ WORDPRESS_ATTRIBUTES = {
18
+ :post_id => -1,
19
+ :post_author => 1,
20
+ :post_date => Time.new,
21
+ :post_date_gmt => Time.new.utc,
22
+ :post_content => '',
23
+ :post_title => '',
24
+ :post_excerpt => '',
25
+ :post_status => 'draft',
26
+ :comment_status => 'open',
27
+ :ping_status => 'open',
28
+ :post_password => '',
29
+ :post_name => '',
30
+ :to_ping => '',
31
+ :pinged => '',
32
+ :post_modified => Time.new,
33
+ :post_modified_gmt => Time.new.utc,
34
+ :post_content_filtered => '',
35
+ :post_parent => 0,
36
+ :guid => '0',
37
+ :menu_order => 0,
38
+ :post_type => 'post',
39
+ :post_mime_type => '',
40
+ :comment_count => 0
41
+ }
42
+
43
+ def to_h
44
+ Hash[ WORDPRESS_ATTRIBUTES.keys.map { |e| [e, instance_variable_get(:"@#{e}")] }]
45
+ end
46
+
47
+ def inspect
48
+ to_h.to_s
49
+ end
50
+
51
+ def persisted?
52
+ @post_id != -1 and !unsaved_changes?
53
+ end
54
+
55
+ def unsaved_changes
56
+ WORDPRESS_ATTRIBUTES.keys.select do |k|
57
+ false
58
+ true if instance_variable_get(:"@#{k}") != @in_database[k]
59
+ end
60
+ end
61
+
62
+ def unsaved_changes?
63
+ # Not an empty array of changes means there are unsaved changes.
64
+ unsaved_changes != []
65
+ end
66
+
67
+ WORDPRESS_ATTRIBUTES.keys.each do |att|
68
+ if READONLY_ATTRIBUTES.include? att
69
+ attr_reader att
70
+ else
71
+ attr_accessor att
72
+ end
73
+ end
74
+
75
+ def save
76
+ # We don't need to save because nothing has changed
77
+ return self if persisted?
78
+
79
+ new_id = update_or_insert @tbl[:posts], "`#{@tbl[:posts]}`.`ID`='#{ post_id.to_i }'", Hash[ WORDPRESS_ATTRIBUTES.keys.map { |e| [e, instance_variable_get(:"@#{e}")] }].reject { |k, v| READONLY_ATTRIBUTES.include? k }
80
+
81
+ # We'll assume everything went OK since no errors were thrown.
82
+ @in_database = Hash[ WORDPRESS_ATTRIBUTES.keys.map { |e| [e, instance_variable_get(:"@#{e}")] }]
83
+ if new_id and new_id > 0
84
+ @in_database[:post_id] = @post_id = new_id
85
+ end
86
+
87
+ self
88
+ end
89
+
90
+ def save!
91
+ save || raise(WordPress::Error.new('Save failed.'))
92
+ end
93
+
94
+ # Post Meta
95
+
96
+ def post_meta
97
+ raise 'Post must be saved before manipulating metadata' if @post_id == -1
98
+ @post_meta ||= WordPress::Post::Meta.new @wp, self
99
+ end
100
+
101
+ # Taxonomies
102
+
103
+ def get_the_terms taxonomy
104
+ raise 'Post must be saved before manipulating taxonomies' if @post_id == -1
105
+ super @post_id, taxonomy
106
+ end
107
+
108
+ def set_post_terms terms, taxonomy, append=false
109
+ raise 'Post must be saved before manipulating taxonomies' if @post_id == -1
110
+ terms = [terms] unless terms.kind_of?(Array)
111
+ current_terms = get_the_terms(taxonomy)
112
+ return current_terms if current_terms.sort == terms.sort && append == false
113
+ super @post_id, terms, taxonomy, append=false
114
+ end
115
+
116
+ # Attachments
117
+
118
+ def attach_featured_image image
119
+ img_id = attach_image(image).post_id
120
+ post_meta['_thumbnail_id'] = img_id
121
+ end
122
+
123
+ def attach_image image
124
+ raise 'Post must be saved before manipulating attached images' if @post_id == -1
125
+
126
+ # Make a new post with the "attachment" format
127
+ if image.respond_to? :open
128
+ handle = image.open
129
+ else
130
+ handle = image
131
+ end
132
+
133
+ title = (0...10).map{(65+rand(26)).chr}.join
134
+ if image.respond_to? :path
135
+ path = Pathname.new image.path
136
+ title = path.each_filename.to_a[-1]
137
+ end
138
+
139
+ mimetype = nil
140
+ ext = ''
141
+ if image.respond_to? :meta
142
+ mimetype = (image.meta['content-type'] || '').split(';')[0]
143
+ type = MIME::Types[mimetype].first
144
+ if type
145
+ ext = '.' + type.extensions.first
146
+ end
147
+ else
148
+ if type = MIME::Types.type_for(title).first
149
+ mimetype = types.content_type
150
+ # ext = types.extensions.first
151
+ end
152
+ end
153
+
154
+ # Build the pathname where this will go.
155
+ file_basename = File.join(@wp.configuration[:wordpress_wp_content], '/uploads')
156
+ uri_basename = @wp.configuration[:wordpress_wp_content_url] || (@wp.options['siteurl'] + '/wp-content/uploads')
157
+
158
+ today = Date.today
159
+ relative_filepath = "#{'%02d' % today.year}/#{'%02d' % today.month}/#{title}"
160
+
161
+ # Copy the file
162
+ local_filepath = Pathname.new(File.join(file_basename, relative_filepath + ext))
163
+ FileUtils.mkdir_p local_filepath.dirname.to_s
164
+
165
+ buffer = handle.read.force_encoding('BINARY')
166
+ out = File.open(local_filepath.to_s, 'wb')
167
+ out.write buffer
168
+ out.close
169
+
170
+ attachment = self.class.build @wp, {
171
+ post_title: title,
172
+ post_name: CGI::escape(title.downcase),
173
+ post_status: 'inherit',
174
+ post_parent: @post_id,
175
+ post_type: 'attachment',
176
+ post_mime_type: mimetype,
177
+ guid: uri_basename + '/' + relative_filepath + ext
178
+ }
179
+ attachment.save
180
+
181
+ attachment.post_meta['_wp_attached_file'] = relative_filepath + ext
182
+
183
+ # Get image metadata
184
+
185
+ begin
186
+ img = Magick::Image::read(local_filepath.to_s).first
187
+ size_hash = {}
188
+
189
+ thumbnail_filename = title + '-150x150' + ext
190
+ thumb_img = img.resize_to_fill(150, 150)
191
+ thumb_img.write File.join(file_basename, "#{'%02d' % today.year}/#{'%02d' % today.month}/#{thumbnail_filename}")
192
+
193
+ size_hash[:thumbnail] = {
194
+ file: thumbnail_filename,
195
+ width: 150,
196
+ height: 150
197
+ }
198
+
199
+ size_hash[:medium] = {
200
+ file: title + ext,
201
+ height: img.rows,
202
+ width: img.columns
203
+ }
204
+
205
+ size_hash[:large] = {
206
+ file: title + ext,
207
+ height: img.rows,
208
+ width: img.columns
209
+ }
210
+
211
+ attachment.post_meta['_wp_attachment_metadata'] = {
212
+ file: title + ext,
213
+ height: img.rows,
214
+ width: img.columns,
215
+ sizes: size_hash
216
+ }
217
+ rescue Exception => e
218
+ # raise e
219
+ puts "Warn: Ignoring exception #{e.to_s}"
220
+ end
221
+
222
+ attachment
223
+ end
224
+
225
+ def featured_image
226
+ thumb_id = post_meta['_thumbnail_id']
227
+ @wp.query(post_type: 'attachment', post_parent: @post_id, post_status: 'inherit', p: thumb_id).first if thumb_id
228
+ end
229
+
230
+ def attached_files *args
231
+ attach_args = {
232
+ post_type: 'attachment', post_parent: @post_id, post_status: 'inherit'
233
+ }.merge(args[0] || {})
234
+ @wp.query attach_args
235
+ end
236
+
237
+ # Initializators
238
+
239
+ def initialize root
240
+ super
241
+
242
+ WORDPRESS_ATTRIBUTES.each do |att, default|
243
+ instance_variable_set :"@#{att}", default
244
+ end
245
+
246
+ @in_database = {}
247
+ end
248
+
249
+ def self.build root, values
250
+ post = new root
251
+ # Use the map
252
+ values = Hash[values.map { |k, v| [DB_MAP[k] || k, v] }]
253
+
254
+
255
+ from_db = false
256
+ # Because the post ID is greater than zero, let's assume that this is a persisted record.
257
+ from_db = true if values[:post_id] and values[:post_id] > 0
258
+
259
+ values.select { |key, value| WORDPRESS_ATTRIBUTES.keys.include? key }.each do |key, value|
260
+ post.instance_variable_set(:"@#{key}", value)
261
+ post.instance_variable_get(:@in_database)[key] = value if from_db
262
+ end
263
+ post
264
+ end
265
+
266
+ end
@@ -0,0 +1,64 @@
1
+ # Encoding: UTF-8
2
+
3
+ require 'php_serialize'
4
+
5
+ class WordPress::Post::Meta < WordPress::Base
6
+
7
+ def initialize root, post
8
+ super root
9
+ @post = post
10
+ end
11
+
12
+ def [](key)
13
+ v = nil
14
+ @conn.query("SELECT `meta_value` FROM `#{@tbl[:postmeta]}` WHERE `meta_key`='#{@conn.escape key}' AND `post_id`='#{ @post.post_id.to_i }' LIMIT 1").each do |row|
15
+ v = row[:meta_value]
16
+ end
17
+ # Apply out-filters
18
+ if v
19
+ if v[0] == 'a' and v[-1] == '}'
20
+ # PHP-serialized array
21
+ v = PHP.unserialize v
22
+ end
23
+ end
24
+ v
25
+ end
26
+
27
+ def []=(key, value)
28
+ old_value = self[key]
29
+ # Apply in-filters
30
+
31
+ if value.kind_of?(Hash) or value.kind_of?(Array)
32
+ value = PHP.serialize value
33
+ end
34
+
35
+ if !value.nil? and !old_value.nil? and value != old_value
36
+ # Update operation.
37
+ @conn.query("UPDATE `#{@tbl[:postmeta]}` SET `meta_value`='#{@conn.escape value.to_s}' WHERE `meta_key`='#{@conn.escape key}' AND `post_id`='#{ @post.post_id.to_i }'")
38
+ elsif value.nil? and !old_value.nil?
39
+ # New value nil, old value not. Delete operation.
40
+ @conn.query("DELETE FROM `#{@tbl[:postmeta]}` WHERE `meta_key`='#{@conn.escape key}' AND `post_id`='#{ @post.post_id.to_i }'")
41
+ elsif !value.nil? and old_value.nil?
42
+ # New value non-nil, old value nil. Insert operation.
43
+ @conn.query("INSERT INTO `#{@tbl[:postmeta]}` (`meta_key`, `meta_value`, `post_id`) VALUES ('#{@conn.escape key}', '#{@conn.escape value.to_s}', '#{ @post.post_id.to_i }')")
44
+ end
45
+ value
46
+ end
47
+
48
+ def keys
49
+ all = []
50
+ @conn.query("SELECT `meta_key` FROM `#{@tbl[:postmeta]}` WHERE `post_id`='#{ @post.post_id.to_i }'").each { |x| all << x }
51
+ all.collect { |x| x[:meta_key] }
52
+ end
53
+
54
+ def to_s
55
+ to_h.to_s
56
+ end
57
+
58
+ def to_h
59
+ Hash[keys.map { |e| [e, self[e]] }]
60
+ end
61
+ alias_method :to_hash, :to_h
62
+ alias_method :inspect, :to_h
63
+
64
+ end
@@ -1,5 +1,5 @@
1
1
  class WordPress
2
2
  module Version
3
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
4
4
  end
5
5
  end
@@ -21,6 +21,8 @@ Gem::Specification.new do |spec|
21
21
  spec.add_dependency "mysql2", "~> 0.3.11"
22
22
  spec.add_dependency "unicode_utils", "~> 1.4.0"
23
23
  spec.add_dependency "k-php-serialize", "~> 1.2.0"
24
+ spec.add_dependency "mime-types", "~> 1.23"
25
+ spec.add_dependency 'rmagick', '= 2.13.2'
24
26
 
25
27
  spec.add_development_dependency "bundler", "~> 1.3"
26
28
  spec.add_development_dependency "rake"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-wordpress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keitaroh Kobayashi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-05-27 00:00:00.000000000 Z
11
+ date: 2013-06-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mysql2
@@ -52,6 +52,34 @@ dependencies:
52
52
  - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.2.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: mime-types
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.23'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.23'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rmagick
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '='
74
+ - !ruby/object:Gem::Version
75
+ version: 2.13.2
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 2.13.2
55
83
  - !ruby/object:Gem::Dependency
56
84
  name: bundler
57
85
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +122,10 @@ files:
94
122
  - Rakefile
95
123
  - lib/wordpress.rb
96
124
  - lib/wordpress/base.rb
125
+ - lib/wordpress/error.rb
97
126
  - lib/wordpress/options.rb
127
+ - lib/wordpress/post.rb
128
+ - lib/wordpress/post/meta.rb
98
129
  - lib/wordpress/version.rb
99
130
  - ruby-wordpress.gemspec
100
131
  homepage: https://github.com/keichan34/ruby-wordpress