camaleon_cms 2.9.1 → 2.9.3

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.
Files changed (241) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +29 -9
  3. data/Rakefile +3 -16
  4. data/app/apps/plugins/attack/admin_controller.rb +9 -6
  5. data/app/apps/plugins/attack/attack_helper.rb +35 -25
  6. data/app/apps/plugins/authoring_post/authoring_post_helper.rb +23 -16
  7. data/app/apps/plugins/front_cache/admin_controller.rb +16 -10
  8. data/app/apps/plugins/front_cache/config/initializer.rb +1 -1
  9. data/app/apps/plugins/front_cache/front_cache_helper.rb +57 -24
  10. data/app/apps/plugins/visibility_post/config/config.json +1 -0
  11. data/app/apps/plugins/visibility_post/config/routes_front.txt +1 -0
  12. data/app/apps/plugins/visibility_post/front_controller.rb +23 -0
  13. data/app/apps/plugins/visibility_post/visibility_post_helper.rb +141 -70
  14. data/app/apps/themes/camaleon_first/main_helper.rb +18 -12
  15. data/app/apps/themes/default/assets/css/style.css.scss +24 -0
  16. data/app/apps/themes/default/assets/genericons/genericons.css +3 -8
  17. data/app/apps/themes/default/default_helper.rb +2 -1
  18. data/app/apps/themes/default/views/category.html.erb +1 -1
  19. data/app/apps/themes/default/views/layouts/index.html.erb +3 -1
  20. data/app/apps/themes/default/views/post_tag.html.erb +1 -1
  21. data/app/apps/themes/default/views/post_type.html.erb +1 -1
  22. data/app/apps/themes/default/views/search.html.erb +1 -1
  23. data/app/apps/themes/new/assets/css/styles.css.scss +24 -0
  24. data/app/apps/themes/new/custom_helper.rb +5 -9
  25. data/app/apps/themes/new/views/category.html.erb +1 -1
  26. data/app/apps/themes/new/views/layouts/_header.html.erb +3 -1
  27. data/app/apps/themes/new/views/post_tag.html.erb +1 -1
  28. data/app/apps/themes/new/views/post_type.html.erb +1 -1
  29. data/app/apps/themes/new/views/search.html.erb +1 -1
  30. data/app/assets/javascripts/camaleon_cms/admin/_data.js +16 -0
  31. data/app/assets/javascripts/camaleon_cms/admin/_post.js +5 -2
  32. data/app/assets/javascripts/camaleon_cms/admin/nav_menu.js +14 -3
  33. data/app/assets/javascripts/camaleon_cms/admin/uploader/_media_manager.js +5 -0
  34. data/app/controllers/camaleon_cms/admin/appearances/nav_menus_controller.rb +29 -10
  35. data/app/controllers/camaleon_cms/admin/appearances/themes_controller.rb +8 -5
  36. data/app/controllers/camaleon_cms/admin/appearances/widgets/assign_controller.rb +9 -2
  37. data/app/controllers/camaleon_cms/admin/appearances/widgets/main_controller.rb +4 -3
  38. data/app/controllers/camaleon_cms/admin/appearances/widgets/sidebar_controller.rb +2 -2
  39. data/app/controllers/camaleon_cms/admin/categories_controller.rb +27 -8
  40. data/app/controllers/camaleon_cms/admin/comments_controller.rb +0 -1
  41. data/app/controllers/camaleon_cms/admin/installers_controller.rb +32 -1
  42. data/app/controllers/camaleon_cms/admin/media_controller.rb +84 -19
  43. data/app/controllers/camaleon_cms/admin/plugins_controller.rb +1 -3
  44. data/app/controllers/camaleon_cms/admin/post_tags_controller.rb +15 -6
  45. data/app/controllers/camaleon_cms/admin/posts/drafts_controller.rb +40 -11
  46. data/app/controllers/camaleon_cms/admin/posts_controller.rb +58 -22
  47. data/app/controllers/camaleon_cms/admin/sessions_controller.rb +238 -45
  48. data/app/controllers/camaleon_cms/admin/settings/custom_fields_controller.rb +103 -18
  49. data/app/controllers/camaleon_cms/admin/settings/post_types_controller.rb +17 -5
  50. data/app/controllers/camaleon_cms/admin/settings/sites_controller.rb +33 -7
  51. data/app/controllers/camaleon_cms/admin/settings_controller.rb +11 -6
  52. data/app/controllers/camaleon_cms/admin/user_roles_controller.rb +9 -7
  53. data/app/controllers/camaleon_cms/admin/users_controller.rb +89 -18
  54. data/app/controllers/camaleon_cms/admin_controller.rb +144 -26
  55. data/app/controllers/camaleon_cms/apps/plugins_admin_controller.rb +5 -0
  56. data/app/controllers/camaleon_cms/camaleon_controller.rb +37 -92
  57. data/app/controllers/camaleon_cms/frontend_controller.rb +140 -70
  58. data/app/controllers/concerns/camaleon_cms/admin/custom_fields_concern.rb +44 -0
  59. data/app/controllers/concerns/camaleon_cms/frontend_concern.rb +46 -17
  60. data/app/controllers/concerns/camaleon_cms/frontend_visited_state_concern.rb +72 -0
  61. data/app/controllers/concerns/camaleon_cms/hook_lifecycle_concern.rb +104 -0
  62. data/app/controllers/concerns/camaleon_cms/request_context_concern.rb +113 -0
  63. data/app/controllers/concerns/camaleon_cms/runtime_admin_menu_concern.rb +237 -0
  64. data/app/controllers/concerns/camaleon_cms/runtime_captcha_image_concern.rb +13 -0
  65. data/app/controllers/concerns/camaleon_cms/runtime_html_content_concern.rb +143 -0
  66. data/app/controllers/concerns/camaleon_cms/runtime_shortcode_theme_concern.rb +246 -0
  67. data/app/controllers/concerns/camaleon_cms/runtime_state_concern.rb +13 -0
  68. data/app/controllers/concerns/camaleon_cms/runtime_uploader_concern.rb +54 -0
  69. data/app/controllers/concerns/camaleon_cms/session_captcha_runtime_concern.rb +19 -0
  70. data/app/controllers/concerns/camaleon_cms/session_runtime_concern.rb +40 -0
  71. data/app/decorators/camaleon_cms/application_decorator.rb +11 -8
  72. data/app/decorators/camaleon_cms/category_decorator.rb +3 -2
  73. data/app/decorators/camaleon_cms/post_comment_decorator.rb +13 -5
  74. data/app/decorators/camaleon_cms/post_decorator.rb +67 -51
  75. data/app/decorators/camaleon_cms/post_type_decorator.rb +1 -1
  76. data/app/decorators/camaleon_cms/site_decorator.rb +29 -23
  77. data/app/decorators/camaleon_cms/term_taxonomy_decorator.rb +21 -10
  78. data/app/decorators/camaleon_cms/theme_decorator.rb +3 -3
  79. data/app/decorators/camaleon_cms/user_decorator.rb +26 -5
  80. data/app/helpers/camaleon_cms/admin/application_helper.rb +21 -24
  81. data/app/helpers/camaleon_cms/admin/breadcrumb_helper.rb +1 -1
  82. data/app/helpers/camaleon_cms/admin/custom_fields_helper.rb +24 -23
  83. data/app/helpers/camaleon_cms/admin/menus_helper.rb +249 -139
  84. data/app/helpers/camaleon_cms/admin/post_type_helper.rb +51 -31
  85. data/app/helpers/camaleon_cms/camaleon_helper.rb +31 -39
  86. data/app/helpers/camaleon_cms/captcha_helper.rb +73 -53
  87. data/app/helpers/camaleon_cms/comment_helper.rb +87 -41
  88. data/app/helpers/camaleon_cms/content_helper.rb +13 -6
  89. data/app/helpers/camaleon_cms/email_helper.rb +7 -3
  90. data/app/helpers/camaleon_cms/frontend/content_select_helper.rb +34 -20
  91. data/app/helpers/camaleon_cms/frontend/nav_menu_helper.rb +144 -67
  92. data/app/helpers/camaleon_cms/frontend/seo_helper.rb +39 -28
  93. data/app/helpers/camaleon_cms/frontend/site_helper.rb +32 -12
  94. data/app/helpers/camaleon_cms/hooks_helper.rb +14 -4
  95. data/app/helpers/camaleon_cms/html_helper.rb +73 -38
  96. data/app/helpers/camaleon_cms/plugins_helper.rb +23 -24
  97. data/app/helpers/camaleon_cms/session_helper.rb +195 -39
  98. data/app/helpers/camaleon_cms/short_code_helper.rb +181 -85
  99. data/app/helpers/camaleon_cms/site_helper.rb +43 -9
  100. data/app/helpers/camaleon_cms/theme_helper.rb +35 -19
  101. data/app/helpers/camaleon_cms/uploader_helper.rb +19 -422
  102. data/app/helpers/camaleon_cms/user_roles_helper.rb +5 -4
  103. data/app/mailers/camaleon_cms/html_mailer.rb +4 -4
  104. data/app/models/camaleon_cms/ability.rb +65 -105
  105. data/app/models/camaleon_cms/category.rb +7 -5
  106. data/app/models/camaleon_cms/custom_field.rb +29 -6
  107. data/app/models/camaleon_cms/custom_field_group.rb +75 -21
  108. data/app/models/camaleon_cms/custom_fields_relationship.rb +133 -2
  109. data/app/models/camaleon_cms/media.rb +8 -2
  110. data/app/models/camaleon_cms/meta.rb +2 -2
  111. data/app/models/camaleon_cms/nav_menu.rb +6 -2
  112. data/app/models/camaleon_cms/nav_menu_item.rb +18 -8
  113. data/app/models/camaleon_cms/plugin.rb +4 -3
  114. data/app/models/camaleon_cms/post.rb +113 -27
  115. data/app/models/camaleon_cms/post_comment.rb +10 -6
  116. data/app/models/camaleon_cms/post_default.rb +42 -12
  117. data/app/models/camaleon_cms/post_relationship.rb +6 -4
  118. data/app/models/camaleon_cms/post_tag.rb +4 -3
  119. data/app/models/camaleon_cms/post_type.rb +22 -12
  120. data/app/models/camaleon_cms/site.rb +40 -28
  121. data/app/models/camaleon_cms/term_relationship.rb +10 -7
  122. data/app/models/camaleon_cms/term_taxonomy.rb +51 -5
  123. data/app/models/camaleon_cms/theme.rb +3 -3
  124. data/app/models/camaleon_cms/user.rb +17 -5
  125. data/app/models/camaleon_cms/user_role.rb +77 -4
  126. data/app/models/camaleon_cms/widget/assigned.rb +11 -6
  127. data/app/models/camaleon_cms/widget/main.rb +13 -7
  128. data/app/models/camaleon_cms/widget/sidebar.rb +3 -6
  129. data/app/models/camaleon_record.rb +123 -5
  130. data/app/models/concerns/camaleon_cms/categories_tags_for_posts.rb +20 -38
  131. data/app/models/concerns/camaleon_cms/common_relationships.rb +18 -5
  132. data/app/models/concerns/camaleon_cms/custom_fields_read.rb +115 -58
  133. data/app/models/concerns/camaleon_cms/metas.rb +32 -7
  134. data/app/models/concerns/camaleon_cms/normalize_attrs.rb +2 -8
  135. data/app/models/concerns/camaleon_cms/site_default_settings.rb +120 -16
  136. data/app/models/concerns/camaleon_cms/user_methods.rb +44 -19
  137. data/app/models/current_request.rb +23 -0
  138. data/app/uploaders/camaleon_cms_aws_uploader.rb +39 -11
  139. data/app/uploaders/camaleon_cms_local_uploader.rb +76 -19
  140. data/app/uploaders/camaleon_cms_uploader.rb +23 -10
  141. data/app/validators/camaleon_cms/post_uniq_validator.rb +21 -8
  142. data/app/validators/camaleon_cms/uniq_validator.rb +1 -1
  143. data/app/validators/camaleon_cms/user_url_validator.rb +215 -36
  144. data/app/views/camaleon_cms/admin/appearances/nav_menus/_left_menu_items.html.erb +2 -2
  145. data/app/views/camaleon_cms/admin/appearances/widgets/main/form.html.erb +1 -1
  146. data/app/views/camaleon_cms/admin/categories/index.html.erb +3 -3
  147. data/app/views/camaleon_cms/admin/comments/index.html.erb +2 -2
  148. data/app/views/camaleon_cms/admin/comments/list.html.erb +1 -1
  149. data/app/views/camaleon_cms/admin/installers/form.html.erb +5 -0
  150. data/app/views/camaleon_cms/admin/installers/welcome.html.erb +30 -6
  151. data/app/views/camaleon_cms/admin/plugins/_plugins_list.html.erb +2 -2
  152. data/app/views/camaleon_cms/admin/post_tags/index.html.erb +3 -3
  153. data/app/views/camaleon_cms/admin/posts/_sidebar.html.erb +2 -2
  154. data/app/views/camaleon_cms/admin/posts/form.html.erb +3 -2
  155. data/app/views/camaleon_cms/admin/posts/index.html.erb +6 -6
  156. data/app/views/camaleon_cms/admin/search.html.erb +1 -1
  157. data/app/views/camaleon_cms/admin/sessions/back_to_parent.html.erb +39 -0
  158. data/app/views/camaleon_cms/admin/sessions/logout_confirm.html.erb +27 -0
  159. data/app/views/camaleon_cms/admin/settings/_email_settings.html.erb +4 -1
  160. data/app/views/camaleon_cms/admin/settings/custom_fields/_get_items.html.erb +1 -1
  161. data/app/views/camaleon_cms/admin/settings/custom_fields/_render.html.erb +42 -6
  162. data/app/views/camaleon_cms/admin/settings/custom_fields/_render_category_simple.html.erb +1 -1
  163. data/app/views/camaleon_cms/admin/settings/custom_fields/fields/_select_eval.html.erb +1 -1
  164. data/app/views/camaleon_cms/admin/settings/custom_fields/form.html.erb +5 -4
  165. data/app/views/camaleon_cms/admin/settings/custom_fields/index.html.erb +1 -1
  166. data/app/views/camaleon_cms/admin/settings/post_types/index.html.erb +1 -1
  167. data/app/views/camaleon_cms/admin/settings/shortcodes.html.erb +4 -4
  168. data/app/views/camaleon_cms/admin/settings/site.html.erb +1 -1
  169. data/app/views/camaleon_cms/admin/settings/sites/form.html.erb +1 -1
  170. data/app/views/camaleon_cms/admin/settings/sites/index.html.erb +1 -1
  171. data/app/views/camaleon_cms/admin/user_roles/form.html.erb +102 -7
  172. data/app/views/camaleon_cms/admin/user_roles/index.html.erb +1 -1
  173. data/app/views/camaleon_cms/admin/users/form.html.erb +8 -4
  174. data/app/views/camaleon_cms/admin/users/index.html.erb +2 -2
  175. data/app/views/camaleon_cms/default_theme/partials/_render_custom_field.html.erb +8 -2
  176. data/app/views/camaleon_cms/default_theme/sitemap.html.erb +1 -1
  177. data/app/views/camaleon_cms/default_theme/sitemap.xml.builder +1 -1
  178. data/app/views/layouts/camaleon_cms/admin/_flash_messages.html.erb +2 -2
  179. data/app/views/layouts/camaleon_cms/admin/_header.html.erb +1 -1
  180. data/config/initializers/action_view.rb +42 -5
  181. data/config/initializers/active_record_extension.rb +13 -27
  182. data/config/initializers/assets.rb +52 -23
  183. data/config/initializers/custom_initializers.rb +3 -3
  184. data/config/locales/camaleon_cms/admin/ar.yml +7 -2
  185. data/config/locales/camaleon_cms/admin/de.yml +7 -2
  186. data/config/locales/camaleon_cms/admin/en.yml +39 -2
  187. data/config/locales/camaleon_cms/admin/es.yml +7 -2
  188. data/config/locales/camaleon_cms/admin/fr.yml +7 -2
  189. data/config/locales/camaleon_cms/admin/it.yml +7 -2
  190. data/config/locales/camaleon_cms/admin/nl.yml +8 -2
  191. data/config/locales/camaleon_cms/admin/pt-BR.yml +7 -2
  192. data/config/locales/camaleon_cms/admin/pt.yml +7 -2
  193. data/config/locales/camaleon_cms/admin/ru.yml +7 -2
  194. data/config/locales/camaleon_cms/admin/uk.yml +7 -2
  195. data/config/locales/camaleon_cms/admin/zh-CH.yml +7 -2
  196. data/config/routes/admin.rb +33 -15
  197. data/config/routes/frontend.rb +21 -15
  198. data/db/migrate/20150611161134_post_table_into_utf8.rb +14 -14
  199. data/db/migrate/20150926095310_rename_column_posts.rb +3 -3
  200. data/db/migrate/20151212095328_add_confirm_token_to_users.rb +3 -3
  201. data/db/migrate/20160504155652_add_feature_to_posts.rb +1 -1
  202. data/db/migrate/20160504155653_move_first_name_of_users.rb +2 -2
  203. data/db/migrate/20160609121449_add_group_to_custom_field_values.rb +1 -1
  204. data/db/migrate/20161215202255_drop_user_relationship_table.rb +1 -1
  205. data/db/migrate/20180124132318_create_media.rb +1 -1
  206. data/db/migrate/20180704211100_adjust_field_length.rb +1 -1
  207. data/lib/camaleon_cms/assets_precompile.rb +86 -0
  208. data/lib/camaleon_cms/captcha_image_generation.rb +65 -0
  209. data/lib/camaleon_cms/content_security.rb +158 -0
  210. data/lib/camaleon_cms/engine.rb +47 -9
  211. data/lib/camaleon_cms/media_security_headers.rb +27 -0
  212. data/lib/camaleon_cms/setup_token.rb +69 -0
  213. data/lib/camaleon_cms/svg_content_checker.rb +123 -0
  214. data/lib/camaleon_cms/task_reporter.rb +14 -0
  215. data/lib/camaleon_cms/unsafe_markup.rb +207 -0
  216. data/lib/camaleon_cms/uploader_content_security.rb +248 -0
  217. data/lib/camaleon_cms/uploader_image_processing.rb +166 -0
  218. data/lib/camaleon_cms/uploader_path_security.rb +146 -0
  219. data/lib/camaleon_cms/uploader_pipeline.rb +350 -0
  220. data/lib/camaleon_cms/uploader_support.rb +86 -0
  221. data/lib/camaleon_cms/version.rb +1 -1
  222. data/lib/camaleon_cms.rb +11 -0
  223. data/lib/ext/hash.rb +28 -2
  224. data/lib/ext/string.rb +13 -8
  225. data/lib/ext/translator.rb +10 -2
  226. data/lib/generators/camaleon_cms/gem_plugin_template/app/controllers/plugins/my_plugin/admin_controller.rb +5 -1
  227. data/lib/generators/camaleon_cms/install_generator.rb +7 -4
  228. data/lib/generators/camaleon_cms/install_template/plugin_routes.rb +5 -12
  229. data/lib/generators/camaleon_cms/theme_generator.rb +5 -10
  230. data/lib/generators/camaleon_cms/theme_template/views/layouts/index.html.erb +3 -1
  231. data/lib/plugin_routes.rb +412 -368
  232. data/lib/tasks/camaleon_cms/camaleon_tasks.rake +2 -1
  233. data/lib/tasks/cross_site_field_groups.rake +74 -0
  234. data/lib/tasks/custom_fields_roles.rake +58 -0
  235. data/lib/tasks/orphaned_comments.rake +42 -0
  236. data/lib/tasks/private_upload_acls.rake +31 -0
  237. data/lib/tasks/site_custom_field_groups.rake +36 -0
  238. data/lib/tasks/unsafe_stored_content.rake +42 -0
  239. data/lib/tasks/unsafe_stored_uploads.rake +70 -0
  240. data/lib/tasks/user_field_groups.rake +27 -0
  241. metadata +185 -7
