You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

外部链接自动转联盟链接的代码失效问题排查

问题描述

我需要在产品数据解析完成后,自动为来自example.com或其他广告主的产品URL添加联盟链接。我已在以下代码中实现相关逻辑:检测产品URL是否包含example.com,若是则生成追踪链接,并注册用于联盟链接转换的JavaScript脚本,但目前联盟链接并未成功转换,恳请协助排查问题。

<?php

namespace ExternalImporter\application\libs\pextractor\parser\parsers;

use ExternalImporter\application\libs\pextractor\parser\AdvancedParser;
use ExternalImporter\application\libs\pextractor\parser\Product;

class ExampleAdvanced extends AdvancedParser
{
    public function getHttpOptions()
    {
        $user_agent = array('ia_archiver');

        return array('user-agent' => $user_agent[array_rand($user_agent)]);
    }

    public function parseLinks()
    {
        $path = array(
            ".//a[@class='product__title a']/@href",
        );

        return $this->xpathArray($path);
    }

    public function parseTitle()
    {
        return $this->xpathScalar(".//h1[@class='product__title']") . ' ' . $this->xpathScalar(".//h2[@class='product-details__description inherit-font-styles']");
    }

    public function parseDescription()
    {
        $d = $this->xpathScalar(".//div[@id='tab6']", true);
        return preg_replace('~<div class="product-number text-uppercase">.+?</div>~ims', '', $d);
    }

    public function afterParseFix(Product $product)
    {
        // Replace image URLs
        $product->image = str_replace(',w_520,h_520,', ',w_1800,h_1800,', $product->image);
        foreach ($product->images as $k => $img)
        {
            $product->images[$k] = str_replace(',w_520,h_520,', ',w_1800,h_1800,', $img);
        }

        // Import images to the WooCommerce product gallery
        $this->importImageToProductGallery($product->id, $product->image);
        foreach ($product->images as $img)
        {
            $this->importImageToProductGallery($product->id, $img);
        }

        // Update the product URL to the affiliate link only for example.com
        if (strpos($product->url, 'example.com') !== false) {
            $product->url = $this->generateTrackingLink($product->url);

            // Enqueue the JavaScript for affiliate link conversion
            add_action('wp_footer', function () use ($product) {
                $this->addAffiliateJavascript($product->url);
            });
        }

        return $product;
    }

    protected function importImageToProductGallery($productId, $imageUrl)
    {
        // Download the image to a temporary file (use wp_remote_get for WordPress)
        $response = wp_remote_get($imageUrl);
        $tempFilePath = wp_tempnam($imageUrl);
        if (is_wp_error($response) || !is_wp_error($tempFilePath)) {
            // Handle the error, log it, etc.
            return;
        }

        // Get the file name from the URL
        $filename = basename($imageUrl);

        // Prepare the image data for WooCommerce
        $imageData = [
            'name' => $filename,
            'post_title' => $filename,
            'post_content' => '',
            'post_status' => 'inherit',
        ];

        // Create an attachment from the temporary file and add it to the product gallery
        $attachmentId = wp_insert_attachment($imageData, $tempFilePath, $productId);
        if (!is_wp_error($attachmentId)) {
            require_once(ABSPATH . 'wp-admin/includes/image.php');
            $attachmentData = wp_generate_attachment_metadata($attachmentId, $tempFilePath);
            wp_update_attachment_metadata($attachmentId, $attachmentData);

            // Add the image to the product gallery
            add_post_meta($productId, '_product_image_gallery', $attachmentId, false);
        }

        // Clean up the temporary file
        unlink($tempFilePath);

        // Add any additional processing or linking logic as needed
    }

    protected function addAffiliateJavascript($productUrl)
    {
        ?>
        <script>
            jQuery(document).ready(function($) {
                // Attach a click event to all <a> elements
                $("a").click(function() {
                    // Check if the link is from example.com
                    if ($(this).attr('href').indexOf('example.com') >= 0) {
                        // Check if the link already contains the affiliate parameters
                        if ($(this).attr('href').indexOf('id=a0s*vOA3SnI') < 0) {
                            // Update the link with the affiliate parameters
                            $(this).attr('href', function(_, currentHref) {
                                return currentHref +
                                    (currentHref.includes('?') ? '&' : '?') +
                                    'id=a0s*vOA3SnI&mid=50238&murl=' +
                                    encodeURIComponent(currentHref);
                            });
                        }
                    }
                    // Return true to follow the link
                    return true;
                });
            });
        </script>
        <?php
    }
}
问题排查与修复方案

核心问题拆解

你的代码存在多个逻辑漏洞,直接导致联盟链接转换失败:

  • PHP端核心方法缺失:调用了generateTrackingLink但未实现,PHP层面无法生成有效追踪链接
  • JS事件绑定失效:ready绑定的点击事件无法覆盖动态加载的链接(比如WooCommerce后期渲染的按钮)
  • URL判断逻辑粗糙:直接用attr('href')可能获取不到有效路径,indexOf判断容易遗漏相对路径、跨域链接
  • 钩子重复注册:每次解析产品都会添加wp_footer钩子,导致页面加载多份相同JS,引发冲突
  • 图片导入逻辑错误:wp_remote_get结果判断颠倒,未将下载内容写入临时文件,图库追加逻辑会覆盖原有图片

修复后的完整代码

<?php

namespace ExternalImporter\application\libs\pextractor\parser\parsers;

