ruby-wordpress 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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