PluginProbe
Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News / 4.0.8
Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News v4.0.8
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 2.3.5 2.3.6 2.4.0 2.4.1 2.4.10 2.4.11 2.4.12 2.4.13 2.4.14 2.4.15 2.4.16 2.4.17 2.4.18 2.4.19 2.4.2 2.4.20 2.4.21 All 88 releases
post-carousel / src / divi-5 / index.jsx

index.jsx in Smart Post – Post Grid, Post Carousel, Post Slider Gutenberg Blocks for Blog & News 4.0.8, at src/divi-5/index.jsx

204 lines 5.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Smart Post Show Pro - Divi 5 Module
3 *
4 * React component for Divi 5 Visual Builder
5 * Uses useFetch pattern following official Divi 5 Dynamic Module example
6 *
7 * @package Smart_Post_Show_Pro
8 */
9
10 import metadata from "./module.json";
11 import { SettingsContent } from "./settings-content";
12 import "./module-icons"; // Import to register custom icon
13
14 // Access React from global scope (Divi provides this).
15 const React = window?.vendor?.React;
16 const { useEffect, useRef } = React || {};
17
18 // Access Divi globals - these are provided by Divi in the window object
19 const ModuleContainer = window?.divi?.module?.ModuleContainer;
20 const StyleContainer = window?.divi?.module?.StyleContainer;
21 const elementClassnames = window?.divi?.module?.elementClassnames;
22 const registerModule = window?.divi?.moduleLibrary?.registerModule;
23 const addAction = window?.vendor?.wp?.hooks?.addAction;
24 const useFetch = window?.divi?.rest?.useFetch;
25
26 /**
27 * Styles Component
28 * Generates module styles
29 */
30 const ModuleStyles = ({ elements, settings, mode, state, noStyleTag }) => {
31 return (
32 <StyleContainer mode={mode} state={state} noStyleTag={noStyleTag}>
33 {elements.style({
34 attrName: "module",
35 styleProps: { disabledOn: { disabledModuleVisibility: settings?.disabledModuleVisibility } },
36 })}
37 </StyleContainer>
38 );
39 };
40
41 /**
42 * Script Data Component
43 * Outputs module script data
44 */
45 const ModuleScriptData = ({ elements }) => {
46 return <>{elements.scriptData({ attrName: "module" })}</>;
47 };
48
49 /**
50 * Classnames Function
51 * Adds module CSS classes
52 */
53 const moduleClassnames = ({ classnamesInstance, attrs }) => {
54 classnamesInstance.add(elementClassnames({ attrs: attrs?.module?.decoration ?? {} }));
55 };
56
57 /**
58 * Edit Renderer Component
59 *
60 * Uses useFetch pattern following official Divi 5 Dynamic Module example.
61 * Fetches template HTML from REST API for visual builder.
62 * CSS and Google Fonts are now included inline in the HTML response.
63 */
64 const EditRenderer = ({ attrs, id, name, elements }) => {
65 const templateId = attrs?.templateId?.innerContent?.desktop?.value || "0";
66
67 // useFetch hook for fetching template HTML from REST API.
68 const { fetch, response, isLoading } = useFetch(null);
69
70 // Reference for handling fetch abort (following Divi 5 pattern).
71 const fetchAbortRef = useRef(null);
72
73 // Track last fetched template ID to prevent duplicate requests.
74 const lastFetchedRef = useRef(null);
75
76 // Load template HTML when templateId changes (following Divi 5 pattern).
77 useEffect(() => {
78 // Don't fetch if no template selected.
79 if (!templateId || templateId === "0") {
80 return;
81 }
82
83 // Prevent duplicate requests for the same template ID.
84 if (lastFetchedRef.current === templateId) {
85 return;
86 }
87
88 // Mark this template as being fetched.
89 lastFetchedRef.current = templateId;
90
91 // Abort previous fetch if there's any.
92 if (fetchAbortRef.current) {
93 fetchAbortRef.current.abort();
94 }
95
96 // Create new AbortController instance.
97 fetchAbortRef.current = new AbortController();
98
99 // Fetch template HTML from REST API (following Divi 5 useFetch pattern).
100 // Response includes HTML with inline CSS and Google Fonts.
101 fetch({
102 method: "GET",
103 restRoute: `/spsp/divi5/v1/template-html?template_id=${templateId}`,
104 })
105 .then(() => {
106 setTimeout(() => {
107 if (typeof window !== "undefined" && typeof window.init === "function") {
108 window.init();
109 }
110 }, 0);
111 })
112 .catch((error) => {
113 // Only log non-abort errors.
114 if (error.name !== "AbortError") {
115 console.error("Smart Post Show Pro: Error loading template", error);
116 }
117 });
118
119 // Cleanup function - abort fetch on unmount or templateId change.
120 return () => {
121 if (fetchAbortRef.current) {
122 fetchAbortRef.current.abort();
123 fetchAbortRef.current = null;
124 }
125 };
126 // Only depend on templateId - NOT fetch (causes infinite loop)
127 }, [templateId]);
128
129 // Compute template HTML from response.
130 let templateHtml = '<div style="padding:20px;text-align:center;color:#999;">Failed to load template</div>';
131
132 if (response && response.success && response.html) {
133 templateHtml = response.html;
134 } else if (response && !response.success) {
135 templateHtml = '<div style="padding:20px;text-align:center;color:#999;">Failed to load template</div>';
136 } else if (!response) {
137 templateHtml = '<div style="padding:20px;text-align:center;color:#999;">No response from server</div>';
138 }
139
140 // Following Divi 5 pattern: conditional rendering inside return statement.
141 return (
142 <ModuleContainer
143 attrs={attrs}
144 elements={elements}
145 id={id}
146 moduleClassName="spsp_divi5_smart_post_show"
147 name={name}
148 scriptDataComponent={ModuleScriptData}
149 stylesComponent={ModuleStyles}
150 classnamesFunction={moduleClassnames}
151 >
152 {elements.styleComponents({ attrName: "module" })}
153 <div className="et_pb_module_inner spsp-divi5-testimonial-wrapper" data-template-id={templateId}>
154 {!templateId || templateId === "0" ? (
155 <div
156 style={{
157 padding: "20px",
158 textAlign: "center",
159 color: "#999",
160 borderRadius: "4px",
161 border: "1px dotted #ddd",
162 }}
163 >
164 <p style={{ fontSize: "14px", margin: "0" }}>Please select a saved template</p>
165 </div>
166 ) : isLoading ? (
167 <div
168 style={{
169 padding: "20px",
170 textAlign: "center",
171 color: "#666",
172 borderRadius: "4px",
173 border: "1px dotted #ddd",
174 }}
175 >
176 <p>Loading template...</p>
177 </div>
178 ) : (
179 <div dangerouslySetInnerHTML={{ __html: templateHtml }} />
180 )}
181 </div>
182 </ModuleContainer>
183 );
184 };
185
186 /**
187 * Smart Post Show Pro Module Definition
188 * Exported for Divi 5 to pick up
189 */
190 export const spspDivi5SmartPostShow = {
191 metadata,
192 renderers: {
193 edit: EditRenderer,
194 },
195 settings: {
196 content: SettingsContent,
197 },
198 };
199
200 // Also register via hooks for compatibility
201 addAction("divi.moduleLibrary.registerModuleLibraryStore.after", "spsp.divi5SmartPostShow", () => {
202 registerModule(spspDivi5SmartPostShow.metadata, spspDivi5SmartPostShow);
203 });
204