Content properties are a form of key-value storage, where the key is associated with a piece of Confluence Content. Content properties are one of the forms of persistence available to you as an add-on developer. Content properties allow to store up to 32 KB of JSON with each piece of content (for example, a page, blog post, or attachment), so, you do not have to use your own data store. If you need to store metadata, for example, about a piece (or pieces) of content, content property is a great way to do it.
Content properties are accessible both by Java and REST APIs.
You can use CQL to query content properties in your Confluence instance. For example, a plugin can store the number of likes on a page in a content property. You can create an index schema module for that property, and then you can query the values to see how many pieces of content have more than 20 likes.
GET content properties
To retrieve any existing content properties for a piece of content, perform a GET on the
endpoint /rest/api/content/{content_ID}/property
.
1 2# Retrieves content properties associated with a piece of content with ID 12345 curl -u admin:admin -X GET "http://localhost:8080/confluence/rest/api/content/12345/property" | python -mjson.tool
POST new content properties
To add content properties to a piece of Confluence content, perform a POST to the same endpoint. The key in your content property can be an arbitrary string (like "myprop"), whereas the value must be a structured JSON.
1 2# Stores a JSON document under the key "myprop" against content with ID 12345 curl -i -u admin:admin -X POST -H "Content-Type: application/json" \ -d '{ "key" : "myprop", "value" : { "id": "507f1f77bcf86cd799439011", "editDate": "2000-01-01T11:00:00.000+11:00", "description": "If you have any questions please address them to admin@example.com", "content": { "likes": 5, "tags": ["cql", "confluence"] } } }' http://localhost:8080/confluence/rest/api/content/12345/property
DELETE content properties
If you need to delete content properties, you can perform a DELETE on the endpoint.
1 2# Removes JSON document associated with key "myprop from content with ID 12345 curl -i -u admin:admin -X DELETE "http://localhost:8080/confluence/rest/api/content/12345/property/myprop"
Content properties are available as an expansion on the content resource. This allows content properties to be retrieved in the same REST call as fetching the content itself. This expansion is available from any resource that returns content, including the CQL search resource.
GET content properties as an expansion on content.
1 2# fetch properties at the same time as fetching content, note the expand=metadata.properties.myprop curl -u admin:admin -X GET "http://localhost:8080/confluence/rest/api/content/12345?expand=metadata.properties.myprop" | python -mjson.tool { id: "12345", type: "page", status: "current", title: "New in the platform team? Read me first", metadata: { _expandable: { currentuser: "", labels: "", properties: { myprop: { "id": "507f1f77bcf86cd799439011", "editDate": "2000-01-01T11:00:00.000+11:00", "description": "If you have any questions please address them to admin@example.com", "content": { "likes": 5, "tags": ["cql", "confluence"] } } } } } }
To allow searching of content properties using CQL, you can enable indexing of data stored as content properties by defining an index schema. You can define an exclusive index schema for each content property key; then, whenever a content property is saved, Confluence checks if a schema is defined for its key. If a schema exists, indexable values are extracted from content property values and stored in an index. There can only be one index schema definition for a content property key, so any duplicates are disabled. In the case of offending keys, an appropriate log message is available.
When defining an index schema for content properties, you need to provide a set of extraction expressions and field
type pairs, which are used to retrieve a specific value from a JSON document and transform it into the desired representation.
Supported index field types are: string
, text
, number
, and date
.
For an example, see the JSON document and its index schema later on this page.
Example of content property value.
1 2{ "id": "507f1f77bcf86cd799439011", "editDate": "2000-01-01T11:00:00.000+11:00", "description": "If you have any questions please address them to admin@example.com", "content": { "likes": 5, "tags": ["cql", "confluence"] } }
Extraction definition for a P2 plugin | Extracted value |
---|---|
<extract path="id" type="string" /> | "507f1f77bcf86cd799439011" |
<extract path="editDate" type="date" /> | 1st of Jan 2000 00:00:00.000 UTC |
<extract path="content.tags" type="string" /> | An array containing "cql" , "confluence" |
<extract path="content.likes" type="number" /> | 5 |
To access an embedded field in a document, use dot notation as shown in the following example. After successful validation, all extracted values are stored inside an index, and you can address them in CQL queries.
Putting it all together, here's a sample index schema definition:
atlassian-plugin.xml
Example of P2 add-on index schema definition
1 2<content-property-index-schema key="module-key"> <key property-key="attachments"> <extract path="id" type="string" /> <extract path="description" type="text" /> <extract path="editDate" type="date" /> </key> <key property-key="metadata"> <extract path="content.tags" type="string" /> <extract path="content.likes" type="number" /> </key> </content-property-index-schema>
Field type doesn't only specify how data is stored in the index, but also determines which CQL operators are available in your query.
Type | Description | Supported CQL operators |
---|---|---|
string | Entire extracted value will be indexed as a single token, without any filtering. When extraction expression evaluates to a JSON array, each element will be indexed separately. Enables searching for an exact value, e.g. unique identifier. | IN , NOT IN , = , != |
text | Extracted value will be tokenized before indexing, allowing searching for a particular words. | ~ , !~ |
number | Extracted number will be indexed as a double value for efficient range filtering. |
< , <= , = , != , > , >=
|
date | Two representation are possible, either a String following the ISO 8601 datetime format, or a long value in the Unix time. Enables efficient range filtering.
| < , <= , = , != , > , >=
|
You can't currently sort by these fields. See CONFSERVER-58077.
You can address indexed content properties in a CQL query using the content.property
field handler.
Any content that contains content properties matching the query is returned in the results.
The query syntax is as follows: content.property[<KEY>].<PATH> <OPERATOR> value
.
Examples of CQL queries on content properties.
1 2content.property[attachments].editDate >= 2001-01-01 content.property[attachments].description ~ "questions" content.property[metadata].content.tags IN ("cql", "help") content.property[metadata].content.likes <= 5
Note the dot notation when referencing embedded fields like 'content.likes'.
Legend
Symbol | Meaning |
---|---|
KEY | The key of the content properties you search. |
PATH | The path to the value you'd like to search in the JSON document (use dot notation for embedded fields). |
OPERATOR | One of the supported CQL operators for the field type. |
Content properties which are attached to custom content can also be indexed in the content body field by defining search body property module descriptors which make reference to the custom content type and content property key. This makes custom content searchable by content properties via the CQL 'text' field and also the quick-nav search bar.
For the following examples assume we have two custom content types com.company.product.plugins.pluginName:customType
and myCustomType
with
defined content with IDs 123456789
and 987654321
respectively.
Examples of search body property definitions in atlassian-plugin.xml
1 2<search-body-property key="moduleKey" content-type="com.company.product.plugins.pluginName:customType" content-property="attachments" /> <search-body-property key="moduleKeyTwo" content-type="myCustomType" content-property="metadata" />
content-type
refers to the custom content type.
content-property
refers to the content property key to extract the value to be added to the content body field.
Examples of corresponding content properties POST requests for custom content
1 2# Stores a JSON document under the key "myprop" against content with ID 12345 curl -i -u admin:admin -X POST -H "Content-Type: application/json" \ -d '{ "key" : "attachments", "value" : "This text will be added to the content body field" }' http://localhost:8080/confluence/rest/api/content/123456789/property
1 2# Stores a JSON document under the key "myprop" against content with ID 12345 curl -i -u admin:admin -X POST -H "Content-Type: application/json" \ -d '{ "key" : "metadata", "value" : { "description": "The whole json value be added to the content body field", "content": { "likes": 5, "tags": ["cql", "confluence"] } } }' http://localhost:8080/confluence/rest/api/content/987654321/property
Custom content type | Content id | What is added to content body field |
---|---|---|
com.company.product.plugins.pluginName:customType | 123456789 | "This text will be added to the content body field" |
myCustomType | 987654321 | "{
"description": "The whole json value be added to the content body field",
"content": {
"likes": 5,
"tags": ["cql", "confluence"]
}
}" |
JSON expressions and extractions that are available when using the index schema are not available as part of the search body property descriptors. In the second content properties example above, the JSON inside the value field will be converted into text and stored in the content body field, even the JSON field names "description" and "content" will be used in indexing for search.
Rate this page: