Class: Compostr::CustomPostType

Inherits:
Object
  • Object
show all
Defined in:
lib/compostr/custom_post_type.rb

Overview

Base class to inherit from for Classes that map to Wordpress Custom Post Types.

Besides the post_id, title, content, excerpt and featured_image (id) that define a post, the CustomPostType likely will own custom field values. These are specified with wp_custom_field_single and wp_custom_field_multi (depending on their type).

To loop over the fields, use @fields and @multi_fields.

Direct Known Subclasses

NullCustomPostType

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(**kwargs) ⇒ CustomPostType

Returns a new instance of CustomPostType.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/compostr/custom_post_type.rb', line 105

def initialize **kwargs
  @fields = Hash.new
  # This one is painful, maybe field? and field!?
  #@fields.default_proc = proc do |hash, key|
  #  hash[key] = CustomFieldValue.new(nil, key, nil)
  #end
  @multi_fields = Hash.new
  @multi_fields.default_proc = proc do |hash, key|
    hash[key] = []
  end
  kwargs.each do |k,v|
    if k == :title
      # strip ?
      @title = v
    elsif k == :content
      self.content= v
    elsif k == :excerpt
      self.excerpt= v
    elsif k == :post_id
      self.post_id= v
    elsif k == :featured_image_id
      @featured_image_id = v
    # Better: has_custom_field?
    elsif respond_to?(k.to_sym)
      self.send(((k.to_s) + "=").to_sym, v)
    elsif additional_field_action == :add
      @fields[k.to_sym] = CustomFieldValue.new(nil, k.to_sym, v)
    end
  end
end

Instance Attribute Details

#contentObject

Returns the value of attribute content.



12
13
14
# File 'lib/compostr/custom_post_type.rb', line 12

def content
  @content
end

#excerptObject

Returns the value of attribute excerpt.



12
13
14
# File 'lib/compostr/custom_post_type.rb', line 12

def excerpt
  @excerpt
end

Returns the value of attribute featured_image_id.



12
13
14
# File 'lib/compostr/custom_post_type.rb', line 12

def featured_image_id
  @featured_image_id
end

#fieldsObject

TODO rename to single_fields?



14
15
16
# File 'lib/compostr/custom_post_type.rb', line 14

def fields
  @fields
end

#multi_fieldsObject

TODO rename to single_fields?



14
15
16
# File 'lib/compostr/custom_post_type.rb', line 14

def multi_fields
  @multi_fields
end

#post_idObject

Returns the value of attribute post_id.



12
13
14
# File 'lib/compostr/custom_post_type.rb', line 12

def post_id
  @post_id
end

#titleObject

Returns the value of attribute title.



12
13
14
# File 'lib/compostr/custom_post_type.rb', line 12

def title
  @title
end

Class Method Details

.additional_field_action(action) ⇒ Object

Define whether additional custom fields should be

:ignore -> ignored (default)
:delete -> marked for deletion
:add    -> added

Other values for action will silently be ignored.



94
95
96
97
98
99
# File 'lib/compostr/custom_post_type.rb', line 94

def self.additional_field_action(action)
  if [:ignore, :delete, :add].include? action.to_sym
    # @additional_field_action = :action
    self.class_eval("@additional_field_action = :#{action}")
  end
end

.from_content_hash(content_hash) ⇒ Object

From a Hash as returned by RubyPress’s getPost(s) method populate and return a new CustomPostType-instance.

Custom field values will be created as specified by the wp_custom_field_single/multi definitions.



200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/compostr/custom_post_type.rb', line 200

def self.from_content_hash content_hash
  return nil if content_hash.nil?
  entity = new(post_id: content_hash["post_id"],
               content: content_hash["post_content"],
               excerpt: content_hash["post_excerpt"],
               title:   content_hash["post_title"])

  custom_fields_list = content_hash["custom_fields"] || []

  supported_fields.each do |field_key|
    #puts "iterating over supported field #{field_key}"
    if is_single_field? field_key
      # Here: duplicate deletion possible
      field = custom_fields_list.find{|f| f["key"] == field_key}
      if field
        entity.send("#{field_key}=".to_sym, field["value"])
        entity.field?(field_key).id = field["id"]
      end
    else
      fields = custom_fields_list.select{|f| f["key"] == field_key}
      values = fields.map{|f| f["value"]}
      entity.send("#{field_key}=".to_sym, values)
      # Not elegant: Set the id one per one
      fields.each do |f|
        entity.set_field_id(field_key, f["value"], f["id"])
      end
    end
  end
  # if additional fields add, add these

  entity
