A CQL Search macro allows you to enter Common Query Language (CQL). The following image is a CQL Search macro form filled with example content:

The following image is an example of the code for this macro:

import com.atlassian.confluence.api.model.Expansion
import com.atlassian.confluence.api.model.content.Content
import com.atlassian.confluence.api.model.pagination.PageResponse
import com.atlassian.confluence.api.model.pagination.SimplePageRequest
import com.atlassian.confluence.api.model.search.SearchContext
import com.atlassian.confluence.api.service.search.CQLSearchService
import com.atlassian.confluence.xhtml.api.XhtmlContent
import com.onresolve.scriptrunner.runner.ScriptRunnerImpl
import groovy.xml.MarkupBuilder

def cqlSearchService = ScriptRunnerImpl.getOsgiService(CQLSearchService)
def xhtmlContent = ScriptRunnerImpl.getOsgiService(XhtmlContent)
def maxResults = parameters.maxResults as Integer ?: 10

def cqlQuery = parameters.cql as String

def pageRequest = new SimplePageRequest(0, maxResults)
def searchResult = cqlSearchService.searchContent(cqlQuery, SearchContext.builder().build(), pageRequest, Expansion.combine("space")) as PageResponse<Content>

def writer = new StringWriter()
def builder = new MarkupBuilder(writer)

if (searchResult.size()) {
    builder.table {
        tbody {
            tr {
                th { p("Title") }
                th { p("Space") }
            }
            searchResult.results.each { content ->
                tr {
                    td {
                        p {
                            "ac:link" {
                                "ri:page"("ri:content-title": content.title, "ri:space-key": content.space.key)
                            }
                        }
                    }
                    td { p(content.space.name) }
                }
            }
        }
    }

    if (searchResult.respondsTo("totalSize")) { // confl 5.8+
        builder.p("Showing ${Math.min(maxResults, searchResult.totalSize())} of ${searchResult.totalSize()}")
    }
} else {
    builder.p("No results")
}

def view = xhtmlContent.convertStorageToView(writer.toString(), context)
view