# post-carousel/4.0.8/src/saved-template-sidebar/index.js

Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog &amp; News, version 4.0.8. 165 lines.

- Page: https://pluginprobe.com/plugins/post-carousel/4.0.8/code/src/saved-template-sidebar/index.js
- Raw: https://pluginprobe.com/plugins/post-carousel/4.0.8/raw/src/saved-template-sidebar/index.js
- Modified: 2026-09-02T10:51:28+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/post-carousel/4.0.8/code/src/saved-template-sidebar/index.js#L10-L20`.

```javascript
import { __ } from "@wordpress/i18n";
import { registerPlugin } from "@wordpress/plugins";
import { useSelect } from "@wordpress/data";
import { createPortal, useEffect, useState } from "@wordpress/element";
import "./editor.scss";

const CopyIcon = () => (
	<svg
		width="18"
		height="18"
		viewBox="0 0 18 18"
		fill="none"
		xmlns="http://www.w3.org/2000/svg"
		aria-hidden="true"
		focusable="false"
	>
		<path
			d="M6 6V3.75A.75.75 0 0 1 6.75 3h7.5a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-.75.75H12M3.75 6.75h7.5a.75.75 0 0 1 .75.75v7.5a.75.75 0 0 1-.75.75h-7.5a.75.75 0 0 1-.75-.75v-7.5a.75.75 0 0 1 .75-.75Z"
			stroke="currentColor"
			strokeWidth="1.2"
			strokeLinecap="round"
			strokeLinejoin="round"
		/>
	</svg>
);

const PORTAL_CLASSNAME = "spspc-shortcode-portal";

const copyText = async (text) => {
	// First try Clipboard API
	if (navigator.clipboard && navigator.clipboard.writeText) {
		try {
			await navigator.clipboard.writeText(text);
			return true;
		} catch (e) {
			console.log("Clipboard API failed, using fallback.", e);
		}
	}

	// Fallback method: hidden textarea + execCommand
	try {
		const textarea = document.createElement("textarea");
		textarea.value = text;

		// Hide from screen
		textarea.style.position = "fixed";
		textarea.style.opacity = "0";
		textarea.style.pointerEvents = "none";

		document.body.appendChild(textarea);
		textarea.select();

		const success = document.execCommand("copy");
		document.body.removeChild(textarea);

		return success;
	} catch (err) {
		console.log("Fallback copy failed:", err);
		return false;
	}
};

const SavedTemplateSidebar = () => {
	const { postType, postId } = useSelect(
		(select) => ({
			postType: select("core/editor")?.getCurrentPostType?.() || null,
			postId: select("core/editor")?.getCurrentPostId?.() || null,
		}),
		[]
	);

	const [copied, setCopied] = useState(false);
	const [portalTarget, setPortalTarget] = useState(null);

	useEffect(() => {
		if (postType !== "sp_post_template") {
			setPortalTarget(null);
			return undefined;
		}

		let container = null;

		const ensureContainer = () => {
			const fill = document.querySelector(".interface-complementary-area__fill");
			if (!fill) {
				return;
			}

			let existing = fill.querySelector(`:scope > .${PORTAL_CLASSNAME}`);
			if (!existing) {
				existing = document.createElement("div");
				existing.className = PORTAL_CLASSNAME;
				fill.insertBefore(existing, fill.firstChild);
			} else if (fill.firstElementChild !== existing) {
				fill.insertBefore(existing, fill.firstChild);
			}

			if (existing !== container) {
				container = existing;
				setPortalTarget(existing);
			}
		};

		ensureContainer();

		const observer = new window.MutationObserver(ensureContainer);
		observer.observe(document.body, { childList: true, subtree: true });

		return () => {
			observer.disconnect();
			if (container && container.parentNode) {
				container.parentNode.removeChild(container);
			}
			setPortalTarget(null);
		};
	}, [postType]);

	if (postType !== "sp_post_template" || !portalTarget) {
		return null;
	}

	const idForShortcode = postId || 0;
	const shortcode = `[smart_post id="${idForShortcode}"]`;
	const savedTemplatesUrl =
		(window.sp_smart_post_block_localize && window.sp_smart_post_block_localize.savedTemplatesUrl) ||
		(window.sp_pcp_block_settings && window.sp_pcp_block_settings.savedTemplatesUrl) ||
		"";

	const handleCopy = async () => {
		const ok = await copyText(shortcode);
		if (!ok) {
			return;
		}
		setCopied(true);
		window.setTimeout(() => setCopied(false), 1500);
	};

	return createPortal(
		<div className="spspc-shortcode-panel">
			<p className="spspc-shortcode-panel__intro">
				{__("You can use this shortcode anywhere and manage it from", "post-carousel")}{" "}
				<a className="spspc-shortcode-panel__link" href={savedTemplatesUrl} rel="noopener noreferrer">
					{__("Saved Templates.", "post-carousel")}
				</a>
			</p>
			<button
				type="button"
				className="spspc-shortcode-panel__chip"
				onClick={handleCopy}
				aria-label={copied ? __("Shortcode copied", "post-carousel") : __("Copy shortcode", "post-carousel")}
			>
				<span className="spspc-shortcode-panel__code">{shortcode}</span>
				<span className="spspc-shortcode-panel__copy">
					{copied ? <span className="spspc-shortcode-panel__copy-text">Copied!</span> : <CopyIcon />}
				</span>
			</button>
		</div>,
		portalTarget
	);
};

registerPlugin("spspc-saved-template-sidebar", {
	render: SavedTemplateSidebar,
});

```
