wagtailsettings_models.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. """
  2. Custom wagtail settings used by CodeRed CMS.
  3. Settings are user-configurable on a per-site basis (multisite).
  4. Global project or developer settings should be defined in coderedcms.settings.py .
  5. """
  6. import json
  7. from django.db import models
  8. from django.utils.translation import gettext_lazy as _
  9. from wagtail.admin.edit_handlers import FieldPanel, HelpPanel, MultiFieldPanel
  10. from wagtail.images.edit_handlers import ImageChooserPanel
  11. from wagtail.contrib.settings.models import BaseSetting, register_setting
  12. from wagtail.images import get_image_model_string
  13. from coderedcms.fields import MonospaceField
  14. from coderedcms.settings import cr_settings
  15. @register_setting(icon='fa-facebook-official')
  16. class SocialMediaSettings(BaseSetting):
  17. """
  18. Social media accounts.
  19. """
  20. class Meta:
  21. verbose_name = _('Social Media')
  22. facebook = models.URLField(
  23. blank=True,
  24. verbose_name=_('Facebook'),
  25. help_text=_('Your Facebook page URL'),
  26. )
  27. twitter = models.URLField(
  28. blank=True,
  29. verbose_name=_('Twitter'),
  30. help_text=_('Your Twitter page URL'),
  31. )
  32. instagram = models.CharField(
  33. max_length=255,
  34. blank=True,
  35. verbose_name=_('Instagram'),
  36. help_text=_('Your Instagram username, without the @'),
  37. )
  38. youtube = models.URLField(
  39. blank=True,
  40. verbose_name=_('YouTube'),
  41. help_text=_('Your YouTube channel or user account URL'),
  42. )
  43. linkedin = models.URLField(
  44. blank=True,
  45. verbose_name=_('LinkedIn'),
  46. help_text=_('Your LinkedIn page URL'),
  47. )
  48. googleplus = models.URLField(
  49. blank=True,
  50. verbose_name=_('Google'),
  51. help_text=_('Your Google+ page or Google business listing URL'),
  52. )
  53. @property
  54. def twitter_handle(self):
  55. """
  56. Gets the handle of the twitter account from a URL.
  57. """
  58. return self.twitter.strip().strip('/').split('/')[-1]
  59. @property
  60. def social_json(self):
  61. """
  62. Returns non-blank social accounts as a JSON list.
  63. """
  64. socialist = [
  65. self.facebook,
  66. self.twitter,
  67. self.instagram,
  68. self.youtube,
  69. self.linkedin,
  70. self.googleplus,
  71. ]
  72. socialist = list(filter(None, socialist))
  73. return json.dumps(socialist)
  74. panels = [
  75. MultiFieldPanel(
  76. [
  77. FieldPanel('facebook'),
  78. FieldPanel('twitter'),
  79. FieldPanel('instagram'),
  80. FieldPanel('youtube'),
  81. FieldPanel('linkedin'),
  82. FieldPanel('googleplus'),
  83. ],
  84. _('Social Media Accounts'),
  85. )
  86. ]
  87. @register_setting(icon='fa-desktop')
  88. class LayoutSettings(BaseSetting):
  89. """
  90. Branding, navbar, and theme settings.
  91. """
  92. class Meta:
  93. verbose_name = _('Layout')
  94. logo = models.ForeignKey(
  95. get_image_model_string(),
  96. null=True,
  97. blank=True,
  98. on_delete=models.SET_NULL,
  99. related_name='+',
  100. verbose_name=_('Logo'),
  101. help_text=_('Brand logo used in the navbar and throughout the site')
  102. )
  103. favicon = models.ForeignKey(
  104. get_image_model_string(),
  105. null=True,
  106. blank=True,
  107. on_delete=models.SET_NULL,
  108. related_name='favicon',
  109. verbose_name=_('Favicon'),
  110. )
  111. navbar_color_scheme = models.CharField(
  112. blank=True,
  113. max_length=50,
  114. choices=cr_settings['FRONTEND_NAVBAR_COLOR_SCHEME_CHOICES'],
  115. default=cr_settings['FRONTEND_NAVBAR_COLOR_SCHEME_DEFAULT'],
  116. verbose_name=_('Navbar color scheme'),
  117. help_text=_('Optimizes text and other navbar elements for use with light or dark backgrounds.'), # noqa
  118. )
  119. navbar_class = models.CharField(
  120. blank=True,
  121. max_length=255,
  122. default=cr_settings['FRONTEND_NAVBAR_CLASS_DEFAULT'],
  123. verbose_name=_('Navbar CSS class'),
  124. help_text=_('Custom classes applied to navbar e.g. "bg-light", "bg-dark", "bg-primary".'),
  125. )
  126. navbar_fixed = models.BooleanField(
  127. default=False,
  128. verbose_name=_('Fixed navbar'),
  129. help_text=_('Fixed navbar will remain at the top of the page when scrolling.'),
  130. )
  131. navbar_wrapper_fluid = models.BooleanField(
  132. default=True,
  133. verbose_name=_('Full width navbar'),
  134. help_text=_('The navbar will fill edge to edge.'),
  135. )
  136. navbar_content_fluid = models.BooleanField(
  137. default=False,
  138. verbose_name=_('Full width navbar contents'),
  139. help_text=_('Content within the navbar will fill edge to edge.'),
  140. )
  141. navbar_collapse_mode = models.CharField(
  142. blank=True,
  143. max_length=50,
  144. choices=cr_settings['FRONTEND_NAVBAR_COLLAPSE_MODE_CHOICES'],
  145. default=cr_settings['FRONTEND_NAVBAR_COLLAPSE_MODE_DEFAULT'],
  146. verbose_name=_('Collapse navbar menu'),
  147. help_text=_('Control on what screen sizes to show and collapse the navbar menu links.'),
  148. )
  149. navbar_format = models.CharField(
  150. blank=True,
  151. max_length=50,
  152. choices=cr_settings['FRONTEND_NAVBAR_FORMAT_CHOICES'],
  153. default=cr_settings['FRONTEND_NAVBAR_FORMAT_DEFAULT'],
  154. verbose_name=_('Navbar format'),
  155. )
  156. navbar_search = models.BooleanField(
  157. default=True,
  158. verbose_name=_('Search box'),
  159. help_text=_('Show search box in navbar')
  160. )
  161. frontend_theme = models.CharField(
  162. blank=True,
  163. max_length=50,
  164. choices=cr_settings['FRONTEND_THEME_CHOICES'],
  165. default=cr_settings['FRONTEND_THEME_DEFAULT'],
  166. verbose_name=_('Theme variant'),
  167. help_text=cr_settings['FRONTEND_THEME_HELP'],
  168. )
  169. panels = [
  170. MultiFieldPanel(
  171. [
  172. ImageChooserPanel('logo'),
  173. ImageChooserPanel('favicon'),
  174. ],
  175. heading=_('Branding')
  176. ),
  177. MultiFieldPanel(
  178. [
  179. FieldPanel('navbar_color_scheme'),
  180. FieldPanel('navbar_class'),
  181. FieldPanel('navbar_fixed'),
  182. FieldPanel('navbar_wrapper_fluid'),
  183. FieldPanel('navbar_content_fluid'),
  184. FieldPanel('navbar_collapse_mode'),
  185. FieldPanel('navbar_format'),
  186. FieldPanel('navbar_search'),
  187. ],
  188. heading=_('Site Navbar Layout')
  189. ),
  190. MultiFieldPanel(
  191. [
  192. FieldPanel('frontend_theme'),
  193. ],
  194. heading=_('Theming')
  195. ),
  196. ]
  197. @register_setting(icon='fa-google')
  198. class AnalyticsSettings(BaseSetting):
  199. """
  200. Tracking and Google Analytics.
  201. """
  202. class Meta:
  203. verbose_name = _('Tracking')
  204. ga_tracking_id = models.CharField(
  205. blank=True,
  206. max_length=255,
  207. verbose_name=_('UA Tracking ID'),
  208. help_text=_('Your Google "Universal Analytics" tracking ID (begins with "UA-")'),
  209. )
  210. ga_g_tracking_id = models.CharField(
  211. blank=True,
  212. max_length=255,
  213. verbose_name=_('G Tracking ID'),
  214. help_text=_('Your Google Analytics 4 tracking ID (begins with "G-")'),
  215. )
  216. ga_track_button_clicks = models.BooleanField(
  217. default=False,
  218. verbose_name=_('Track button clicks'),
  219. help_text=_('Track all button clicks using Google Analytics event tracking. Event tracking details can be specified in each button’s advanced settings options.'), # noqa
  220. )
  221. gtm_id = models.CharField(
  222. blank=True,
  223. max_length=255,
  224. verbose_name=_('Google Tag Manager ID'),
  225. help_text=_('Begins with "GTM-"'),
  226. )
  227. head_scripts = MonospaceField(
  228. blank=True,
  229. null=True,
  230. verbose_name=_('<head> tracking scripts'),
  231. help_text=_('Add tracking scripts between the <head> tags.'),
  232. )
  233. body_scripts = MonospaceField(
  234. blank=True,
  235. null=True,
  236. verbose_name=_('<body> tracking scripts'),
  237. help_text=_('Add tracking scripts toward closing <body> tag.'),
  238. )
  239. panels = [
  240. HelpPanel(
  241. heading=_('Know your tracking'),
  242. content=_(
  243. '<h3><b>Which tracking IDs do I need?</b></h3>'
  244. '<p>Before adding tracking to your site, '
  245. '<a href="https://docs.coderedcorp.com/cms/how_to/add_tracking_scripts.html" '
  246. 'target="_blank">read about the difference between UA, G, GTM, '
  247. 'and other tracking IDs</a>.</p>'
  248. ),
  249. ),
  250. MultiFieldPanel(
  251. [
  252. FieldPanel('ga_tracking_id'),
  253. FieldPanel('ga_g_tracking_id'),
  254. FieldPanel('ga_track_button_clicks'),
  255. ],
  256. heading=_('Google Analytics'),
  257. ),
  258. MultiFieldPanel(
  259. [
  260. FieldPanel('gtm_id'),
  261. ],
  262. heading=_('Google Tag Manager'),
  263. ),
  264. MultiFieldPanel(
  265. [
  266. FieldPanel('head_scripts'),
  267. FieldPanel('body_scripts'),
  268. ],
  269. heading=_('Other Tracking Scripts')
  270. )
  271. ]
  272. @register_setting(icon='fa-universal-access')
  273. class ADASettings(BaseSetting):
  274. """
  275. Accessibility related options.
  276. """
  277. class Meta:
  278. verbose_name = 'Accessibility'
  279. skip_navigation = models.BooleanField(
  280. default=False,
  281. verbose_name=_('Show skip navigation link'),
  282. help_text=_('Shows a "Skip Navigation" link above the navbar that takes you directly to the main content.'), # noqa
  283. )
  284. panels = [
  285. MultiFieldPanel(
  286. [
  287. FieldPanel('skip_navigation'),
  288. ],
  289. heading=_('Accessibility')
  290. )
  291. ]
  292. @register_setting(icon='cog')
  293. class GeneralSettings(BaseSetting):
  294. """
  295. Various site-wide settings. A good place to put
  296. one-off settings that don't belong anywhere else.
  297. """
  298. from_email_address = models.CharField(
  299. blank=True,
  300. max_length=255,
  301. verbose_name=_('From email address'),
  302. help_text=_('The default email address this site appears to send from. For example: "sender@example.com" or "Sender Name <sender@example.com>" (without quotes)'), # noqa
  303. )
  304. search_num_results = models.PositiveIntegerField(
  305. default=10,
  306. verbose_name=_('Number of results per page'),
  307. )
  308. external_new_tab = models.BooleanField(
  309. default=False,
  310. verbose_name=_('Open all external links in new tab')
  311. )
  312. panels = [
  313. MultiFieldPanel(
  314. [
  315. FieldPanel('from_email_address'),
  316. ],
  317. _('Email')
  318. ),
  319. MultiFieldPanel(
  320. [
  321. FieldPanel('search_num_results'),
  322. ],
  323. _('Search Settings')
  324. ),
  325. MultiFieldPanel(
  326. [
  327. FieldPanel('external_new_tab'),
  328. ],
  329. _('Links')
  330. ),
  331. ]
  332. class Meta:
  333. verbose_name = _('General')
  334. @register_setting(icon='fa-puzzle-piece')
  335. class GoogleApiSettings(BaseSetting):
  336. """
  337. Settings for Google API services.
  338. """
  339. class Meta:
  340. verbose_name = _('Google API')
  341. google_maps_api_key = models.CharField(
  342. blank=True,
  343. max_length=255,
  344. verbose_name=_('Google Maps API Key'),
  345. help_text=_('The API Key used for Google Maps.')
  346. )
  347. @register_setting(icon='fa-puzzle-piece')
  348. class MailchimpApiSettings(BaseSetting):
  349. """
  350. Settings for Mailchimp API services.
  351. """
  352. class Meta:
  353. verbose_name = _('Mailchimp API')
  354. mailchimp_api_key = models.CharField(
  355. blank=True,
  356. max_length=255,
  357. verbose_name=_('Mailchimp API Key'),
  358. help_text=_('The API Key used for Mailchimp.')
  359. )