@@ -1,21 +1,22 @@
1
1
  # Camaleon CMS is a content management system
2
2
  # Copyright (C) 2015 by Owen Peredo Diaz
3
3
  # Email: owenperedo@gmail.com
4
- # This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
5
- # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
4
+ # This program is free software: you can redistribute it and/or modify it under the terms of the
5
+ # GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License,
6
+ # or (at your option) any later version.
7
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
8
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
6
9
  # See the GNU Affero General Public License (GPLv3) for more details.
7
10
  module CamaleonCms
8
11
  module Frontend
9
12
  module ContentSelectHelper
10
- # select single post of post type
13
+ # select a single post of post type
11
14
  # the_post_type('post') do
12
15
  # the_post('first-blog-post')
13
16
  # end
14
17
  def the_post(slug)
15
- post = @object.the_post(slug)
16
- process_in_block(post) do
17
- yield(post) if block_given?
18
- end
18
+ post = camaleon_frontend_object.the_post(slug)
19
+ process_in_block(post) { yield(post) if block_given? }
19
20
  post
20
21
  end
21
22
 
@@ -28,7 +29,7 @@ module CamaleonCms
28
29
  # the_posts(limit: 10)
29
30
  # end
30
31
  def the_posts(options = {})
31
- @object.posts.visible_frontend.limit(options[:limit]).decorate
32
+ camaleon_frontend_object.posts.visible_frontend.limit(options[:limit]).decorate
32
33
  end
