wagtailsettings_models.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  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 HelpPanel, FieldPanel, 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.settings import cr_settings
  14. @register_setting(icon='fa-facebook-official')
  15. class SocialMediaSettings(BaseSetting):
  16. """
  17. Social media accounts.
  18. """
  19. class Meta:
  20. verbose_name = _('Social Media')
  21. facebook = models.URLField(
  22. blank=True,
  23. verbose_name=_('Facebook'),
  24. help_text=_('Your Facebook page URL'),
  25. )
  26. twitter = models.URLField(
  27. blank=True,
  28. verbose_name=_('Twitter'),
  29. help_text=_('Your Twitter page URL'),
  30. )
  31. instagram = models.CharField(
  32. max_length=255,
  33. blank=True,
  34. verbose_name=_('Instagram'),
  35. help_text=_('Your Instagram username, without the @'),
  36. )
  37. youtube = models.URLField(
  38. blank=True,
  39. verbose_name=_('YouTube'),
  40. help_text=_('Your YouTube channel or user account URL'),
  41. )
  42. linkedin = models.URLField(
  43. blank=True,
  44. verbose_name=_('LinkedIn'),
  45. help_text=_('Your LinkedIn page URL'),
  46. )
  47. googleplus = models.URLField(
  48. blank=True,
  49. verbose_name=_('Google'),
  50. help_text=_('Your Google+ page or Google business listing URL'),
  51. )
  52. @property
  53. def twitter_handle(self):
  54. """
  55. Gets the handle of the twitter account from a URL.
  56. """
  57. return self.twitter.strip().strip('/').split('/')[-1]
  58. @property
  59. def social_json(self):
  60. """
  61. Returns non-blank social accounts as a JSON list.
  62. """
  63. socialist = [
  64. self.facebook,
  65. self.twitter,
  66. self.instagram,
  67. self.youtube,
  68. self.linkedin,
  69. self.googleplus,
  70. ]
  71. socialist = list(filter(None, socialist))
  72. return json.dumps(socialist)
  73. panels = [
  74. MultiFieldPanel(
  75. [
  76. FieldPanel('facebook'),
  77. FieldPanel('twitter'),
  78. FieldPanel('instagram'),
  79. FieldPanel('youtube'),
  80. FieldPanel('linkedin'),
  81. FieldPanel('googleplus'),
  82. ],
  83. _('Social Media Accounts'),
  84. )
  85. ]
  86. @register_setting(icon='fa-desktop')
  87. class LayoutSettings(BaseSetting):
  88. """
  89. Branding, navbar, and theme settings.
  90. """
  91. class Meta:
  92. verbose_name = _('Layout')
  93. logo = models.ForeignKey(
  94. get_image_model_string(),
  95. null=True,
  96. blank=True,
  97. on_delete=models.SET_NULL,
  98. related_name='+',
  99. verbose_name=_('Logo'),
  100. help_text=_('Brand logo used in the navbar and throughout the site')
  101. )
  102. favicon = models.ForeignKey(
  103. get_image_model_string(),
  104. null=True,
  105. blank=True,
  106. on_delete=models.SET_NULL,
  107. related_name='favicon',
  108. verbose_name=_('Favicon'),
  109. )
  110. navbar_color_scheme = models.CharField(
  111. blank=True,
  112. max_length=50,
  113. choices=cr_settings['FRONTEND_NAVBAR_COLOR_SCHEME_CHOICES'],
  114. default=cr_settings['FRONTEND_NAVBAR_COLOR_SCHEME_DEFAULT'],
  115. verbose_name=_('Navbar color scheme'),
  116. help_text=_('Optimizes text and other navbar elements for use with light or dark backgrounds.'), # noqa
  117. )
  118. navbar_class = models.CharField(
  119. blank=True,
  120. max_length=255,
  121. default=cr_settings['FRONTEND_NAVBAR_CLASS_DEFAULT'],
  122. verbose_name=_('Navbar CSS class'),
  123. help_text=_('Custom classes applied to navbar e.g. "bg-light", "bg-dark", "bg-primary".'),
  124. )
  125. navbar_fixed = models.BooleanField(
  126. default=False,
  127. verbose_name=_('Fixed navbar'),
  128. help_text=_('Fixed navbar will remain at the top of the page when scrolling.'),
  129. )
  130. navbar_wrapper_fluid = models.BooleanField(
  131. default=True,
  132. verbose_name=_('Full width navbar'),
  133. help_text=_('The navbar will fill edge to edge.'),
  134. )
  135. navbar_content_fluid = models.BooleanField(
  136. default=False,
  137. verbose_name=_('Full width navbar contents'),
  138. help_text=_('Content within the navbar will fill edge to edge.'),
  139. )
  140. navbar_collapse_mode = models.CharField(
  141. blank=True,
  142. max_length=50,
  143. choices=cr_settings['FRONTEND_NAVBAR_COLLAPSE_MODE_CHOICES'],
  144. default=cr_settings['FRONTEND_NAVBAR_COLLAPSE_MODE_DEFAULT'],
  145. verbose_name=_('Collapse navbar menu'),
  146. help_text=_('Control on what screen sizes to show and collapse the navbar menu links.'),
  147. )
  148. navbar_format = models.CharField(
  149. blank=True,
  150. max_length=50,
  151. choices=cr_settings['FRONTEND_NAVBAR_FORMAT_CHOICES'],
  152. default=cr_settings['FRONTEND_NAVBAR_FORMAT_DEFAULT'],
  153. verbose_name=_('Navbar format'),
  154. )
  155. navbar_search = models.BooleanField(
  156. default=True,
  157. verbose_name=_('Search box'),
  158. help_text=_('Show search box in navbar')
  159. )
  160. frontend_theme = models.CharField(
  161. blank=True,
  162. max_length=50,
  163. choices=cr_settings['FRONTEND_THEME_CHOICES'],
  164. default=cr_settings['FRONTEND_THEME_DEFAULT'],
  165. verbose_name=_('Theme variant'),
  166. help_text=cr_settings['FRONTEND_THEME_HELP'],
  167. )
  168. panels = [
  169. MultiFieldPanel(
  170. [
  171. ImageChooserPanel('logo'),
  172. ImageChooserPanel('favicon'),
  173. ],
  174. heading=_('Branding')
  175. ),
  176. MultiFieldPanel(
  177. [
  178. FieldPanel('navbar_color_scheme'),
  179. FieldPanel('navbar_class'),
  180. FieldPanel('navbar_fixed'),
  181. FieldPanel('navbar_wrapper_fluid'),
  182. FieldPanel('navbar_content_fluid'),
  183. FieldPanel('navbar_collapse_mode'),
  184. FieldPanel('navbar_format'),
  185. FieldPanel('navbar_search'),
  186. ],
  187. heading=_('Site Navbar Layout')
  188. ),
  189. MultiFieldPanel(
  190. [
  191. FieldPanel('frontend_theme'),
  192. ],
  193. heading=_('Theming')
  194. ),
  195. ]
  196. @register_setting(icon='fa-google')
  197. class AnalyticsSettings(BaseSetting):
  198. """
  199. Tracking and Google Analytics.
  200. """
  201. class Meta:
  202. verbose_name = _('Tracking')
  203. ga_tracking_id = models.CharField(
  204. blank=True,
  205. max_length=255,
  206. verbose_name=_('GA Tracking ID'),
  207. help_text=_('Your Google Analytics tracking ID (begins with "UA-")'),
  208. )
  209. ga_track_button_clicks = models.BooleanField(
  210. default=False,
  211. verbose_name=_('Track button clicks'),
  212. 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
  213. )
  214. panels = [
  215. MultiFieldPanel(
  216. [
  217. FieldPanel('ga_tracking_id'),
  218. FieldPanel('ga_track_button_clicks'),
  219. ],
  220. heading=_('Google Analytics')
  221. )
  222. ]
  223. @register_setting(icon='fa-universal-access')
  224. class ADASettings(BaseSetting):
  225. """
  226. Accessibility related options.
  227. """
  228. class Meta:
  229. verbose_name = 'Accessibility'
  230. skip_navigation = models.BooleanField(
  231. default=False,
  232. verbose_name=_('Show skip navigation link'),
  233. help_text=_('Shows a "Skip Navigation" link above the navbar that takes you directly to the main content.'), # noqa
  234. )
  235. panels = [
  236. MultiFieldPanel(
  237. [
  238. FieldPanel('skip_navigation'),
  239. ],
  240. heading=_('Accessibility')
  241. )
  242. ]
  243. @register_setting(icon='cog')
  244. class GeneralSettings(BaseSetting):
  245. """
  246. Various site-wide settings. A good place to put
  247. one-off settings that don't belong anywhere else.
  248. """
  249. from_email_address = models.CharField(
  250. blank=True,
  251. max_length=255,
  252. verbose_name=_('From email address'),
  253. 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
  254. )
  255. search_num_results = models.PositiveIntegerField(
  256. default=10,
  257. verbose_name=_('Number of results per page'),
  258. )
  259. external_new_tab = models.BooleanField(
  260. default=False,
  261. verbose_name=_('Open all external links in new tab')
  262. )
  263. panels = [
  264. MultiFieldPanel(
  265. [
  266. FieldPanel('from_email_address'),
  267. ],
  268. _('Email')
  269. ),
  270. MultiFieldPanel(
  271. [
  272. FieldPanel('search_num_results'),
  273. ],
  274. _('Search Settings')
  275. ),
  276. MultiFieldPanel(
  277. [
  278. FieldPanel('external_new_tab'),
  279. ],
  280. _('Links')
  281. ),
  282. ]
  283. class Meta:
  284. verbose_name = _('General')
  285. @register_setting(icon='fa-line-chart')
  286. class SeoSettings(BaseSetting):
  287. """
  288. Additional search engine optimization and meta tags
  289. that can be turned on or off.
  290. """
  291. class Meta:
  292. verbose_name = _('SEO')
  293. og_meta = models.BooleanField(
  294. default=True,
  295. verbose_name=_('Use OpenGraph Markup'),
  296. help_text=_('Show an optimized preview when linking to this site on Facebook, Linkedin, Twitter, and others. See http://ogp.me/.'), # noqa
  297. )
  298. twitter_meta = models.BooleanField(
  299. default=True,
  300. verbose_name=_('Use Twitter Markup'),
  301. help_text=_('Shows content as a "card" when linking to this site on Twitter. See https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/abouts-cards.'), # noqa
  302. )
  303. struct_meta = models.BooleanField(
  304. default=True,
  305. verbose_name=_('Use Structured Data'),
  306. help_text=_('Optimizes information about your organization for search engines. See https://schema.org/.'), # noqa
  307. )
  308. amp_pages = models.BooleanField(
  309. default=True,
  310. verbose_name=_('Use AMP Pages'),
  311. help_text=_('Generates an alternate AMP version of Article pages that are preferred by search engines. See https://www.ampproject.org/'), # noqa
  312. )
  313. panels = [
  314. MultiFieldPanel(
  315. [
  316. FieldPanel('og_meta'),
  317. FieldPanel('twitter_meta'),
  318. FieldPanel('struct_meta'),
  319. FieldPanel('amp_pages'),
  320. HelpPanel(content=_('If these settings are enabled, the corresponding values in each page’s SEO tab are used.')), # noqa
  321. ],
  322. heading=_('Search Engine Optimization')
  323. )
  324. ]
  325. @register_setting(icon='fa-puzzle-piece')
  326. class GoogleApiSettings(BaseSetting):
  327. """
  328. Settings for Google API services.
  329. """
  330. class Meta:
  331. verbose_name = _('Google API')
  332. google_maps_api_key = models.CharField(
  333. blank=True,
  334. max_length=255,
  335. verbose_name=_('Google Maps API Key'),
  336. help_text=_('The API Key used for Google Maps.')
  337. )
  338. @register_setting(icon='fa-puzzle-piece')
  339. class MailchimpApiSettings(BaseSetting):
  340. """
  341. Settings for Mailchimp API services.
  342. """
  343. class Meta:
  344. verbose_name = _('Mailchimp API')
  345. mailchimp_api_key = models.CharField(
  346. blank=True,
  347. max_length=255,
  348. verbose_name=_('Mailchimp API Key'),
  349. help_text=_('The API Key used for Mailchimp.')
  350. )