app/models/locomotive/concerns/site/metafields.rb
module Locomotive
module Concerns
module Site
module Metafields
extend ActiveSupport::Concern
include Concerns::Shared::JsonAttribute
included do
## fields ##
field :metafields, type: Hash, default: {}
field :metafields_schema, type: Array, default: []
field :metafields_ui, type: Hash, default: {}
## behaviours ##
json_attribute :metafields_schema
json_attribute :metafields
json_attribute :metafields_ui
end
def has_metafields?
!self.metafields_schema.blank?
end
def any_localized_metafield?
return false unless self.has_metafields?
self.metafields_schema.any? { |g| g['fields'].any? { |f| f['localized'] == true } }
end
def find_metafield(name)
return nil if name.blank? || !has_metafields?
fields = self.metafields_schema.map { |g| g['fields'] }.flatten
fields.find do |f|
_name = f['name'].downcase.underscore.gsub(' ', '_')
_name == name
end
end
def cast_metafields(namespace)
return nil if namespace.blank? || !has_metafields?
schema = self.metafields_schema.find { |s| s['name'] == namespace }
values = self.metafields[namespace]
return nil if schema.blank? || values.blank?
values.map do |name, value|
field = schema['fields'].find { |f| f['name'] == name }
next unless field
[name, cast_metafield_value(field, value)]
end.compact.to_h
end
protected
def _metafields_schema_schema
{
'id' => 'http://locomotive.works/schemas/metafields.json',
'definitions' => {
'field' => {
'type' => 'object',
'properties' => {
'name' => { 'type' => 'string', 'pattern' => '^[A-Za-z0-9_]+$', 'not': { 'enum': ['dom_id', 'model_name', 'method_missing', '_name', '_label', '_position', '_fields', '_t'] } },
'label' => { 'type' => ['string', 'object'] },
'hint' => { 'type' => ['string', 'object'] },
'type' => { 'enum' => ['string', 'text', 'integer', 'float', 'image', 'boolean', 'select', 'color'] },
'position' => { 'type' => 'integer' },
'select_options' => { 'type' => ['object', 'array'] },
'localized' => { 'type' => 'boolean' },
},
'required' => ['name']
}
},
'type' => 'array',
'items' => {
'type' => 'object',
'properties' => {
'name' => { 'type' => 'string', 'pattern' => '^[A-Za-z0-9_]+$' },
'label' => { 'type' => ['string', 'object'] },
'fields' => { 'type' => 'array', 'items': {'$ref': '#/definitions/field' } },
'position' => { 'type' => 'integer', 'minimum' => 0 }
},
'required' => ['name', 'fields']
}
}
end
def cast_metafield_value(field, value)
case field['type']
when 'boolean'
['1', 'true', true].include?(value)
when 'integer'
Integer(value)
else
value
end
end
end
end
end
end