33
34
 
34
35
  # select post type by just pass slug to parameter
@@ -52,7 +53,7 @@ module CamaleonCms
52
53
  # the_comments
53
54
  # end
54
55
  def the_comments(options = {})
55
- @object.comments.limit(options[:limit]).decorate if @object.present?
56
+ camaleon_frontend_object.comments.limit(options[:limit]).decorate if camaleon_frontend_object.present?
56
57
  end
57
58
 
58
59
  # select title of post
@@ -60,7 +61,7 @@ module CamaleonCms
60
61
  # the_title
61
62
  # end
62
63
  def the_title
63
- @object.the_title if @object.present?
64
+ camaleon_frontend_object&.the_title
64
65
  end
65
66
 
66
67
  # select content of post
@@ -68,7 +69,12 @@ module CamaleonCms
68
69
  # the_content
69
70
  # end
70
71
  def the_content
71
- @object.the_content.html_safe if @object.present?
72
+ # Security (scan-and-reject policy): no render-time transform. Stored content is gated at
73
+ # save (Post#reject_untrusted_dangerous_content), always equals what its author wrote, and
74
+ # renders verbatim — the same contract as the templates' `raw post.the_content`. The
75
+ # sanitize this once applied used the narrow default allowlist, so it also broke trusted
76
+ # authors' tables and embeds on this DSL path only.
77
+ camaleon_frontend_object.the_content.to_s.html_safe if camaleon_frontend_object.present? # rubocop:disable Rails/OutputSafety
72
78
  end
