{"id":5598,"date":"2026-08-25T14:31:01","date_gmt":"2026-08-25T14:31:01","guid":{"rendered":"https:\/\/yamuparkoti.com\/short-url\/"},"modified":"2026-08-25T16:17:15","modified_gmt":"2026-08-25T16:17:15","slug":"short-url","status":"publish","type":"page","link":"https:\/\/yamuparkoti.com\/de\/short-url\/","title":{"rendered":"Short URL Generator"},"content":{"rendered":"\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n<div class=\"wp-block-bplugins-custom-html\" id='bPluginsCustomHtml-1'>\n<style>\r\n    .su-wrap {\r\n        --primary: #2196F3;\r\n        --primary-dark: #1976D2;\r\n        --accent: #4CAF50;\r\n        --text: #f0f0f0;\r\n        --text-light: #b0b0b0;\r\n        --background: #17171f;\r\n        --card-bg: #1d1d26;\r\n        --border: #2a2a33;\r\n        --danger: #ef5350;\r\n        --radius: 10px;\r\n        --transition: all 0.25s ease;\r\n        background: var(--background);\r\n        color: var(--text);\r\n        font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\r\n        padding: 32px 18px 40px;\r\n        border-radius: var(--radius);\r\n        position: relative;\r\n    }\r\n    body.dark-mode .su-wrap { --background: #121212; --card-bg: #1e1e1e; --border: #333; }\r\n\r\n    .su-wrap * { box-sizing: border-box; }\r\n    .su-inner { max-width: 780px; margin: 0 auto; }\r\n\r\n    .su-head { text-align: center; margin-bottom: 26px; }\r\n    .su-head h2 {\r\n        margin: 0 0 8px; font-size: 30px; line-height: 1.25; color: var(--text); font-weight: 700;\r\n    }\r\n    .su-head p { margin: 0; color: var(--text-light); font-size: 15px; }\r\n\r\n    .su-theme-btn {\r\n        position: absolute; top: 14px; right: 14px; width: 40px; height: 40px;\r\n        border-radius: 50%; border: 1px solid var(--border); background: var(--card-bg);\r\n        color: var(--text); font-size: 17px; cursor: pointer; line-height: 1;\r\n        transition: var(--transition);\r\n    }\r\n    .su-theme-btn:hover { border-color: var(--primary); }\r\n\r\n    .su-card {\r\n        background: var(--card-bg); border: 1px solid var(--border);\r\n        border-radius: var(--radius); padding: 22px;\r\n    }\r\n\r\n    .su-label { display: block; font-size: 13px; color: var(--text-light); margin: 0 0 7px; }\r\n\r\n    .su-input, .su-short-out {\r\n        width: 100%; padding: 14px 15px; font-size: 16px;\r\n        background: var(--background); color: var(--text);\r\n        border: 1px solid var(--border); border-radius: 8px;\r\n        transition: var(--transition); font-family: inherit;\r\n    }\r\n    .su-input:focus, .su-short-out:focus {\r\n        outline: none; border-color: var(--primary); box-shadow: 0 0 0 3px rgba(33, 150, 243, 0.18);\r\n    }\r\n    .su-input::placeholder { color: #6b6b78; }\r\n\r\n    .su-btn {\r\n        display: inline-block; width: 100%; margin-top: 14px; padding: 14px 20px;\r\n        background: var(--primary); color: #fff; border: none; border-radius: 8px;\r\n        font-size: 16px; font-weight: 600; cursor: pointer; transition: var(--transition);\r\n        font-family: inherit;\r\n    }\r\n    .su-btn:hover { background: var(--primary-dark); }\r\n    .su-btn:disabled { opacity: 0.6; cursor: not-allowed; }\r\n\r\n    .su-link-btn {\r\n        background: none; border: none; color: var(--primary); font-size: 13px;\r\n        cursor: pointer; padding: 12px 0 0; font-family: inherit;\r\n    }\r\n    .su-link-btn:hover { text-decoration: underline; }\r\n\r\n    .su-custom-panel { display: none; margin-top: 10px; }\r\n    .su-preview {\r\n        margin-top: 8px; font-size: 13px; color: var(--text-light);\r\n        word-break: break-all; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\r\n    }\r\n    .su-preview-set { color: var(--accent); }\r\n\r\n    .su-hint { margin: 10px 0 0; font-size: 12px; color: var(--text-light); text-align: center; }\r\n\r\n    .su-status { display: none; margin-top: 14px; padding: 11px 14px; border-radius: 8px; font-size: 14px; }\r\n    .su-ok  { background: rgba(76, 175, 80, 0.12); color: #7dd382; border: 1px solid rgba(76, 175, 80, 0.3); }\r\n    .su-err { background: rgba(239, 83, 80, 0.12); color: #ff8a86; border: 1px solid rgba(239, 83, 80, 0.32); }\r\n\r\n    .su-result { display: none; margin-top: 18px; padding: 20px; background: var(--card-bg);\r\n                 border: 1px solid var(--primary); border-radius: var(--radius); }\r\n    .su-result-title { font-size: 13px; color: var(--text-light); margin: 0 0 9px; }\r\n    .su-short-row { display: flex; gap: 9px; flex-wrap: wrap; }\r\n    .su-short-out {\r\n        flex: 1 1 240px; font-weight: 600; color: var(--primary);\r\n        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\r\n    }\r\n    .su-action {\r\n        padding: 0 18px; border-radius: 8px; border: 1px solid var(--border);\r\n        background: var(--background); color: var(--text); font-size: 14px; font-weight: 600;\r\n        cursor: pointer; transition: var(--transition); font-family: inherit; white-space: nowrap;\r\n    }\r\n    .su-action:hover { border-color: var(--primary); color: var(--primary); }\r\n    .su-action.su-copied { background: var(--accent); border-color: var(--accent); color: #fff; }\r\n    a.su-action { display: inline-flex; align-items: center; text-decoration: none; }\r\n    .su-dest { margin-top: 11px; font-size: 13px; color: var(--text-light); word-break: break-all; }\r\n\r\n    .su-history { display: none; margin-top: 26px; }\r\n    .su-history-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 11px; }\r\n    .su-history-head h3 { margin: 0; font-size: 16px; color: var(--text); font-weight: 600; }\r\n    .su-item {\r\n        display: flex; align-items: center; gap: 11px; padding: 12px 14px;\r\n        background: var(--card-bg); border: 1px solid var(--border);\r\n        border-radius: 8px; margin-bottom: 8px;\r\n    }\r\n    .su-item-main { flex: 1 1 auto; min-width: 0; }\r\n    .su-item-short {\r\n        display: block; color: var(--primary); text-decoration: none; font-weight: 600; font-size: 14px;\r\n        font-family: ui-monospace, SFMono-Regular, Menlo, monospace;\r\n    }\r\n    .su-item-short:hover { text-decoration: underline; }\r\n    .su-item-dest {\r\n        font-size: 12px; color: var(--text-light); margin-top: 3px;\r\n        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\r\n    }\r\n    .su-item-clicks { font-size: 12px; color: var(--text-light); white-space: nowrap; }\r\n    .su-mini {\r\n        padding: 6px 11px; font-size: 12px; border-radius: 6px; cursor: pointer;\r\n        background: var(--background); color: var(--text); border: 1px solid var(--border);\r\n        transition: var(--transition); font-family: inherit;\r\n    }\r\n    .su-mini:hover { border-color: var(--primary); color: var(--primary); }\r\n    .su-mini.su-copied { background: var(--accent); border-color: var(--accent); color: #fff; }\r\n    .su-mini-x { padding: 6px 10px; font-size: 15px; line-height: 1; }\r\n    .su-mini-x:hover { border-color: var(--danger); color: var(--danger); }\r\n\r\n    .su-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-top: 26px; }\r\n    .su-fact { background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px; padding: 15px; }\r\n    .su-fact strong { display: block; color: var(--text); font-size: 14px; margin-bottom: 4px; }\r\n    .su-fact span { color: var(--text-light); font-size: 13px; line-height: 1.5; }\r\n\r\n    .su-gate { }\r\n    .su-gate h3 { margin: 0 0 6px; font-size: 18px; color: var(--text); font-weight: 600; }\r\n    .su-gate .su-gate-sub { margin: 0 0 18px; font-size: 14px; color: var(--text-light); }\r\n    .su-field { margin-bottom: 14px; }\r\n    .su-consent {\r\n        margin: 4px 0 0; font-size: 12px; line-height: 1.55; color: var(--text-light);\r\n    }\r\n    .su-consent a { color: var(--primary); }\r\n    .su-tool { display: none; }\r\n    .su-who {\r\n        display: flex; align-items: center; justify-content: space-between; gap: 10px;\r\n        flex-wrap: wrap; margin-bottom: 14px; padding: 9px 13px;\r\n        background: var(--card-bg); border: 1px solid var(--border); border-radius: 8px;\r\n        font-size: 13px; color: var(--text-light);\r\n    }\r\n    .su-who strong { color: var(--text); font-weight: 600; word-break: break-all; }\r\n\r\n    @media (max-width: 600px) {\r\n        .su-wrap { padding: 26px 13px 32px; }\r\n        .su-head h2 { font-size: 24px; }\r\n        .su-action { width: 100%; justify-content: center; padding: 12px; }\r\n        .su-item { flex-wrap: wrap; }\r\n        .su-item-main { flex: 1 1 100%; }\r\n    }\r\n<\/style>\r\n\r\n<div class=\"su-wrap\">\r\n    <button type=\"button\" class=\"su-theme-btn\" id=\"su-theme\" aria-label=\"Toggle dark mode\">\ud83c\udf19<\/button>\r\n\r\n    <div class=\"su-inner\">\r\n        <div class=\"su-head\">\r\n            <h2>Short URL Generator<\/h2>\r\n            <p>Turn a long link into a short, tidy one you can share anywhere. Free, no sign-up.<\/p>\r\n        <\/div>\r\n\r\n        <div class=\"su-card su-gate\" id=\"su-gate\">\r\n            <h3>One quick step before you shorten<\/h3>\r\n            <p class=\"su-gate-sub\">Enter your email to unlock the shortener and join the newsletter.<\/p>\r\n\r\n            <div class=\"su-field\">\r\n                <label class=\"su-label\" for=\"su-email\">Your email address<\/label>\r\n                <input type=\"email\" class=\"su-input\" id=\"su-email\" name=\"email\"\r\n                       placeholder=\"you@example.com\" autocomplete=\"email\"\r\n                       inputmode=\"email\" spellcheck=\"false\" required>\r\n            <\/div>\r\n\r\n            <input type=\"text\" id=\"su-website\" name=\"website\" tabindex=\"-1\" autocomplete=\"off\"\r\n                   aria-hidden=\"true\" style=\"position:absolute;left:-9999px;opacity:0;height:0\">\r\n\r\n            <button type=\"button\" class=\"su-btn\" id=\"su-subscribe\">Subscribe and Continue<\/button>\r\n            <p class=\"su-consent\">\r\n                We check that the address is real, then send one email asking you to confirm.\r\n                By continuing you agree to receive the newsletter, and you can unsubscribe from\r\n                any email with a single click. Your address is never sold or shared.\r\n            <\/p>\r\n            <div class=\"su-status\" id=\"su-gate-status\" role=\"status\" aria-live=\"polite\"><\/div>\r\n        <\/div>\r\n\r\n        <div class=\"su-tool\" id=\"su-tool\">\r\n            <div class=\"su-who\" id=\"su-who\">\r\n                <span>Signed in as <strong id=\"su-who-email\"><\/strong><\/span>\r\n                <button type=\"button\" class=\"su-mini\" id=\"su-signout\">Use a different email<\/button>\r\n            <\/div>\r\n\r\n        <form class=\"su-card\" id=\"su-form\">\r\n            <label class=\"su-label\" for=\"su-url\">Paste your long URL<\/label>\r\n            <input type=\"url\" class=\"su-input\" id=\"su-url\" name=\"url\"\r\n                   placeholder=\"https:\/\/example.com\/a\/very\/long\/link\" autocomplete=\"off\"\r\n                   inputmode=\"url\" spellcheck=\"false\" aria-describedby=\"su-status\">\r\n\r\n            <button type=\"button\" class=\"su-link-btn\" id=\"su-custom-toggle\" aria-expanded=\"false\"\r\n                    aria-controls=\"su-custom\">+ Use a custom alias<\/button>\r\n\r\n            <div class=\"su-custom-panel\" id=\"su-custom\">\r\n                <label class=\"su-label\" for=\"su-alias\">Custom alias (optional)<\/label>\r\n                <input type=\"text\" class=\"su-input\" id=\"su-alias\" name=\"alias\"\r\n                       placeholder=\"my-offer\" autocomplete=\"off\" spellcheck=\"false\"\r\n                       maxlength=\"32\" pattern=\"[A-Za-z0-9_-]{3,32}\">\r\n                <div class=\"su-preview\" id=\"su-preview\">yamuparkoti.com\/s\/your-alias<\/div>\r\n            <\/div>\r\n\r\n            <button type=\"submit\" class=\"su-btn\" id=\"su-go\">Shorten URL<\/button>\r\n            <p class=\"su-hint\">Free to use. Links never expire.<\/p>\r\n            <div class=\"su-status\" id=\"su-status\" role=\"status\" aria-live=\"polite\"><\/div>\r\n        <\/form>\r\n\r\n        <div class=\"su-result\" id=\"su-result\">\r\n            <p class=\"su-result-title\">Your short link<\/p>\r\n            <div class=\"su-short-row\">\r\n                <input type=\"text\" class=\"su-short-out\" id=\"su-short\" readonly>\r\n                <button type=\"button\" class=\"su-action\" id=\"su-copy\">Copy<\/button>\r\n                <a class=\"su-action\" id=\"su-open\" href=\"#\" target=\"_blank\" rel=\"noopener\">Open<\/a>\r\n            <\/div>\r\n            <div class=\"su-dest\" id=\"su-dest\"><\/div>\r\n        <\/div>\r\n\r\n        <div class=\"su-history\" id=\"su-history\">\r\n            <div class=\"su-history-head\">\r\n                <h3>Your links<\/h3>\r\n                <button type=\"button\" class=\"su-mini\" id=\"su-clear\">Clear list<\/button>\r\n            <\/div>\r\n            <div id=\"su-list\"><\/div>\r\n            <\/div>\r\n        <\/div>\r\n\r\n        <div class=\"su-facts\">\r\n            <div class=\"su-fact\">\r\n                <strong>Links never expire<\/strong>\r\n                <span>Once created, a short link keeps working. There is no time limit and no account needed.<\/span>\r\n            <\/div>\r\n            <div class=\"su-fact\">\r\n                <strong>Custom aliases<\/strong>\r\n                <span>Choose your own ending, so a link can read as a name instead of random characters.<\/span>\r\n            <\/div>\r\n            <div class=\"su-fact\">\r\n                <strong>Click counts<\/strong>\r\n                <span>Every link tracks how many times it was opened. Totals only, no visitor tracking.<\/span>\r\n            <\/div>\r\n        <\/div>\r\n    <\/div>\r\n<\/div>\n\n<script>\n(function () {\r\n    'use strict';\r\n\r\n    \/\/ NOTE FOR FUTURE EDITS: this site's render filter rewrites a bare ampersand into a\r\n    \/\/ numeric HTML entity, and entities are NOT decoded inside a script element. One literal\r\n    \/\/ ampersand here is a fatal SyntaxError that kills the whole tool. The corruption is\r\n    \/\/ inconsistent - some survive, some do not - so never rely on \"that one worked\".\r\n    \/\/ Never use the AND operator in this file. Use nested ifs or Array.every. OR is safe.\r\n\r\n    var API = '\/wp-json\/yam\/v1';\r\n    \/\/ The site's own newsletter, already live on every page. It owns the mailing list\r\n    \/\/ and runs its own double opt-in, so the gate feeds it rather than duplicating it.\r\n    var NEWSLETTER = '\/wp-json\/yam\/v1\/subscribe';\r\n    var STORE = 'yam-su-links';\r\n    var IDENT = 'yam-su-ident';\r\n    var MAX_STORED = 25;\r\n\r\n    var $ = function (id) { return document.getElementById(id); };\r\n\r\n    \/* ------------------------------------------------------------ storage *\/\r\n\r\n    function load() {\r\n        try {\r\n            var raw = localStorage.getItem(STORE);\r\n            if (!raw) { return []; }\r\n            var list = JSON.parse(raw);\r\n            return Object.prototype.toString.call(list) === '[object Array]' ? list : [];\r\n        } catch (e) { return []; }\r\n    }\r\n\r\n    function save(list) {\r\n        try { localStorage.setItem(STORE, JSON.stringify(list.slice(0, MAX_STORED))); } catch (e) {}\r\n    }\r\n\r\n    function remember(rec) {\r\n        var list = load().filter(function (r) { return r.code !== rec.code; });\r\n        list.unshift(rec);\r\n        save(list);\r\n        renderList();\r\n    }\r\n\r\n    \/* ------------------------------------------------------------- identity *\/\r\n    \/\/ The email gate. A visitor identifies themselves once, the server hands back a token,\r\n    \/\/ and that token is what unlocks link creation from then on in this browser.\r\n\r\n    function loadIdent() {\r\n        try {\r\n            var raw = localStorage.getItem(IDENT);\r\n            if (!raw) { return null; }\r\n            var o = JSON.parse(raw);\r\n            if (!o) { return null; }\r\n            return o.token ? o : null;\r\n        } catch (e) { return null; }\r\n    }\r\n\r\n    function saveIdent(o) {\r\n        try { localStorage.setItem(IDENT, JSON.stringify(o)); } catch (e) {}\r\n    }\r\n\r\n    function clearIdent() {\r\n        try { localStorage.removeItem(IDENT); } catch (e) {}\r\n    }\r\n\r\n    function applyIdentity() {\r\n        var ident = loadIdent();\r\n        var gate = $('su-gate');\r\n        var tool = $('su-tool');\r\n        var who = $('su-who-email');\r\n        if (ident) {\r\n            if (gate) { gate.style.display = 'none'; }\r\n            if (tool) { tool.style.display = 'block'; }\r\n            if (who) { who.textContent = ident.email || ''; }\r\n        } else {\r\n            if (gate) { gate.style.display = 'block'; }\r\n            if (tool) { tool.style.display = 'none'; }\r\n        }\r\n        return ident;\r\n    }\r\n\r\n    function setGateStatus(msg, kind) {\r\n        var box = $('su-gate-status');\r\n        if (!box) { return; }\r\n        box.textContent = msg || '';\r\n        box.className = 'su-status' + (kind ? ' su-' + kind : '');\r\n        box.style.display = msg ? 'block' : 'none';\r\n    }\r\n\r\n    function subscribe() {\r\n        var emailField = $('su-email');\r\n        var btn = $('su-subscribe');\r\n        var hpField = $('su-website');\r\n        var email = emailField ? emailField.value.trim() : '';\r\n        var hp = hpField ? hpField.value : '';\r\n\r\n        if (!email) {\r\n            setGateStatus('Please enter your email address.', 'err');\r\n            if (emailField) { emailField.focus(); }\r\n            return;\r\n        }\r\n\r\n        if (btn) { btn.disabled = true; btn.textContent = 'Checking your email...'; }\r\n        setGateStatus('');\r\n\r\n        \/\/ Step 1: our own check. Stricter than the newsletter form (it verifies the domain\r\n        \/\/ actually accepts mail), so a typo never reaches the mailing list.\r\n        fetch(API + '\/linkgate', {\r\n            method: 'POST',\r\n            headers: { 'Content-Type': 'application\/json' },\r\n            body: JSON.stringify({ email: email })\r\n        }).then(function (r) {\r\n            return r.json().then(function (j) { return { ok: r.ok, status: r.status, data: j }; });\r\n        }).then(function (res) {\r\n            if (!res.ok) {\r\n                if (btn) { btn.disabled = false; btn.textContent = 'Subscribe and Continue'; }\r\n                var msg = res.data ? res.data.message : '';\r\n                if (!msg) { msg = 'Something went wrong (HTTP ' + res.status + ').'; }\r\n                if (res.status === 404) {\r\n                    msg = 'The service is not responding. If you are the site owner, check that the Yam Short Links plugin is active.';\r\n                }\r\n                setGateStatus(msg, 'err');\r\n                return null;\r\n            }\r\n            return res.data;\r\n        }).then(function (gate) {\r\n            if (!gate) { return; }\r\n\r\n            \/\/ Step 2: hand the address to the site newsletter, which sends its own\r\n            \/\/ confirmation. A returning visitor is not re-subscribed.\r\n            var after = function (newsMsg) {\r\n                if (btn) { btn.disabled = false; btn.textContent = 'Subscribe and Continue'; }\r\n                saveIdent({ token: gate.token, email: gate.email });\r\n                applyIdentity();\r\n                renderList();\r\n                refreshClicks();\r\n                setStatus(newsMsg || 'You are all set. You can shorten links below.', 'ok');\r\n                var url = $('su-url');\r\n                if (url) { url.focus(); }\r\n            };\r\n\r\n            if (gate.returning) { after('Welcome back. You can shorten links below.'); return; }\r\n\r\n            fetch(NEWSLETTER, {\r\n                method: 'POST',\r\n                headers: { 'Content-Type': 'application\/json' },\r\n                body: JSON.stringify({ email: gate.email, website: hp })\r\n            }).then(function (r) { return r.json(); })\r\n              .then(function (j) {\r\n                  var m = (j) ? j.msg : '';\r\n                  after(m || 'You are all set. You can shorten links below.');\r\n              })\r\n              \/\/ The newsletter failing must never lock someone out of the tool.\r\n              .catch(function () { after('You are all set. You can shorten links below.'); });\r\n        }).catch(function () {\r\n            if (btn) { btn.disabled = false; btn.textContent = 'Subscribe and Continue'; }\r\n            setGateStatus('Could not reach the server. Please check your connection and try again.', 'err');\r\n        });\r\n    }\r\n\r\n    \/* -------------------------------------------------------------- helpers *\/\r\n\r\n    function setStatus(msg, kind) {\r\n        var box = $('su-status');\r\n        if (!box) { return; }\r\n        box.textContent = msg || '';\r\n        box.className = 'su-status' + (kind ? ' su-' + kind : '');\r\n        box.style.display = msg ? 'block' : 'none';\r\n    }\r\n\r\n    function busy(on) {\r\n        var btn = $('su-go');\r\n        if (!btn) { return; }\r\n        btn.disabled = on;\r\n        btn.textContent = on ? 'Shortening...' : 'Shorten URL';\r\n    }\r\n\r\n    function copy(text, btn) {\r\n        var done = function () {\r\n            if (!btn) { return; }\r\n            var old = btn.textContent;\r\n            btn.textContent = 'Copied';\r\n            btn.classList.add('su-copied');\r\n            setTimeout(function () { btn.textContent = old; btn.classList.remove('su-copied'); }, 1600);\r\n        };\r\n        if (navigator.clipboard) {\r\n            navigator.clipboard.writeText(text).then(done, function () { fallbackCopy(text, done); });\r\n        } else {\r\n            fallbackCopy(text, done);\r\n        }\r\n    }\r\n\r\n    function fallbackCopy(text, done) {\r\n        var ta = document.createElement('textarea');\r\n        ta.value = text;\r\n        ta.setAttribute('readonly', '');\r\n        ta.style.position = 'fixed';\r\n        ta.style.left = '-9999px';\r\n        document.body.appendChild(ta);\r\n        ta.select();\r\n        try { document.execCommand('copy'); done(); } catch (e) {}\r\n        document.body.removeChild(ta);\r\n    }\r\n\r\n    function shortHost() {\r\n        return location.host + '\/s\/';\r\n    }\r\n\r\n    \/* --------------------------------------------------------------- create *\/\r\n\r\n    function shorten() {\r\n        var urlField = $('su-url');\r\n        var aliasField = $('su-alias');\r\n        var url = urlField ? urlField.value.trim() : '';\r\n        var alias = aliasField ? aliasField.value.trim() : '';\r\n\r\n        if (!url) {\r\n            setStatus('Please paste a link first.', 'err');\r\n            if (urlField) { urlField.focus(); }\r\n            return;\r\n        }\r\n\r\n        \/\/ Check identity BEFORE flipping the button into its busy state, or this early\r\n        \/\/ return leaves it stuck reading \"Shortening...\" forever.\r\n        var ident = loadIdent();\r\n        if (!ident) {\r\n            applyIdentity();\r\n            setGateStatus('Please enter your email address to continue.', 'err');\r\n            return;\r\n        }\r\n\r\n        busy(true);\r\n        setStatus('');\r\n\r\n        var body = { url: url, token: ident.token };\r\n        if (alias) { body.alias = alias; }\r\n\r\n        fetch(API + '\/shorten', {\r\n            method: 'POST',\r\n            headers: { 'Content-Type': 'application\/json' },\r\n            body: JSON.stringify(body)\r\n        }).then(function (r) {\r\n            return r.json().then(function (j) { return { ok: r.ok, status: r.status, data: j }; });\r\n        }).then(function (res) {\r\n            busy(false);\r\n            if (!res.ok) {\r\n                var msg = res.data ? res.data.message : '';\r\n                if (!msg) { msg = 'Something went wrong (HTTP ' + res.status + ').'; }\r\n                if (res.status === 404) {\r\n                    msg = 'The shortener service is not responding. If you are the site owner, check that the Yam Short Links plugin is active.';\r\n                }\r\n                \/\/ Token no longer recognised, e.g. the subscriber row was removed.\r\n                if (res.status === 401) {\r\n                    clearIdent();\r\n                    applyIdentity();\r\n                    setStatus('');\r\n                    setGateStatus(msg, 'err');\r\n                    return;\r\n                }\r\n                setStatus(msg, 'err');\r\n                return;\r\n            }\r\n            showResult(res.data);\r\n            remember({\r\n                code: res.data.code, short_url: res.data.short_url,\r\n                url: res.data.url, created: Date.now(), clicks: res.data.clicks || 0\r\n            });\r\n            setStatus(res.data.reused\r\n                ? 'You had already shortened this link, so here is the same short URL.'\r\n                : 'Short link created.', 'ok');\r\n            if (aliasField) { aliasField.value = ''; }\r\n        }).catch(function () {\r\n            busy(false);\r\n            setStatus('Could not reach the server. Please check your connection and try again.', 'err');\r\n        });\r\n    }\r\n\r\n    function showResult(data) {\r\n        var box = $('su-result');\r\n        if (!box) { return; }\r\n        var out = $('su-short');\r\n        if (out) {\r\n            out.value = data.short_url;\r\n            out.setAttribute('aria-label', 'Your short link: ' + data.short_url);\r\n        }\r\n        var dest = $('su-dest');\r\n        if (dest) {\r\n            dest.textContent = data.url;\r\n            dest.setAttribute('title', data.url);\r\n        }\r\n        var open = $('su-open');\r\n        if (open) { open.href = data.short_url; }\r\n        box.style.display = 'block';\r\n        box.setAttribute('aria-live', 'polite');\r\n    }\r\n\r\n    \/* ---------------------------------------------------------- saved links *\/\r\n\r\n    function renderList() {\r\n        var host = $('su-list');\r\n        var wrap = $('su-history');\r\n        if (!host) { return; }\r\n        var list = load();\r\n        if (wrap) { wrap.style.display = list.length ? 'block' : 'none'; }\r\n        host.innerHTML = '';\r\n\r\n        list.forEach(function (rec) {\r\n            var row = document.createElement('div');\r\n            row.className = 'su-item';\r\n\r\n            var main = document.createElement('div');\r\n            main.className = 'su-item-main';\r\n\r\n            var a = document.createElement('a');\r\n            a.className = 'su-item-short';\r\n            a.href = rec.short_url;\r\n            a.target = '_blank';\r\n            a.rel = 'noopener';\r\n            a.textContent = rec.short_url.replace(\/^https?:\\\/\\\/\/, '');\r\n            main.appendChild(a);\r\n\r\n            var dest = document.createElement('div');\r\n            dest.className = 'su-item-dest';\r\n            \/\/ textContent, never innerHTML: the destination is attacker-controlled text.\r\n            dest.textContent = rec.url;\r\n            dest.title = rec.url;\r\n            main.appendChild(dest);\r\n            row.appendChild(main);\r\n\r\n            var clicks = document.createElement('span');\r\n            clicks.className = 'su-item-clicks';\r\n            clicks.setAttribute('data-code', rec.code);\r\n            clicks.textContent = (rec.clicks || 0) + ' clicks';\r\n            row.appendChild(clicks);\r\n\r\n            var cp = document.createElement('button');\r\n            cp.type = 'button';\r\n            cp.className = 'su-mini';\r\n            cp.textContent = 'Copy';\r\n            cp.addEventListener('click', function () { copy(rec.short_url, cp); });\r\n            row.appendChild(cp);\r\n\r\n            var rm = document.createElement('button');\r\n            rm.type = 'button';\r\n            rm.className = 'su-mini su-mini-x';\r\n            rm.textContent = '\u00d7';\r\n            rm.setAttribute('aria-label', 'Remove ' + rec.short_url + ' from this list');\r\n            rm.addEventListener('click', function () {\r\n                save(load().filter(function (r) { return r.code !== rec.code; }));\r\n                renderList();\r\n            });\r\n            row.appendChild(rm);\r\n\r\n            host.appendChild(row);\r\n        });\r\n    }\r\n\r\n    \/\/ Click counts are per-link, so refresh them lazily rather than on every keystroke.\r\n    function refreshClicks() {\r\n        var list = load();\r\n        if (!list.length) { return; }\r\n        list.slice(0, 10).forEach(function (rec) {\r\n            fetch(API + '\/stats?code=' + encodeURIComponent(rec.code))\r\n                .then(function (r) { return r.ok ? r.json() : null; })\r\n                .then(function (j) {\r\n                    if (!j) { return; }\r\n                    var node = document.querySelector('.su-item-clicks[data-code=\"' + rec.code + '\"]');\r\n                    if (node) { node.textContent = j.clicks + (j.clicks === 1 ? ' click' : ' clicks'); }\r\n                    var stored = load();\r\n                    stored.forEach(function (s) { if (s.code === rec.code) { s.clicks = j.clicks; } });\r\n                    save(stored);\r\n                })\r\n                .catch(function () {});\r\n        });\r\n    }\r\n\r\n    \/* ------------------------------------------------------------------ init *\/\r\n\r\n    function init() {\r\n        var go = $('su-go');\r\n        if (go) { go.addEventListener('click', shorten); }\r\n\r\n        var form = $('su-form');\r\n        if (form) { form.addEventListener('submit', function (e) { e.preventDefault(); shorten(); }); }\r\n\r\n        var url = $('su-url');\r\n        if (url) {\r\n            url.addEventListener('keydown', function (e) {\r\n                if (e.key === 'Enter') { e.preventDefault(); shorten(); }\r\n            });\r\n        }\r\n\r\n        var toggle = $('su-custom-toggle');\r\n        var panel = $('su-custom');\r\n        if (toggle) {\r\n            if (panel) {\r\n                toggle.addEventListener('click', function () {\r\n                    var open = panel.style.display === 'block';\r\n                    panel.style.display = open ? 'none' : 'block';\r\n                    toggle.setAttribute('aria-expanded', open ? 'false' : 'true');\r\n                    toggle.textContent = open ? '+ Use a custom alias' : '\u2212 Use a custom alias';\r\n                    if (!open) { var a = $('su-alias'); if (a) { a.focus(); } }\r\n                });\r\n            }\r\n        }\r\n\r\n        var alias = $('su-alias');\r\n        var preview = $('su-preview');\r\n        if (alias) {\r\n            if (preview) {\r\n                var paint = function () {\r\n                    var v = alias.value.trim();\r\n                    preview.textContent = shortHost() + (v || 'your-alias');\r\n                    preview.classList.toggle('su-preview-set', !!v);\r\n                };\r\n                alias.addEventListener('input', paint);\r\n                paint();\r\n            }\r\n        }\r\n\r\n        var cp = $('su-copy');\r\n        if (cp) {\r\n            cp.addEventListener('click', function () {\r\n                var out = $('su-short');\r\n                if (out) { copy(out.value, cp); }\r\n            });\r\n        }\r\n\r\n        var out = $('su-short');\r\n        if (out) { out.addEventListener('focus', function () { out.select(); }); }\r\n\r\n        var clear = $('su-clear');\r\n        if (clear) {\r\n            clear.addEventListener('click', function () {\r\n                if (window.confirm('Clear your saved links from this browser? The short links themselves keep working.')) {\r\n                    save([]);\r\n                    renderList();\r\n                }\r\n            });\r\n        }\r\n\r\n        var dark = $('su-theme');\r\n        if (dark) {\r\n            var saved = null;\r\n            try { saved = localStorage.getItem('su-theme'); } catch (e) { saved = null; }\r\n            if (saved === 'light') { document.body.classList.remove('dark-mode'); }\r\n            if (saved === 'dark') { document.body.classList.add('dark-mode'); }\r\n            dark.textContent = document.body.classList.contains('dark-mode') ? '\u2600\ufe0f' : '\ud83c\udf19';\r\n            dark.setAttribute('aria-label', 'Toggle dark mode');\r\n            dark.addEventListener('click', function () {\r\n                document.body.classList.toggle('dark-mode');\r\n                var on = document.body.classList.contains('dark-mode');\r\n                dark.textContent = on ? '\u2600\ufe0f' : '\ud83c\udf19';\r\n                try { localStorage.setItem('su-theme', on ? 'dark' : 'light'); } catch (e) {}\r\n            });\r\n        }\r\n\r\n        var sub = $('su-subscribe');\r\n        if (sub) { sub.addEventListener('click', subscribe); }\r\n\r\n        var emailField = $('su-email');\r\n        if (emailField) {\r\n            emailField.addEventListener('keydown', function (e) {\r\n                if (e.key === 'Enter') { e.preventDefault(); subscribe(); }\r\n            });\r\n        }\r\n\r\n        var signout = $('su-signout');\r\n        if (signout) {\r\n            signout.addEventListener('click', function () {\r\n                clearIdent();\r\n                applyIdentity();\r\n                setStatus('');\r\n                setGateStatus('');\r\n                var f = $('su-email');\r\n                if (f) { f.value = ''; f.focus(); }\r\n            });\r\n        }\r\n\r\n        applyIdentity();\r\n        renderList();\r\n        refreshClicks();\r\n    }\r\n\r\n    \/\/ Never assume DOMContentLoaded has not fired yet: if anything defers or relocates this\r\n    \/\/ script that assumption silently leaves every control unwired.\r\n    if (document.readyState === 'loading') {\r\n        document.addEventListener('DOMContentLoaded', init);\r\n    } else {\r\n        init();\r\n    }\r\n})();\r\n<\/script><\/div>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">What this URL shortener does<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">A long web address is awkward to share. It wraps onto two lines in a message, it gets cut off in a social media bio, and it is impossible to read aloud or type from a printed page. This tool takes any http or https link and gives you a short one in its place, in the form <code>yamuparkoti.com\/s\/ab12cd<\/code>. Open the short link and it forwards straight to the original address.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The short links are hosted here on yamuparkoti.com rather than on a third-party service. That means they do not stop working if some other company changes its pricing or shuts down, and there is no account to create and nothing to pay.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How to shorten a link<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before your first link, the tool asks for your email address. This does two things: it keeps automated spam off the service, and it subscribes you to the newsletter. We check the address is real and send one confirmation email. You only do this once per browser, and you can unsubscribe from any email with a single click.<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Enter your email address and press <strong>Subscribe and Continue<\/strong>. This is asked once.<\/li>\n\n\n<li>Paste the full address into the box. If you leave off the <code>https:\/\/<\/code> it will be added for you.<\/li>\n\n\n<li>If you want the link to read as a word rather than random characters, open <strong>Use a custom alias<\/strong> and type one.<\/li>\n\n\n<li>Press <strong>Shorten URL<\/strong>. Your short link appears straight away with a Copy button next to it.<\/li>\n\n\n<li>Paste it wherever you need it. It stays saved in the list on this page so you can find it again.<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Custom aliases<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">By default the tool picks a random six-character code. A custom alias lets you replace that with something meaningful, so <code>yamuparkoti.com\/s\/spring-sale<\/code> is possible instead of <code>yamuparkoti.com\/s\/k7Rp2x<\/code>. An alias can be 3 to 32 characters long and may contain letters, numbers, hyphens and underscores.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Aliases are first come, first served: if somebody has already taken the one you want, the tool tells you and you can pick another. Random codes avoid the characters that are easy to misread, so there is no letter O next to a zero, and no capital I next to a lowercase L.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Where short links are worth using<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Social media bios<\/strong> where you only get one link and very little space.<\/li>\n\n\n<li><strong>Printed material and slides<\/strong>, where somebody has to read the address and type it by hand.<\/li>\n\n\n<li><strong>Text messages<\/strong>, where a long URL eats the character limit.<\/li>\n\n\n<li><strong>QR codes<\/strong>, because a shorter address makes a simpler, more reliable code. You can generate one with the <a href=\"https:\/\/yamuparkoti.com\/qr-code-generator-free-online\/\">QR Code Generator<\/a>.<\/li>\n\n\n<li><strong>Measuring interest<\/strong>, since every short link counts how many times it was opened.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">About the click counter<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Each short link keeps a running total of how many times it has been opened, shown next to the link in your list. It is a plain count and nothing more. No cookies are set on the person clicking, no profile is built, and no visitor details are stored against a click.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The list of links on this page is kept in your own browser storage, not in an account. Clearing your browser data will empty that list, but the short links themselves keep working for everybody who has them.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Frequently asked questions<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Is it free?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes, completely. There is no account to create, no trial and no payment. All that is asked is a working email address, which also signs you up to the newsletter. To keep automated abuse out there is a generous cap of 15 new links an hour and 60 a day per visitor. That applies only to creating links: the links themselves never expire, and there is no limit on how many times one can be clicked.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What happens if I hit the limit?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The tool says so and asks you to try again a little later. Every link you have already made carries on working normally in the meantime. The caps are set high enough that ordinary use will not reach them.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Why do you ask for my email?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Two reasons, and it is fair to state both. It keeps automated abuse off a free public tool, and it is how the newsletter list is built. The address is checked for a working mail domain, so a made-up one will not get through. Nothing is sold or shared, every email carries an unsubscribe link, and unsubscribing does not stop you using the shortener.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Do the short links expire?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. A link works until it is deliberately removed. Removing a link from the list on this page only hides it from your own view; it does not disable the link.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can I shorten a link that is already short?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The tool will not shorten a link that already points at another shortener, or at a short link on this site. Chaining redirects together makes links slower and less trustworthy, so paste the original destination instead.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What kinds of links are allowed?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Ordinary web addresses beginning with http or https. Anything else is refused, including scripts and local addresses. Shortening the same URL twice gives you the same short link back rather than creating a duplicate.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Will the short link change my destination page?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">No. The short link issues a permanent redirect to exactly the address you gave, with nothing appended and no interstitial page in between. Anyone who clicks it lands on your page directly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can I see how many people clicked?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes, the count sits beside each link in your list on this page and updates when you reload. It counts openings of the short link, so repeat visits from the same person are all counted.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">More free tools<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If this was useful, these might be too: the <a href=\"https:\/\/yamuparkoti.com\/qr-code-generator-free-online\/\">QR Code Generator<\/a> turns your new short link into a scannable code, the <a href=\"https:\/\/yamuparkoti.com\/jpeg-pdf-dual-converter\/\">JPEG PDF Converter<\/a> moves files between images and PDFs, the <a href=\"https:\/\/yamuparkoti.com\/date-calculator-pro\/\">Date Calculator Pro<\/a> works out ages and working days, and the <a href=\"https:\/\/yamuparkoti.com\/word-count-checker\/\">Word Count Checker<\/a> counts words and characters.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Free URL shortener. Turn any long link into a short yamuparkoti.com\/s\/ address, pick your own custom alias, and see how many times it was clicked. No sign-up, no expiry.<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"_kadence_starter_templates_imported_post":false,"footnotes":""},"class_list":["post-5598","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/pages\/5598","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/comments?post=5598"}],"version-history":[{"count":5,"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/pages\/5598\/revisions"}],"predecessor-version":[{"id":5607,"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/pages\/5598\/revisions\/5607"}],"wp:attachment":[{"href":"https:\/\/yamuparkoti.com\/de\/wp-json\/wp\/v2\/media?parent=5598"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}