23. Content types III: Sponsors – Mastering Plone 6 development

23. Content types III: Sponsors#

Without sponsors, a conference would be hard to finance! Plus it is a good opportunity for Plone companies to advertise their services.

In this part we will:

  • Create a sponsor contenttype to manage sponsors

  • Store non-visible information about the sponsor in the sponsor-type

Tools and techniques covered:

  • Schema hint and directives

  • Field permissions

Backend chapter

Checkout ploneconf.site at tag "search":

git checkout search

The code at the end of the chapter:

git checkout schema

More info in The code for the training

23.1. The Python schema#

First we create the schema for the new content type.

Add a new file content/sponsor.py.

 1from plone.app.textfield import RichText
 2from plone.autoform import directives
 3from plone.dexterity.content import Container
 4from plone.namedfile import field as namedfile
 5from plone.supermodel import model
 6from plone.supermodel.directives import fieldset
 7from zope import schema
 8from zope.interface import implementer
 9
10
11class ISponsor(model.Schema):
12    """Dexterity Schema for Sponsors"""
13
14    level = schema.Choice(
15        title="Sponsoring Level", values=["bronze", "silver", "gold"], required=True
16    )
17
18    text = RichText(title="Text", required=False)
19
20    url = schema.URI(title="Link", required=False)
21
22    fieldset("Images", fields=["logo", "advertisement"])
23    logo = namedfile.NamedBlobImage(
24        title="Logo",
25        required=False,
26    )
27
28    advertisement = namedfile.NamedBlobImage(
29        title="Advertisement (Gold-sponsors and above)",
30        required=False,
31    )
32
33    directives.read_permission(notes="plone.app.controlpanel.Site")
34    directives.write_permission(notes="plone.app.controlpanel.Site")
35    notes = RichText(
36        title="Secret Notes (only for site-administrators and managers)", required=False
37    )
38
39
40@implementer(ISponsor)
41class Sponsor(Container):
42    """Sponsor instance class"""

Some things are notable here:

  • fieldset('Images', fields=['logo', 'advertisement']) moves the two image fields to another tab.

  • directives.read_permission(...) sets the read and write permission for the field notes to users who can make changes on the control panel 'Site'. Usually this permission is only granted to Site Administrators and Managers. We use it to store information that should not be publicly visible.

See also

See the Content types: Reference for a reference of all field-types and directives you can use in dexterity.

23.2. The Factory Type Information, or FTI#

Next, we create the factory type information ("FTI") for the new type in profiles/default/types/sponsor.xml

 1<?xml version="1.0" encoding="utf-8"?>
 2<object xmlns:i18n="http://xml.zope.org/namespaces/i18n"
 3        meta_type="Dexterity FTI"
 4        name="sponsor"
 5        i18n:domain="plone"
 6>
 7  <property name="title"
 8            i18n:translate=""
 9  >Sponsor</property>
10  <property name="description"
11            i18n:translate=""
12  />
13  <property name="icon_expr">string:${portal_url}/document_icon.png</property>
14  <property name="factory">sponsor</property>
15  <property name="add_view_expr">string:${folder_url}/++add++sponsor</property>
16  <property name="link_target" />
17  <property name="immediate_view">view</property>
18  <property name="global_allow">True</property>
19  <property name="filter_content_types">True</property>
20  <property name="allowed_content_types" />
21  <property name="allow_discussion">False</property>
22  <property name="default_view">view</property>
23  <property name="view_methods">
24    <element value="view" />
25  </property>
26  <property name="default_view_fallback">False</property>
27  <property name="add_permission">cmf.AddPortalContent</property>
28  <property name="schema">ploneconf.site.content.sponsor.ISponsor</property>
29  <property name="klass">ploneconf.site.content.sponsor.Sponsor</property>
30  <property name="behaviors">
31    <element value="plone.dublincore" />
32    <element value="plone.namefromtitle" />
33    <element value="plone.versioning" />
34  </property>
35  <property name="model_source" />
36  <property name="model_file" />
37  <property name="schema_policy">dexterity</property>
38  <alias from="(Default)"
39         to="(dynamic view)"
40  />
41  <alias from="edit"
42         to="@@edit"
43  />
44  <alias from="sharing"
45         to="@@sharing"
46  />
47  <alias from="view"
48         to="(selected layout)"
49  />
50  <action action_id="view"
51          category="object"
52          condition_expr=""
53          description=""
54          icon_expr=""
55          link_target=""
56          title="View"
57          url_expr="string:${object_url}"
58          visible="True"
59  >
60    <permission value="View" />
61  </action>
62  <action action_id="edit"
63          category="object"
64          condition_expr=""
65          description=""
66          icon_expr=""
67          link_target=""
68          title="Edit"
69          url_expr="string:${object_url}/edit"
70          visible="True"
71  >
72    <permission value="Modify portal content" />
73  </action>
74</object>

Then we register the FTI in profiles/default/types.xml

1<?xml version="1.0"?>
2<object name="portal_types" meta_type="Plone Types Tool">
3 <object name="talk" meta_type="Dexterity FTI"/>
4 <object name="sponsor" meta_type="Dexterity FTI"/>
5</object>

After reinstalling our package we can create the new type.

In production you will want to manage and document such changes in code with upgrade steps. See the next chapter.

23.3. Summary#

  • You created a new content type to store information on sponsors

  • You learned how to protect individual fields from being edited with permissions

  • Next you will learn how to display the sponsors at the bottom of every page