73
79
 
74
80
  # select url of post
@@ -76,7 +82,7 @@ module CamaleonCms
76
82
  # the_url
77
83
  # end
78
84
  def the_url
79
- @object.the_url if @object.present?
85
+ camaleon_frontend_object&.the_url
80
86
  end
81
87
 
82
88
  # select thumbnail of post
@@ -84,15 +90,15 @@ module CamaleonCms
84
90
  # the_thumbnail
85
91
  # end
86
92
  def the_thumbnail
87
- @object.the_thumb_url if @object.present?
93
+ camaleon_frontend_object&.the_thumb_url
88
94
  end
89
95
 
90
- # select slug of post, post type ... (@object)
96
+ # select slug of post, post type ...
91
97
  # the_post('blog') do
92
98
  # the_slug
93
99
  # end
94
100
  def the_slug
95
- @object.the_slug if @object.present?
101
+ camaleon_frontend_object&.the_slug
96
102
  end
97
103
 
98
104
  # select excerpt of post
@@ -100,7 +106,7 @@ module CamaleonCms
100
106
  # the_excerpt
101
107
  # end
102
108
  def the_excerpt(chars = 200)
103
- @object.the_excerpt(chars) if @object.present?
109
+ camaleon_frontend_object&.the_excerpt(chars)
104
110
  end
105
111
 
106
112
  # select custome field from object
@@ -108,7 +114,7 @@ module CamaleonCms
108
114
  # the_field('extra-content')
109
115
  # end
110
116
  def the_field(slug)
111
- @object.the_field(slug) if @object.present?
117
+ camaleon_frontend_object&.the_field(slug)
112
118
  end
113
119
 
114
120
  # loop through each post of post type
@@ -152,10 +158,18 @@ module CamaleonCms
152
158
  # the_field('extra-content')
153
159
  # end
154
160
  def process_in_block(object)
155
- temp_object = @object
156
- @object = object
161
+ temp_object = CurrentRequest.frontend_object
162
+ CurrentRequest.frontend_object = object
157
163
  yield