end

.is_multi_field?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


305
306
307
# File 'lib/compostr/custom_post_type.rb', line 305

def self.is_multi_field?(field_name)
  supported_multi_fields.include? field_name
end

.is_single_field?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


313
314
315
# File 'lib/compostr/custom_post_type.rb', line 313

def self.is_single_field?(field_name)
  supported_single_fields.include? field_name
end

.supported_fieldsObject

Returns list of field keys generally supported by this Custom Post Type.



174
175
176
# File 'lib/compostr/custom_post_type.rb', line 174

def self.supported_fields
  supported_single_fields | supported_multi_fields
end

.supported_multi_fieldsObject

Returns list of multiple-valued field keys generally supported by this Custom Post Type.



186
187
188
# File 'lib/compostr/custom_post_type.rb', line 186

def self.supported_multi_fields
  instance_variable_get(:@supported_multi_fields) || []
end

.supported_single_fieldsObject

Returns list of single-valued field keys generally supported by this Custom Post Type.



180
181
182
# File 'lib/compostr/custom_post_type.rb', line 180

def self.supported_single_fields
  instance_variable_get(:@supported_single_fields) || []
end

.wp_custom_field_multi(field_key) ⇒ Object

Specify a field that will make and take a fine array.



55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/compostr/custom_post_type.rb', line 55

def self.wp_custom_field_multi(field_key)
  # def field_key=(new_value)
  #   multi_field('field_key') = new_value.map{|v| CustomFieldValue.new(nil, 'field_key', v)}
  # end
  # TODO recycle!
  self.class_eval("def #{field_key.to_s}=(new_value); @multi_fields['#{field_key.to_s}'] = new_value.map{|v| CustomFieldValue.new(nil, '#{field_key.to_s}', v)}; end")
  # def field_key
  #   multi_field(field_key).map(&:value).compact
  # end
  self.class_eval("def #{field_key.to_s}; return multi_field('#{field_key.to_s}').map(&:value).compact; end")

  # Add field to @supported_(multi_)fields.
  # This is declared in the class, thus a kindof CLASS variable!
  self.class_eval("(@supported_multi_fields ||= []) << '#{field_key}'")
end

.wp_custom_field_single(field_key) ⇒ Object

Defines accessor methods for the field, which will only allow a single value.

Note that the accessor only wears strings and automatically strips



39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/compostr/custom_post_type.rb', line 39

def self.wp_custom_field_single(field_key)
  # def field_key=(new_value)
  #   field!('field_key') = new_value.to_s.strip
  # end
  self.class_eval("def #{field_key.to_s}=(new_value); field!('#{field_key.to_s}').value = WPString.wp_string(new_value); end")
  # def field_key
  #   field?(field_key).value
  # end
  self.class_eval("def #{field_key.to_s}; return field?('#{field_key.to_s}').value; end")

  # Add field to @supported_(single_)fields.
  # This is declared in the class, thus a kindof CLASS variable!
  self.class_eval("(@supported_single_fields ||= []) << '#{field_key}'")
end

.wp_post_content_alias(content_alias) ⇒ Object

Alias the post_content getter and setter with another ‘name’.



78
79
80
81
# File 'lib/compostr/custom_post_type.rb', line 78

def self.wp_post_content_alias(content_alias)
  self.class_eval("alias :#{content_alias.to_sym}= :content=")
  self.class_eval("alias :#{content_alias.to_sym}  :content")
end

.wp_post_title_alias(title_alias) ⇒ Object

Alias the post_title getter and setter with another ‘name’.



72
73
74
75
# File 'lib/compostr/custom_post_type.rb', line 72

def self.wp_post_title_alias(title_alias)
  self.class_eval("alias :#{title_alias.to_sym}= :title=")
  self.class_eval("alias :#{title_alias.to_sym}  :title")
end

.wp_post_type(wp_post_type) ⇒ Object