use ExternalImporter\application\libs\pextractor\parser\AdvancedParser;
use ExternalImporter\application\libs\pextractor\parser\Product;

class ExampleAdvanced extends AdvancedParser
{
    public function getHttpOptions()
    {
        $user_agent = array('ia_archiver');

        return array('user-agent' => $user_agent[array_rand($user_agent)]);
    }

    public function parseLinks()
    {
        $path = array(
            ".//a[@class='product__title a']/@href",
        );

        return $this->xpathArray($path);
    }

    public function parseTitle()
    {
        return $this->xpathScalar(".//h1[@class='product__title']") . ' ' . $this->xpathScalar(".//h2[@class='product-details__description inherit-font-styles']");
    }

    public function parseDescription()
    {
        $d = $this->xpathScalar(".//div[@id='tab6']", true);
        return preg_replace('~<div class="product-number text-uppercase">.+?</div>~ims', '', $d);
    }

    public function afterParseFix(Product $product)
    {
        // 替换图片URL尺寸
        $product->image = str_replace(',w_520,h_520,', ',w_1800,h_1800,', $product->image);
        foreach ($product->images as $k => $img)
        {
            $product->images[$k] = str_replace(',w_520,h_520,', ',w_1800,h_1800,', $img);
        }

        // 导入图片到WooCommerce产品图库
        $this->importImageToProductGallery($product->id, $product->image);
        foreach ($product->images as $img)
        {
            $this->importImageToProductGallery($product->id, $img);
        }

        // 仅为example.com的产品URL生成联盟链接
        if (strpos($product->url, 'example.com') !== false) {
            $product->url = $this->generateTrackingLink($product->url);
        }

        // 全局注册一次JS转换脚本(避免重复注册)
        if (!has_action('wp_footer', [$this, 'addAffiliateJavascript'])) {
            add_action('wp_footer', [$this, 'addAffiliateJavascript']);
        }

        return $product;
    }

    // 实现缺失的联盟链接生成方法
    protected function generateTrackingLink($originalUrl)
    {
        $affiliateParams = [
            'id' => 'a0s*vOA3SnI',
            'mid' => '50238',
            'murl' => urlencode($originalUrl)
        ];

        $separator = strpos($originalUrl, '?') !== false ? '&' : '?';
        return $originalUrl . $separator . http_build_query($affiliateParams);
    }

    protected function importImageToProductGallery($productId, $imageUrl)
    {
        // 下载图片到临时文件
        $response = wp_remote_get($imageUrl);
        if (is_wp_error($response)) {
            return;
        }

        $tempFilePath = wp_tempnam($imageUrl);
        if (is_wp_error($tempFilePath)) {
            return;
        }

        // 将下载的内容写入临时文件
        file_put_contents($tempFilePath, wp_remote_retrieve_body($response));

        // 获取文件名
        $filename = basename($imageUrl);

        // 准备图片附件数据
        $imageData = [
            'name' => $filename,
            'post_title' => $filename,
            'post_content' => '',
            'post_status' => 'inherit',
        ];

        // 创建附件并添加到产品图库
        $attachmentId = wp_insert_attachment($imageData, $tempFilePath, $productId);
        if (!is_wp_error($attachmentId)) {
            require_once(ABSPATH . 'wp-admin/includes/image.php');
            $attachmentData = wp_generate_attachment_metadata($attachmentId, $tempFilePath);
            wp_update_attachment_metadata($attachmentId, $attachmentData);

            // 追加到产品图库(避免覆盖原有图库)
            $existingGallery = get_post_meta($productId, '_product_image_gallery', true);
            $newGallery = $existingGallery ? $existingGallery . ',' . $attachmentId : $attachmentId;
            update_post_meta($productId, '_product_image_gallery', $newGallery);
        }

        // 清理临时文件
        unlink($tempFilePath);
    }

    protected function addAffiliateJavascript()
    {
        ?>
        <script>
            jQuery(document).on('click', 'a', function(e) {
                let href = $(this).attr('href');
                if (!href) return true;

                // 处理相对路径转为绝对URL
                let urlObj = new URL(href, window.location.origin);
                let fullUrl = urlObj.href;

                // 检查是否为example.com链接且未包含联盟参数
                if (fullUrl.includes('example.com') && !fullUrl.includes('id=a0s*vOA3SnI')) {
                    // 生成联盟链接
                    let separator = fullUrl.includes('?') ? '&' : '?';
                    let affiliateParams = 'id=a0s*vOA3SnI&mid=50238&murl=' + encodeURIComponent(fullUrl);
                    $(this).attr('href', fullUrl + separator + affiliateParams);
                }
                return true;
            });
        </script>
        <?php
    }
}

关键修复说明

  1. 补全generateTrackingLink方法:PHP端直接生成正确的联盟链接,确保产品初始URL就是追踪链接
  2. 优化JS事件绑定:改用事件委托jQuery(document).on('click', 'a', ...),覆盖所有动态生成的链接
  3. 完善URL处理:使用URL对象解析链接,解决相对路径、跨域链接的判断问题
  4. 避免重复注册钩子:通过has_action判断,确保JS脚本只加载一次
  5. 修复图片导入逻辑:修正wp_remote_get结果判断,添加文件写入步骤,优化图库追加逻辑避免覆盖原有图片

内容的提问来源于stack exchange,提问作者Huda

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 20:04:52