158
- @object = temp_object
164
+ ensure
165
+ CurrentRequest.frontend_object = temp_object
166
+ end
167
+
168
+ private
169
+
170
+ def camaleon_frontend_object
171
+ # Fall back to a plugin-set @object ivar; core writes CurrentRequest.frontend_object. Regression M20.
172
+ CurrentRequest.frontend_object || (instance_variable_get(:@object) if instance_variable_defined?(:@object))
159
173
  end
160
174
  end
161
175
  end
@@ -2,7 +2,7 @@ module CamaleonCms
2
2
  module Frontend
3
3
  module NavMenuHelper
4
4
  # draw nav menu as html list
5
- # key: slug for nav menu
5
+ # key: slug for a nav menu
6
6
  # to register this, go to admin -> appearance -> menus
7
7
  # (DEPRECATED)
8
8
  def get_nav_menu(key = 'main_menu', class_name = 'navigation')
@@ -23,19 +23,28 @@ module CamaleonCms
23
23
  item_class_parent: 'dropdown', # class for all menu items that contain sub items
24
24
  sub_container: 'ul', # type of container for sub items
25
25
  sub_class: 'dropdown-menu', # class for sub container
26
- callback_item: ->(args) {}, # rubocop:disable Lint/ShadowingOuterLocalVariable
27
- # callback executed for each item (args = { menu_item, link, level, settings, has_children, link_attrs = "", index}).
26
+ callback_item: ->(args) {},
27
+ # callback executed for each item:
28
+ # (args = { menu_item, link, level, settings, has_children, link_attrs = "", index}).
28
29
  # menu_item: (Object) Menu object
29
30
  # link: (Hash) link data: {link: '', name: ''}
30
31
  # level: (Integer) current level
31
32
  # has_children: (boolean) if this item contain sub menus
32
33
  # settings: (Hash) menu settings
33
34
  # index: (Integer) Index Position of this menu
34
- # link_attrs: (String) Here you can add your custom attrs for current link, sample: id='my_id' data-title='#{args[:link][:name]}'
35
+ # link_attrs: (String) Here you can add your custom attrs for current link,
36
+ # sample: id='my_id' data-title='#{args[:link][:name]}'
35
37
  # item_container_attrs: (String) Here you can add your custom attrs for link container.
36
- # In settings, you can change the values for this item, like after, before, ..:
37
- # sample: lambda{|args| args[:settings][:after] = "<span class='caret'></span>" if args[:has_children]; args[:link_attrs] = "id='#{menu_item.id}'"; }
38
- # sample: lambda{|args| args[:settings][:before] = "<i class='fa fa-home'></i>" if args[:level] == 0 && args[:index] == 0; }
38
+ # In settings, you can change the values for this item, like after, before,...:
39
+ # sample:
40
+ # lambda do |args|
41
+ # args[:settings][:after] = "<span class='caret'></span>" if args[:has_children]
42
+ # args[:link_attrs] = "id='#{menu_item.id}'"
43
+ # end
44
+ # sample:
45
+ # lambda do |args|
46
+ # args[:settings][:before] = "<i class='fa fa-home'></i>" if args[:level] == 0 && args[:index] == 0
47
+ # end
39
48
  before: '', # content before link text
40
49
  after: '', # content after link text
41
50
  link_current: 'current-link', # class for current menu link
@@ -49,7 +58,7 @@ module CamaleonCms
49
58
  }
50
59
 
51
60
  args = args_def.merge!(args)
52
- nav_menu = current_site.nav_menus.find_by_slug(args[:menu_slug])
61
+ nav_menu = current_site.nav_menus.find_by_slug(args[:menu_slug]) # rubocop:disable Rails/DynamicFindBy
53
62
  nav_menu ||= current_site.nav_menus.first
54
63
  html = "<#{args[:container]} class='#{args[:container_class]}' "\
55
64
  "id='#{args[:container_id]}'>#{args[:container_prepend]}{__}#{args[:container_append]}</#{args[:container]}>"
@@ -61,19 +70,22 @@ module CamaleonCms
61
70
  end
62
71
 
63
72
  # draw menu items
73
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
64
74
  def cama_menu_draw_items(args, nav_menu, level = 0)
65
- html = ''
75
+ items_html = []
66
76
  parent_current = false
67
77
  index = 0
78
+ # rubocop:disable Rails/FindEach -- Rendering must preserve the relation's configured term_order.
68
79
  nav_menu.eager_load(:metas).each do |nav_menu_item|
69
80
  _args = args.dup
70
81
  data_nav_item = cama_parse_menu_item(nav_menu_item)
71
82
  next if data_nav_item == false
72
83
 
73
- _is_current = data_nav_item[:current] || site_current_path == data_nav_item[:link] ||
84
+ _is_current = data_nav_item[:current] ||
85
+ site_current_path == data_nav_item[:link] ||
74
86
  site_current_path == data_nav_item[:link].sub('.html', '')
