PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 1.0.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v1.0.0
2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.10.0 All 48 releases
thinkrank / src / admin / components / common / MediaPicker.js

MediaPicker.js in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 1.0.0, at src/admin/components/common/MediaPicker.js

196 lines 5.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * Media Picker Component
3 *
4 * WordPress media library integration for selecting images
5 *
6 * @package ThinkRank
7 * @since 1.0.0
8 */
9
10 import { useState } from '@wordpress/element';
11 import { __ } from '@wordpress/i18n';
12 import {
13 Button,
14 Flex,
15 FlexItem,
16 __experimentalSpacer as Spacer
17 } from '@wordpress/components';
18
19 /**
20 * Media Picker Component
21 */
22 const MediaPicker = ({
23 value,
24 onChange,
25 label,
26 help,
27 allowedTypes = ['image'],
28 multiple = false,
29 disabled = false
30 }) => {
31 const [isOpen, setIsOpen] = useState(false);
32
33 /**
34 * Open WordPress media library
35 */
36 const openMediaLibrary = () => {
37 if (disabled) return;
38
39 // Check if wp.media is available
40 if (typeof wp === 'undefined' || typeof wp.media === 'undefined') {
41 console.error('WordPress media library not available');
42 return;
43 }
44
45 // Create media frame
46 const frame = wp.media({
47 title: label || __('Select Media', 'thinkrank'),
48 button: {
49 text: __('Use this media', 'thinkrank')
50 },
51 multiple: multiple,
52 library: {
53 type: allowedTypes
54 }
55 });
56
57 // Handle media selection
58 frame.on('select', () => {
59 const selection = frame.state().get('selection');
60
61 if (multiple) {
62 const attachments = selection.map(attachment => {
63 const data = attachment.toJSON();
64 return {
65 id: data.id,
66 url: data.url,
67 alt: data.alt || '',
68 title: data.title || '',
69 filename: data.filename || '',
70 mime: data.mime || '',
71 width: data.width || 0,
72 height: data.height || 0
73 };
74 });
75 onChange(attachments);
76 } else {
77 const attachment = selection.first().toJSON();
78 const mediaData = {
79 id: attachment.id,
80 url: attachment.url,
81 alt: attachment.alt || '',
82 title: attachment.title || '',
83 filename: attachment.filename || '',
84 mime: attachment.mime || '',
85 width: attachment.width || 0,
86 height: attachment.height || 0
87 };
88 onChange(mediaData.url);
89 }
90 });
91
92 // Open the frame
93 frame.open();
94 };
95
96 /**
97 * Remove selected media
98 */
99 const removeMedia = () => {
100 onChange(multiple ? [] : '');
101 };
102
103 /**
104 * Get media preview
105 */
106 const getMediaPreview = () => {
107 if (!value) return null;
108
109 if (multiple && Array.isArray(value)) {
110 return value.map((item, index) => (
111 <div key={index} className="media-preview-item">
112 <img
113 src={item.url || item}
114 alt={item.alt || ''}
115 style={{ maxWidth: '100px', maxHeight: '100px', objectFit: 'cover' }}
116 />
117 </div>
118 ));
119 }
120
121 // Single media item
122 const mediaUrl = typeof value === 'object' ? value.url : value;
123 if (mediaUrl) {
124 return (
125 <div className="media-preview-item">
126 <img
127 src={mediaUrl}
128 alt=""
129 style={{ maxWidth: '100px', maxHeight: '100px', objectFit: 'cover' }}
130 />
131 </div>
132 );
133 }
134
135 return null;
136 };
137
138 const hasMedia = multiple ? (Array.isArray(value) && value.length > 0) : !!value;
139
140 return (
141 <div className="thinkrank-media-picker">
142 {label && (
143 <label className="components-base-control__label">
144 {label}
145 </label>
146 )}
147
148 <Spacer marginY={2} />
149
150 <Flex direction="column" gap={3}>
151 {hasMedia && (
152 <FlexItem>
153 <div className="media-preview">
154 {getMediaPreview()}
155 </div>
156 </FlexItem>
157 )}
158
159 <FlexItem>
160 <Flex gap={2}>
161 <Button
162 variant={hasMedia ? "secondary" : "primary"}
163 onClick={openMediaLibrary}
164 disabled={disabled}
165 >
166 {hasMedia
167 ? __('Change Media', 'thinkrank')
168 : __('Select Media', 'thinkrank')
169 }
170 </Button>
171
172 {hasMedia && (
173 <Button
174 variant="tertiary"
175 isDestructive
176 onClick={removeMedia}
177 disabled={disabled}
178 >
179 {__('Remove', 'thinkrank')}
180 </Button>
181 )}
182 </Flex>
183 </FlexItem>
184 </Flex>
185
186 {help && (
187 <p className="components-base-control__help">
188 {help}
189 </p>
190 )}
191 </div>
192 );
193 };
194
195 export default MediaPicker;
196