public static function processLinkExcerpt($excerpt, PageInterface $page, $type = 'link')
    {
        $url = htmlspecialchars_decode(rawurldecode($excerpt['element']['attributes']['href']));

        $url_parts = static::parseUrl($url);

        // If there is a query, then parse it and build action calls.
        if (isset($url_parts['query'])) {
            $actions = array_reduce(explode('&', $url_parts['query']), function ($carry, $item) {
                $parts = explode('=', $item, 2);
                $value = isset($parts[1]) ? rawurldecode($parts[1]) : true;
                $carry[$parts[0]] = $value;

                return $carry;
            }, []);

            // Valid attributes supported.
            $valid_attributes = ['rel', 'target', 'id', 'class', 'classes'];

            // Unless told to not process, go through actions.
            if (array_key_exists('noprocess', $actions)) {
                unset($actions['noprocess']);
            } else {
                // Loop through actions for the image and call them.
                foreach ($actions as $attrib => $value) {
                    $key = $attrib;

                    if (in_array($attrib, $valid_attributes, true)) {
                        // support both class and classes.
                        if ($attrib === 'classes') {
                            $attrib = 'class';
                        }
                        $excerpt['element']['attributes'][$attrib] = str_replace(',', ' ', $value);
                        unset($actions[$key]);
                    }
                }
            }

            $url_parts['query'] = http_build_query($actions, null, '&', PHP_QUERY_RFC3986);
        }

        // If no query elements left, unset query.
        if (empty($url_parts['query'])) {
            unset ($url_parts['query']);
        }

        // Set path to / if not set.
        if (empty($url_parts['path'])) {
            $url_parts['path'] = '';
        }

        // If scheme isn't http(s)..
        if (!empty($url_parts['scheme']) && !in_array($url_parts['scheme'], ['http', 'https'])) {
            // Handle custom streams.
            if ($type !== 'image' && !empty($url_parts['stream']) && !empty($url_parts['path'])) {
                $url_parts['path'] = Grav::instance()['base_url_relative'] . '/' . static::resolveStream("{$url_parts['scheme']}://{$url_parts['path']}");
                unset($url_parts['stream'], $url_parts['scheme']);
            }

            $excerpt['element']['attributes']['href'] = Uri::buildUrl($url_parts);
            return $excerpt;
        }

        // Handle paths and such.
        $url_parts = Uri::convertUrl($page, $url_parts, $type);

        // Build the URL from the component parts and set it on the element.
        $excerpt['element']['attributes']['href'] = Uri::buildUrl($url_parts);

        return $excerpt;
    }