public function searchContent($q, array $contenttypes = null, array $filters = null, $limit = 9999, $offset = 0)
    {
        $query = $this->decodeSearchQuery($q);
        if (!$query['valid']) {
            return false;
        }

        $appCt = $this->app['config']->get('contenttypes');

        // By default we only search through searchable contenttypes
        if (is_null($contenttypes)) {
            $contenttypes = array_keys($appCt);
            $contenttypes = array_filter(
                $contenttypes,
                function ($ct) use ($appCt) {
                    if ((isset($appCt[$ct]['searchable']) && $appCt[$ct]['searchable'] === false) ||
                        (isset($appCt[$ct]['viewless']) && $appCt[$ct]['viewless'] === true)
                    ) {
                        return false;
                    }

                    return true;
                }
            );
            $contenttypes = array_map(
                function ($ct) use ($appCt) {
                    return $appCt[$ct]['slug'];
                },
                $contenttypes
            );
        }

        // Build our search results array
        $results = [];

        // First, attempt to search for the literal string, eg. "Lorum Ipsum"
        foreach ($contenttypes as $contenttype) {
            $ctconfig = $this->getContentType($contenttype);

            $fields = $ctconfig['fields'];
            $filter = null;

            if (is_array($filters) && isset($filters[$contenttype])) {
                $filter = $filters[$contenttype];
            }

            $subResults = $this->searchSingleContentType($query, $contenttype, $fields, $filter, true);

            $results = array_merge($results, $subResults);
        }

        // If that didn't produce results, search for "Lorum" or "Ipsum"
        if (empty($results)) {
            foreach ($contenttypes as $contenttype) {
                $ctconfig = $this->getContentType($contenttype);

                $fields = $ctconfig['fields'];
                $filter = null;

                if (is_array($filters) && isset($filters[$contenttype])) {
                    $filter = $filters[$contenttype];
                }

                $subResults = $this->searchSingleContentType($query, $contenttype, $fields, $filter, false);

                $results = array_merge($results, $subResults);
            }
        }

        // Sort the results
        usort($results, [$this, 'compareSearchWeights']);

        $noOfResults = count($results);

        $pageResults = [];
        if ($offset < $noOfResults) {
            $pageResults = array_slice($results, $offset, $limit);
        }

        return [
            'query'         => $query,
            'no_of_results' => $noOfResults,
            'results'       => $pageResults,
        ];
    }