75
- has_children = nav_menu_item.have_children? && (args[:levels] == -1 ||
76
- (args[:levels] != -1 && level <= args[:levels]))
87
+ has_children = nav_menu_item.have_children? &&
88
+ (args[:levels] == -1 || (args[:levels] != -1 && level <= args[:levels]))
77
89
  r = {
78
90
  menu_item: nav_menu_item.decorate,
79
91
  link: data_nav_item,
@@ -88,44 +100,77 @@ module CamaleonCms
88
100
  _args = r[:settings]
89
101
 
90
102
  if has_children
91
- html_children, current_children = cama_menu_draw_items(args, nav_menu_item.children.reorder(:term_order),
92
- level + 1)
103
+ html_children, current_children = cama_menu_draw_items(
104
+ args, nav_menu_item.children.reorder(:term_order), level + 1
105
+ )
93
106
  else
94
107
  html_children = ''
95
108
  current_children = false
96
109
  end
97
- parent_current = true if _is_current || current_children
110
+ parent_current ||= _is_current || current_children
111
+
112
+ item_classes = [_args[:item_class]]
113
+ item_classes << _args[:item_class_parent] if has_children
114
+ item_classes << _args[:item_current] if _is_current
115
+ item_classes << 'current-menu-ancestor' if current_children
116
+ item_class_str = item_classes.reject(&:blank?).join(' ')
117
+
118
+ item_attrs = []
119
+ item_attrs << r[:item_container_attrs] if r[:item_container_attrs].present?
120
+ item_attrs << "class='#{ERB::Util.html_escape(item_class_str)}'" if item_class_str.present?
121
+ item_attrs_str = item_attrs.reject(&:blank?).join(' ')
122
+
123
+ item_open = "<#{_args[:item_container]}"
124
+ item_open << " #{item_attrs_str}" if item_attrs_str.present?
125
+ item_open << '>'
126
+
127
+ link_attr_parts = []
128
+ link_attr_parts << r[:link_attrs] if r[:link_attrs].present?
129
+ if nav_menu_item.target.present?
130
+ link_attr_parts << "target='#{ERB::Util.html_escape(nav_menu_item.target.to_s)}'"
131
+ end
132
+ link_attr_parts << "href='#{ERB::Util.html_escape(data_nav_item[:link].to_s)}'"
133
+ link_classes = []
134
+ link_classes << args[:link_current] if _is_current
135
+ link_classes << _args[:link_class_parent] if has_children
136
+ link_classes << _args[:link_class]
137
+ link_class_str = link_classes.reject(&:blank?).join(' ')
138
+ link_attr_parts << "class='#{ERB::Util.html_escape(link_class_str)}'" if link_class_str.present?
139
+ link_attr_parts << "data-toggle='dropdown'" if has_children
140
+ link_attrs_str = link_attr_parts.reject(&:blank?).join(' ')
141
+
142
+ # Menu labels intentionally support trusted HTML snippets (icons, buttons, embeds) configured by site admins.
143
+ link_inner = [_args[:before], data_nav_item[:name].to_s, _args[:after]].reject(&:blank?).join('')
144
+ link_tag = "<a #{link_attrs_str}>#{link_inner}</a>"
145
+
146
+ item_inner = [
147
+ _args[:link_before],
148
+ link_tag,
149
+ _args[:link_after],
150
+ html_children
151
+ ].reject(&:blank?).join('')
152
+ item_html = "#{item_open}#{item_inner}</#{_args[:item_container]}>"
153
+ # rubocop:disable Rails/OutputSafety -- User-controlled fields are escaped before this trusted menu markup is marked safe.
154
+ items_html << item_html.html_safe
155
+ # rubocop:enable Rails/OutputSafety
98
156
 
99
- html += "<#{_args[:item_container]} #{r[:item_container_attrs]} class='#{_args[:item_class]} #{if has_children
100
- _args[:item_class_parent]
101
- end} #{if _is_current
102
- _args[:item_current].to_s
103
- end} #{if current_children
104
- 'current-menu-ancestor'
105
- end}'>#{_args[:link_before]}
106
- <a #{r[:link_attrs]} #{if nav_menu_item.target.present?
107
- " target='#{nav_menu_item.target}'"
108
- end} href='#{data_nav_item[:link]}' class='#{if _is_current
109
- args[:link_current]
110
- end} #{if has_children
111
- _args[:link_class_parent]
112
- end} #{_args[:link_class]}' #{if has_children
113
- "data-toggle='dropdown'"
114
- end} >#{_args[:before]}#{data_nav_item[:name]}#{_args[:after]}</a> #{_args[:link_after]}
115
- #{html_children}
116
- </#{_args[:item_container]}>"
117
157
  index += 1
118
158
  end
159
+ # rubocop:enable Rails/FindEach
119
160
 
120
161
  if level == 0
121
- html
162
+ safe_join(items_html)
122
163
  else
123
- html = "<#{args[:sub_container]} class='#{args[:sub_class]} #{if parent_current
124
- "parent-#{args[:item_current]}"
125
- end} level-#{level}'>#{html}</#{args[:sub_container]}>"
126
- [html, parent_current]
164
+ sub_classes = [args[:sub_class]]
165
+ sub_classes << "parent-#{args[:item_current]}" if parent_current
166
+ sub_classes << "level-#{level}"
167
+ sub_container_class = sub_classes.reject(&:blank?).join(' ')
168
+ sub_html = "<#{args[:sub_container]} class='#{sub_container_class}'>" \
169
+ "#{safe_join(items_html)}</#{args[:sub_container]}>"
170
+ [sub_html, parent_current]
127
171
  end
128
172
  end
173
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
129
174
 
130
175
  # filter and parse all menu items visible for current user and adding the flag for current_parent or current_item
131
176
  # max_levels: max levels to iterate
@@ -139,9 +184,8 @@ module CamaleonCms
139
184
  data_nav_item = cama_parse_menu_item(nav_menu_item)
140
185
  next if data_nav_item == false
141
186
 
142
- _is_current = data_nav_item[:current] || site_current_path == data_nav_item[:link] || site_current_path == data_nav_item[:link].sub(
143
- '.html', ''
144
- )
187
+ _is_current = data_nav_item[:current] || site_current_path == data_nav_item[:link] ||
188
+ site_current_path == data_nav_item[:link].sub('.html', '')
145
189
  has_children = nav_menu_item.have_children?
146
190
  has_children = false if max_levels > 0 && max_levels == internal_level
147
191
  data_nav_item[:label] = data_nav_item[:name]
@@ -157,14 +201,15 @@ module CamaleonCms
157
201
  }.merge!(data_nav_item.except(:current, :name, :link))
158
202
 
159
203
  if has_children
160
- r[:children], _is_current_parent, r[:levels] = cama_menu_parse_items(nav_menu_item.children, max_levels,
161
- internal_level + 1)
204
+ r[:children], _is_current_parent, r[:levels] =
205
+ cama_menu_parse_items(nav_menu_item.children, max_levels, internal_level + 1)
162
206
  if _is_current_parent
163
207
  is_current_parent = true
164
208
  r[:current_parent] = true
165
209
  end
166
210
  r[:levels] = r[:levels] + 1
167
211
  end
212
+
168
213
  is_current_parent = true if r[:current_item]
169
214
  levels << r[:levels]
170
215
  res << r
@@ -181,11 +226,12 @@ module CamaleonCms
181
226
  # draw the breadcrumb as html list
182
227
  def breadcrumb_draw
183
228
  res = []
184
- @_front_breadcrumb.each_with_index do |item, index|
185
- res << if @_front_breadcrumb.size == (index + 1) # last menu
229
+ breadcrumb_items = nav_menu_breadcrumb_items
230
+ breadcrumb_items.each_with_index do |item, index|
231
+ res << if breadcrumb_items.size == (index + 1) # last menu
186
232
  "<li class='active'>#{item[0]}</li>"
187
233
  else
