PK

ADDRLIN : /home/carfac/.trash/wp-statistics.1/src/Service/Analytics/
FLL :
Current File : /home/carfac/.trash/wp-statistics.1/src/Service/Analytics/UrlResolver.php

<?php

namespace WP_Statistics\Service\Analytics;

/**
 * Resolves page type and ID from URL path for SPA tracking support.
 *
 * When tracking hits via REST API, the client sends the page_uri parameter.
 * This class resolves that URI to the correct source_type and source_id,
 * fixing the issue where SPA navigations send stale client-side values.
 */
class UrlResolver
{
    /**
     * Resolve page type and ID from URL path
     *
     * @param string $pageUri URL path (e.g., "/blog/my-post/")
     * @return array ['type' => string, 'id' => int, 'search_query' => string]
     */
    public static function resolve($pageUri)
    {
        $result = ['type' => 'unknown', 'id' => 0, 'search_query' => ''];

        if (empty($pageUri)) {
            return $result;
        }

        // Normalize URI
        $pageUri = '/' . ltrim($pageUri, '/');

        // 1. Home page
        if ($pageUri === '/') {
            return ['type' => 'home', 'id' => 0, 'search_query' => ''];
        }

        // 2. Search page
        if (preg_match('/[?&]s=([^&]*)/', $pageUri, $matches)) {
            return [
                'type'         => 'search',
                'id'           => 0,
                'search_query' => sanitize_text_field(urldecode($matches[1]))
            ];
        }

        // 3. Try to resolve as post/page using WordPress
        $fullUrl = home_url($pageUri);
        $postId  = url_to_postid($fullUrl);

        if ($postId > 0) {
            $postType = get_post_type($postId);
            $type     = self::mapPostType($postType);

            return ['type' => $type, 'id' => $postId, 'search_query' => ''];
        }

        // 4. Try to resolve as taxonomy term
        $termResult = self::resolveTaxonomy($pageUri);
        if ($termResult) {
            return $termResult;
        }

        // 5. Try to resolve as author
        $authorResult = self::resolveAuthor($pageUri);
        if ($authorResult) {
            return $authorResult;
        }

        // 6. Return unknown - fallback to client values
        return $result;
    }

    /**
     * Map WordPress post type to WP Statistics source type
     *
     * @param string $postType WordPress post type
     * @return string WP Statistics source type
     */
    private static function mapPostType($postType)
    {
        if ($postType === 'post') {
            return 'post';
        }
        if ($postType === 'page') {
            return 'page';
        }
        if ($postType === 'attachment') {
            return 'attachment';
        }
        if ($postType === 'product') {
            return 'product';
        }

        return 'post_type_' . $postType;
    }

    /**
     * Resolve taxonomy term from URL
     *
     * @param string $pageUri URL path
     * @return array|null Resolved taxonomy data or null
     */
    private static function resolveTaxonomy($pageUri)
    {
        // Get category base
        $categoryBase = get_option('category_base');
        if (empty($categoryBase)) {
            $categoryBase = 'category';
        }

        // Check category
        if (preg_match('#/' . preg_quote($categoryBase, '#') . '/([^/]+)/?#', $pageUri, $matches)) {
            $term = get_term_by('slug', $matches[1], 'category');
            if ($term && !is_wp_error($term)) {
                return ['type' => 'category', 'id' => $term->term_id, 'search_query' => ''];
            }
        }

        // Get tag base
        $tagBase = get_option('tag_base');
        if (empty($tagBase)) {
            $tagBase = 'tag';
        }

        // Check tag
        if (preg_match('#/' . preg_quote($tagBase, '#') . '/([^/]+)/?#', $pageUri, $matches)) {
            $term = get_term_by('slug', $matches[1], 'post_tag');
            if ($term && !is_wp_error($term)) {
                return ['type' => 'post_tag', 'id' => $term->term_id, 'search_query' => ''];
            }
        }

        // Check custom taxonomies
        $customTaxonomies = get_taxonomies(['public' => true, '_builtin' => false], 'objects');
        foreach ($customTaxonomies as $taxonomy) {
            $rewriteSlug = isset($taxonomy->rewrite['slug']) ? $taxonomy->rewrite['slug'] : $taxonomy->name;

            if (preg_match('#/' . preg_quote($rewriteSlug, '#') . '/([^/]+)/?#', $pageUri, $matches)) {
                $term = get_term_by('slug', $matches[1], $taxonomy->name);
                if ($term && !is_wp_error($term)) {
                    return ['type' => 'tax_' . $taxonomy->name, 'id' => $term->term_id, 'search_query' => ''];
                }
            }
        }

        return null;
    }

    /**
     * Resolve author from URL
     *
     * @param string $pageUri URL path
     * @return array|null Resolved author data or null
     */
    private static function resolveAuthor($pageUri)
    {
        global $wp_rewrite;

        $authorBase = !empty($wp_rewrite->author_base) ? $wp_rewrite->author_base : 'author';

        if (preg_match('#/' . preg_quote($authorBase, '#') . '/([^/]+)/?#', $pageUri, $matches)) {
            $author = get_user_by('slug', $matches[1]);
            if ($author) {
                return ['type' => 'author', 'id' => $author->ID, 'search_query' => ''];
            }
        }

        return null;
    }
}


PK 99