Define accessor method to the POST_TYPE (Class#post_type and Instance#post_type).



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/compostr/custom_post_type.rb', line 18

def self.wp_post_type(wp_post_type)
  # TODO syntax: define_method("....")

  # Class wide variable (could also be a constant)
  self.class_eval("POST_TYPE = '#{wp_post_type}'.freeze")
  # Class accessor method
  # def self.post_type
  #   POST_TYPE
  # end
  self.class_eval("def self.post_type; POST_TYPE; end")
  # Instance accessor method
  # def post_type
  #   POST_TYPE
  # end
  self.class_eval("def post_type; POST_TYPE; end")
end

Instance Method Details

#additional_field_actionObject



101
102
103
# File 'lib/compostr/custom_post_type.rb', line 101

def additional_field_action
  self.class.instance_variable_get(:@additional_field_action) || :ignore
end

#custom_fields_hashObject



136
137
138
# File 'lib/compostr/custom_post_type.rb', line 136

def custom_fields_hash
  @fields.values.map(&:to_hash)
end

#diff(other_cpt_object) ⇒ Object

Returns hash where keys are field names where the values differ. values of returned hash are arrays like [own_value, other_different_value]. Returns empty hash to signalize equaliness.



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
# File 'lib/compostr/custom_post_type.rb', line 335

def diff(other_cpt_object)
  if other_cpt_object.nil?
    other_cpt_object = NullCustomPostType.new
  end

  diff_fields = {}
  # Fields exclusive to this one.
  (@fields.keys - other_cpt_object.fields.keys).each do |f|
    diff_fields[f] = [@fields[f].value, nil]
  end
  # Fields exclusive to the other.
  (other_cpt_object.fields.keys - @fields.keys).each do |f|
    diff_fields[f] = [nil, other_cpt_object.fields[f].value]
  end
  # Mutual fields
  (@fields.keys | other_cpt_object.fields.keys).each do |f|
    field_value = field?(f).value
    other_field_value = other_cpt_object.field?(f).value
    if other_field_value != field_value
      diff_fields[f] = [field_value, other_field_value]
    end
  end
  # Multi-Fields exclusive to this one.
  (@multi_fields.keys - other_cpt_object.multi_fields.keys).each do |f|
    diff_fields[f] = [@multi_fields[f].map(&:value), nil]
  end
  # Multi-Fields exclusive to the other.
  (other_cpt_object.multi_fields.keys - @multi_fields.keys).each do |f|
    diff_fields[f] = [nil, other_cpt_object.multi_fields[f].map(&:value)]
  end
  # Mutual Multi-fields
  (@multi_fields.keys | other_cpt_object.multi_fields.keys).each do |f|
    field_values = multi_field(f).map(&:value).compact
    other_field_values = other_cpt_object.multi_field(f).map(&:value).compact
    if other_field_values != field_values
      diff_fields[f] = [field_values, other_field_values]
    end
  end
  if @title.to_s.strip != other_cpt_object.title.to_s.strip
    diff_fields["title"] = [@title, other_cpt_object.title]
  end
  if @excerpt.to_s.strip != other_cpt_object.excerpt.to_s.strip
    diff_fields["excerpt"] = [@excerpt, other_cpt_object.excerpt]
  end
  if @featured_image_id != other_cpt_object.featured_image_id
    diff_fields["featured_image_id"] = [@featured_image_id, other_cpt_object.featured_image_id]
  end
  if @content.to_s.strip != other_cpt_object.content.to_s.strip
    diff_fields["content"] = [@content, other_cpt_object.content]
  end
  diff_fields
end

#different_from?(other_cpt_object) ⇒ Boolean

Returns:

  • (Boolean)


388
389
390
# File 'lib/compostr/custom_post_type.rb', line 388

def different_from? other_cpt_object
  !diff(other_cpt_object).empty?
end

#field!(field_name) ⇒ Object

Access (or create) a CustomFieldValue that can hold a single value.



154
155
156
157
158
159
160
161
# File 'lib/compostr/custom_post_type.rb', line 154

def field!(field_name)
  # ||= would probably do, too.
  if @fields.key? field_name
    @fields[field_name]
  else
    @fields[field_name] = CustomFieldValue.new(nil, field_name, nil)
  end
end

#field?(field_name) ⇒ Boolean

Access the given field, returns a NullCustomFieldValue if not found. The NullCustomFieldValue does not accept setting any values and returns nil for id, key and value.

Use this to (readonly) access a field with given name.

Returns:

  • (Boolean)


145
146
147
148
149
150
151
# File 'lib/compostr/custom_post_type.rb', line 145

def field?(field_name)
  if @fields.key? field_name
    @fields[field_name]
  else
    NullCustomFieldValue.new
  end
end

#has_custom_field?(field_name) ⇒ Boolean

True iff supported fields include field_name

Returns:

  • (Boolean)


191
192
193
# File 'lib/compostr/custom_post_type.rb', line 191

def has_custom_field? field_name
  supported_fields.include? field_name
end

#in_wordpress?Boolean

Fetched from wordpress/ Post-ID known?

Returns:

  • (Boolean)


318
319
320
# File 'lib/compostr/custom_post_type.rb', line 318

def in_wordpress?
  post_id.to_s != '' && !!post_id
end

#integrate_field_ids(other_entity) ⇒ Object

When additional_field_action == :ignore (the default) sets (wp) ids of fields for which values are set.

If additional_field_action == :add CustomFieldValues of other_entity are copied if not yet existing in this entity (otherwise only the id of the fields are set.

Finally, if additional_field_action == :delete , mark the fields which are NOT set in this entity but in the other entity ready for deletion.

The ids are taken from other_entity (if available, left empty otherwise).



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/compostr/custom_post_type.rb', line 260

def integrate_field_ids other_entity
  # TODO rename and/or restructure this method
  # new from old
  fields.values.each do |f|
    if f.key.start_with? 'ref'
      puts "foreign fields : #{other_entity.fields.keys}"
      puts "foreign fields : #{other_entity.fields.values.map{|v| v.id.to_s + ' ' + v.id.class.to_s}}"
    puts "integrate field : #{f.key} #{f.inspect}"
    puts "    other field : #{other_entity.field?(f.key).inspect}"
    end
    f.id = other_entity.field?(f.key).id
  end

  if additional_field_action == :add
    # old to new
    other_entity.fields.values.each do |f|
      if !@fields.key?(f.key)
        @fields[f.key] = f
      end
    end
  elsif additional_field_action == :delete
    other_entity.fields.values.each do |f|
      if !@fields.key?(f.key)
        # This field will be deleted when used to edit Post
        @fields[f.key] = CustomFieldValue.new(f.id, nil, nil)
      end
    end
  end

  @multi_fields.each do |field_name, mf|
    ids = other_entity.multi_field(field_name).map(&:id)
    mf.each do |mf_entry|
      mf_entry.id = ids.delete_at(0) # keep order, use #pop otherwise
    end
    # If any ids left, delete these custom fields
    ids.each do |id|
      multi_field(field_name) << CustomFieldValue.new(id, nil, nil)
    end
  end
end

#is_multi_field?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


301
302
303
# File 'lib/compostr/custom_post_type.rb', line 301

def is_multi_field?(field_name)
  self.class.is_multi_field?(field_name)
end

#is_single_field?(field_name) ⇒ Boolean

Returns:

  • (Boolean)


309
310
311
# File 'lib/compostr/custom_post_type.rb', line 309

def is_single_field?(field_name)
  self.class.is_single_field?(field_name)
end

#multi_field(field_name) ⇒ Object

Access a CustomFieldValue that can hold multiple values (array).



164
165
166
# File 'lib/compostr/custom_post_type.rb', line 164

def multi_field(field_name)
  @multi_fields[field_name]
end

#set_field_id(field_key, field_value, field_id) ⇒ Object



322
323
324
325
326
327
328
329
# File 'lib/compostr/custom_post_type.rb', line 322

def set_field_id field_key, field_value, field_id
  if is_single_field? field_key
    # ????!! field!
    field?(field_key).id = field_id
  else
    multi_field(field_key).find{|f| f.key == field_key && f.value == field_value}.id = field_id
  end
end

#supported_fieldsObject

Returns list of field keys generally supported by this Custom Post Type.



169
170
171
# File 'lib/compostr/custom_post_type.rb', line 169

def supported_fields
  self.class.supported_fields
end

#to_content_hashObject



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/compostr/custom_post_type.rb', line 233

def to_content_hash
  content = {
    post_type:     post_type,
    post_status:   'publish',
    post_data:     Time.now,
    post_title:    title    || '', # why does content need '@'?
    post_content:  @content || '',
    post_excerpt:  @excerpt || '',
    custom_fields: @fields.map{|k,v| v.to_hash} | @multi_fields.flat_map{|k,v| v.flat_map(&:to_hash)}
  }
  if featured_image_id
    content[:post_thumbnail] = featured_image_id.to_s
  end
  content
end