188
- "<li><a href='#{item[1]}'>#{item[0]}</a></li>"
234
+ "<li><a href='#{ERB::Util.html_escape(item[1])}'>#{item[0]}</a></li>"
189
235
  end
190
236
  end
191
237
  res.join('')
@@ -195,11 +241,11 @@ module CamaleonCms
195
241
  # label => label of the link
196
242
  # url: url for the link
197
243
  def breadcrumb_add(label, url = '', prepend = false)
198
- @_front_breadcrumb ||= []
244
+ breadcrumb_items = nav_menu_breadcrumb_items
199
245
  if prepend
200
- @_front_breadcrumb.unshift([label, url])
246
+ breadcrumb_items.unshift([label, url])
201
247
  else
202
- @_front_breadcrumb << [label, url]
248
+ breadcrumb_items << [label, url]
203
249
  end
204
250
  end
205
251
 
@@ -213,34 +259,44 @@ module CamaleonCms
213
259
  if is_from_backend || post.can_visit?
214
260
  result = { link: post.the_url(as_path: true), name: post.the_title, type_menu: type_menu,
215
261
  url_edit: post.the_edit_url }
216
- result[:current] = @cama_visited_post.present? && @cama_visited_post.id == post.id unless is_from_backend
262
+ unless is_from_backend
263
+ visited_post = nav_menu_visited_state(:frontend_visited_post)
264
+ result[:current] = visited_post.present? && visited_post.id == post.id
265
+ end
217
266
  end
218
267
  when 'category'
219
268
  category = CamaleonCms::Category.find(nav_menu_item.url).decorate
220
269
  result = { link: category.the_url(as_path: true), name: category.the_title,
221
270
  url_edit: category.the_edit_url }
222
271
  unless is_from_backend
223
- result[:current] =
224
- @cama_visited_category.present? && @cama_visited_category.id == category.id
272
+ visited_category = nav_menu_visited_state(:frontend_visited_category)
273
+ result[:current] = visited_category.present? && visited_category.id == category.id
225
274
  end
226
275
  when 'post_tag'
227
276
  post_tag = CamaleonCms::PostTag.find(nav_menu_item.url).decorate
228
277
  result = { link: post_tag.the_url(as_path: true), name: post_tag.the_title,
229
278
  url_edit: post_tag.the_edit_url }
230
- result[:current] = @cama_visited_tag.present? && @cama_visited_tag.id == post_tag.id unless is_from_backend
279
+ unless is_from_backend
280
+ visited_tag = nav_menu_visited_state(:frontend_visited_tag)
281
+ result[:current] = visited_tag.present? && visited_tag.id == post_tag.id
282
+ end
231
283
  when 'post_type'
232
284
  post_type = CamaleonCms::PostType.find(nav_menu_item.url).decorate
233
285
  result = { link: post_type.the_url(as_path: true), name: post_type.the_title,
234
286
  url_edit: post_type.the_edit_url }
235
287
  unless is_from_backend
236
- result[:current] =
237
- @cama_visited_post_type.present? && @cama_visited_post_type.id == post_type.id
288
+ visited_post_type = nav_menu_visited_state(:frontend_visited_post_type)
289
+ result[:current] = visited_post_type.present? && visited_post_type.id == post_type.id
238
290
  end
239
291
  when 'external'
240
292
  result = { link: nav_menu_item.url.to_s.translate, name: nav_menu_item.name.to_s.translate, current: false }
241
293
  # permit to customize or mark as current menu
242
294
  # _args: (HASH) {menu_item: Model Menu Item, parsed_menu: Parsed Menu }
243
- # Sample parsed_menu: {link: "url of the link", name: "Text of the menu", current: Boolean (true => is current menu, false => not current menu item)}
295
+ # Sample parsed_menu:
296
+ # {
297
+ # link: "url of the link", name: "Text of the menu",
298
+ # current: Boolean (true => is current menu, false => not current menu item)
299
+ # }
244
300
  unless is_from_backend
245
301
  result[:link] = cama_root_path if result[:link] == 'root_url'
246
302
  result[:link] = site_current_path if site_current_path == "#{current_site.the_path}#{result[:link]}"
@@ -251,11 +307,15 @@ module CamaleonCms
251
307
  end
252
308
  else
253
309
  # permit to build custom menu items registered as Custom Menu by hook "nav_menu_custom"
254
- # sample: def my_parse_custom_menu_item_listener(args);
310
+ # sample:
311
+ # def my_parse_custom_menu_item_listener(args)
255
312
  # if args[:menu_item].kind == 'MyModelClass'
256
313
  # my_model = MyModelClass.find(args[:menu_item].url)
257
- # res = {name: my_model.name, url_edit: my_model_edit_url(id: my_model.id), link: my_model_public_url(id: my_model.id)}
258
- # res[:current] = site_current_path == my_model_public_url(id: my_model.id) unless args[:is_from_backend]
314
+ # res = {
315
+ # name: my_model.name, url_edit: my_model_edit_url(id: my_model.id),
316
+ # link: my_model_url(id: my_model.id)
317
+ # }
318
+ # res[:current] = site_current_path == my_model_url(id: my_model.id) unless args[:is_from_backend]
259
319
  # args[:parsed_menu] = res
260
320
  # end
261
321
  # end
@@ -264,17 +324,34 @@ module CamaleonCms
264
324
  result = hook_args[:parsed_menu]
265
325
  end
266
326
  rescue StandardError => e
267
- Rails.logger.error "Camaleon CMS - Menu Item Not Found => Skipped menu for: #{e.message} (#{nav_menu_item.inspect})".cama_log_style(:red)
327
+ Rails.logger.error(
328
+ "Camaleon CMS - Menu Item Not Found => Skipped menu for: #{e.message} (#{nav_menu_item.inspect})"
329
+ .cama_log_style(:red)
330
+ )
268
331
  end
269
332
 
