🏠 Home 

AliExpress Product Link Fixer

Enhance your AliExpress shopping experience by converting marketing links into direct product links, ensuring each product is easily accessible with a single click.


Install this script?
// ==UserScript==
// @name         AliExpress Product Link Fixer
// @namespace    http://tampermonkey.net/
// @version      2.0
// @license      MIT
// @description  Enhance your AliExpress shopping experience by converting marketing links into direct product links, ensuring each product is easily accessible with a single click.
// @author       NewsGuyTor
// @match        https://*.aliexpress.com/*
// @icon         https://www.aliexpress.com/favicon.ico
// @grant        none
// ==/UserScript==
(function() {
'use strict';
// Initialize the MutationObserver
let observer;
// Main function to fix links
function fixLinks() {
// Temporarily disconnect the observer to prevent infinite loops
if (observer) observer.disconnect();
try {
removeMarketingAnchors();
rewriteAnchorsWithProductIds();
fixOrCreateLinksForDataProducts();
} catch (err) {
console.error("[AliExpress Product Link Fixer v2] Error in fixLinks():", err);
}
// Reconnect the observer after making changes
if (observer) observer.observe(document.body, { childList: true, subtree: true });
}
/**
* A) Remove "marketing" anchors that have /gcp/ or /ssr/ without ?productIds=...
*    Then unwrap them to expose individual product blocks
*/
function removeMarketingAnchors() {
const anchors = document.querySelectorAll('a[href*="/gcp/"]:not([data-alifix-done]), a[href*="/ssr/"]:not([data-alifix-done])');
anchors.forEach(a => {
if (a.dataset.alifixDone) return; // Skip already processed anchors
const url = new URL(a.href);
if (!url.searchParams.has('productIds')) {
// Mark the anchor as processed
a.dataset.alifixDone = "1";
// Remove the anchor but keep its children in the DOM
unwrapAnchor(a);
}
});
}
/**
* B) Rewrite anchors that contain ?productIds=... to direct product pages
*/
function rewriteAnchorsWithProductIds() {
const anchors = document.querySelectorAll('a[href*="/gcp/"]:not([data-alifix-done]), a[href*="/ssr/"]:not([data-alifix-done])');
anchors.forEach(a => {
if (a.dataset.alifixDone) return; // Skip already processed anchors
const url = new URL(a.href);
const pid = url.searchParams.get('productIds');
if (pid) {
a.href = `https://${url.host}/item/${pid}.html`;
a.dataset.alifixDone = "1"; // Mark as processed
}
});
}
/**
* C) Ensure each <div data-product-ids="..."> has a clickable link
*    Either by fixing existing anchors or creating new ones
*/
function fixOrCreateLinksForDataProducts() {
const divs = document.querySelectorAll('[data-product-ids]:not([data-alifix-done])');
divs.forEach(div => {
// Mark the div as processed
div.dataset.alifixDone = "1";
const pid = div.dataset.productIds;
if (!pid) return;
// Check if there's already an <a> inside the div
const existingAnchor = div.querySelector('a[href]');
if (existingAnchor) {
if (!existingAnchor.dataset.alifixDone) {
existingAnchor.href = `https://${location.host}/item/${pid}.html`;
existingAnchor.dataset.alifixDone = "1"; // Mark as processed
}
} else {
// No anchor found, create one around the div
const link = document.createElement('a');
link.href = `https://${location.host}/item/${pid}.html`;
link.dataset.alifixDone = "1";
// Optionally, style the link to display as block to ensure full area is clickable
link.style.display = "block";
// Insert the link before the div
div.parentNode.insertBefore(link, div);
// Move the div inside the new link
link.appendChild(div);
}
});
}
/**
* Helper function to unwrap an anchor tag but keep its child elements
* @param {HTMLElement} anchor - The anchor element to unwrap
*/
function unwrapAnchor(anchor) {
const parent = anchor.parentNode;
if (!parent) return;
while (anchor.firstChild) {
parent.insertBefore(anchor.firstChild, anchor);
}
parent.removeChild(anchor);
}
// Initial execution on page load
fixLinks();
// Set up the MutationObserver to watch for dynamic content changes
observer = new MutationObserver(fixLinks);
observer.observe(document.body, { childList: true, subtree: true });
})();