270
- # permit to customize data, like: current, title, ... of parsed menu item or skip menu item by assigning false into :parsed_menu
271
- if is_from_backend
272
- result
273
- else
274
- _args = { menu_item: nav_menu_item, parsed_menu: result }
275
- hooks_run('on_render_front_menu_item', _args)
276
- _args[:parsed_menu]
333
+ # permit customizing data, like: current, title, ... of parsed menu item or
334
+ # skip menu item by assigning false into :parsed_menu
335
+ return result if is_from_backend
336
+
337
+ _args = { menu_item: nav_menu_item, parsed_menu: result }
338
+ hooks_run('on_render_front_menu_item', _args)
339
+ _args[:parsed_menu]
340
+ end
341
+
342
+ private
343
+
344
+ def nav_menu_breadcrumb_items
345
+ CurrentRequest.theme_helper_state ||= {}
346
+ CurrentRequest.theme_helper_state[:front_breadcrumb] ||= []
347
+ end
348
+
349
+ def nav_menu_visited_state(current_request_attr)
350
+ if respond_to?(:camaleon_frontend_visited_state, true)
351
+ return camaleon_frontend_visited_state(current_request_attr)
277
352
  end
353
+
354
+ CurrentRequest.public_send(current_request_attr)
278
355
  end
279
356
  end
280
357
  end
@@ -5,42 +5,49 @@ module CamaleonCms
5
5
  # you can pass custom data to overwrite default data generated by the system
6
6
  # return hash of seo attributes used by the_head(...)
7
7
  def cama_the_seo(data = {})
8
+ visited_post = camaleon_frontend_visited_state(:frontend_visited_post)
9
+ visited_post_type = camaleon_frontend_visited_state(:frontend_visited_post_type)
10
+ visited_tag = camaleon_frontend_visited_state(:frontend_visited_tag)
11
+ visited_category = camaleon_frontend_visited_state(:frontend_visited_category)
12
+ visited_user = CurrentRequest.frontend_user
13
+ visited_user ||= instance_variable_get(:@user) if instance_variable_defined?(:@user) # legacy @user (M20)
14
+
8
15
  data2 = if is_home?
9
16
  {}
10
17
  elsif is_page?
11
- { image: @cama_visited_post.the_thumb_url,
12
- title: "#{current_site.the_title} | #{@cama_visited_post.the_title}",
13
- description: @cama_visited_post.the_excerpt,
14
- keywords: @cama_visited_post.the_keywords,
15
- object: @cama_visited_post }
18
+ { image: visited_post.the_thumb_url,
19
+ title: "#{current_site.the_title} | #{visited_post.the_title}",
20
+ description: visited_post.the_excerpt,
21
+ keywords: visited_post.the_keywords,
22
+ object: visited_post }
16
23
  elsif is_ajax?
17
24
  {}
18
25
  elsif is_search?
19
26
  { title: "#{current_site.the_title} | #{ct('search_title', default: 'Search')}" }
20
27
  elsif is_post_type?
21
- { image: @cama_visited_post_type.the_thumb_url,
22
- title: "#{current_site.the_title} | #{@cama_visited_post_type.the_title}",
23
- description: @cama_visited_post_type.the_excerpt,
24
- keywords: @cama_visited_post_type.the_keywords,
25
- object: @cama_visited_post_type }
28
+ { image: visited_post_type.the_thumb_url,
29
+ title: "#{current_site.the_title} | #{visited_post_type.the_title}",
30
+ description: visited_post_type.the_excerpt,
31
+ keywords: visited_post_type.the_keywords,
32
+ object: visited_post_type }
26
33
  elsif is_post_tag?
27
- { title: "#{current_site.the_title} | #{@cama_visited_tag.the_title}",
28
- description: @cama_visited_tag.the_excerpt,
29
- keywords: @cama_visited_tag.the_keywords,
30
- object: @cama_visited_tag }
34
+ { title: "#{current_site.the_title} | #{visited_tag.the_title}",
35
+ description: visited_tag.the_excerpt,
36
+ keywords: visited_tag.the_keywords,
37
+ object: visited_tag }
31
38
  elsif is_category?
32
- { image: @cama_visited_category.the_thumb_url,
33
- title: "#{current_site.the_title} | #{@cama_visited_category.the_title}",
34
- description: @cama_visited_category.the_excerpt,
35
- keywords: @cama_visited_category.the_keywords,
36
- object: @cama_visited_category }
39
+ { image: visited_category.the_thumb_url,
40
+ title: "#{current_site.the_title} | #{visited_category.the_title}",
41
+ description: visited_category.the_excerpt,
42
+ keywords: visited_category.the_keywords,
43
+ object: visited_category }
37
44
  elsif is_profile?
38
- { image: @user.the_avatar, title: "#{current_site.the_title} | #{@user.the_name}",
39
- description: @user.the_slogan, object: @user }
45
+ { image: visited_user.the_avatar, title: "#{current_site.the_title} | #{visited_user.the_name}",
46
+ description: visited_user.the_slogan, object: visited_user }
40
47
  else
41
48
  {}
42
49
  end
43
- cama_build_seo(data2.merge!(@_cama_seo_setting_values || {}).merge(data))
50
+ cama_build_seo(data2.merge!(camaleon_frontend_seo_settings || {}).merge(data))
44
51
  end
45
52
 
46
53
  # permit to define seo attributes by code without hooks
@@ -51,19 +58,23 @@ module CamaleonCms
51
58
  # )
52
59
  # This values will be shown within the_head(...)
53
60
  def cama_seo_settings(options)
54
- @_cama_seo_setting_values ||= {}
55
- @_cama_seo_setting_values = @_cama_seo_setting_values.merge(options)
61
+ CurrentRequest.frontend_seo_settings ||= {}
62
+ CurrentRequest.frontend_seo_settings = CurrentRequest.frontend_seo_settings.merge(options)
56
63
  end
57
64
 
58
65
  private
59
66
 
67
+ def camaleon_frontend_seo_settings
68
+ CurrentRequest.frontend_seo_settings
69
+ end
70
+
60
71
  # create seo attributes with options + default attributes
61
72
  def cama_build_seo(options = {})
62
- options[:image] = current_site.get_option('screenshot', current_site.the_logo) unless options[:image].present?
63
- options[:title] = current_site.the_title unless options[:title].present?
64
- options[:description] = current_site.the_option('seo_description') unless options[:description].present?
73
+ options[:image] = current_site.get_option('screenshot', current_site.the_logo) if options[:image].blank?
74
+ options[:title] = current_site.the_title if options[:title].blank?
75
+ options[:description] = current_site.the_option('seo_description') if options[:description].blank?
65
76
  options[:url] = request.original_url
66
- options[:keywords] = current_site.the_option('keywords') unless options[:keywords].present?
77
+ options[:keywords] = current_site.the_option('keywords') if options[:keywords].blank?
67
78
 
68
79
  s = {
69
80
  keywords: options[:keywords],