UPDATE Enhance audio player block with caption saving functionality and improved UI for caption management
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Antoine M 2025-10-30 09:29:12 +01:00
parent e2ffc8ef75
commit 2a4bbceeeb
4 changed files with 189 additions and 35 deletions

View File

@ -1 +1 @@
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-element', 'wp-i18n'), 'version' => 'a1bd7238a6891cc75b86');
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n'), 'version' => 'f1e5510ad5a5a49f9c51');

View File

@ -30,9 +30,15 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var _wordpress_components__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @wordpress/element */ "@wordpress/element");
/* harmony import */ var _wordpress_element__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(_wordpress_element__WEBPACK_IMPORTED_MODULE_3__);
/* harmony import */ var _editor_scss__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./editor.scss */ "./src/audio-player/editor.scss");
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! react/jsx-runtime */ "react/jsx-runtime");
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _wordpress_data__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @wordpress/data */ "@wordpress/data");
/* harmony import */ var _wordpress_data__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(_wordpress_data__WEBPACK_IMPORTED_MODULE_4__);
/* harmony import */ var _wordpress_core_data__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @wordpress/core-data */ "@wordpress/core-data");
/* harmony import */ var _wordpress_core_data__WEBPACK_IMPORTED_MODULE_5___default = /*#__PURE__*/__webpack_require__.n(_wordpress_core_data__WEBPACK_IMPORTED_MODULE_5__);
/* harmony import */ var _editor_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./editor.scss */ "./src/audio-player/editor.scss");
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! react/jsx-runtime */ "react/jsx-runtime");
/* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7___default = /*#__PURE__*/__webpack_require__.n(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__);
@ -48,17 +54,44 @@ function Edit({
audioUrl,
audioId,
title,
description,
caption
} = attributes;
const audioRef = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_3__.useRef)(null);
const plyrInstance = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_3__.useRef)(null);
const {
saveEntityRecord
} = (0,_wordpress_data__WEBPACK_IMPORTED_MODULE_4__.useDispatch)(_wordpress_core_data__WEBPACK_IMPORTED_MODULE_5__.store);
const [isSavingCaption, setIsSavingCaption] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_3__.useState)(false);
const [saveMessage, setSaveMessage] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_3__.useState)("");
const saveCaptionToMedia = async newCaption => {
if (!audioId) return;
try {
setIsSavingCaption(true);
setSaveMessage("");
await saveEntityRecord("postType", "attachment", {
id: audioId,
caption: newCaption
});
setSaveMessage((0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Légende mise à jour dans la médiathèque.", "carhop-blocks"));
} catch (e) {
setSaveMessage((0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Erreur lors de la mise à jour dans la médiathèque.", "carhop-blocks"));
} finally {
setIsSavingCaption(false);
}
};
const handleCaptionChange = value => {
setAttributes({
caption: value
});
if (audioId) {
void saveCaptionToMedia(value);
}
};
const onSelectAudio = media => {
setAttributes({
audioUrl: media.url,
audioId: media.id,
// Récupérer les métadonnées depuis la médiathèque
description: media.description || "",
caption: media.caption || ""
});
};
@ -72,7 +105,6 @@ function Edit({
setAttributes({
audioUrl: "",
audioId: 0,
description: "",
caption: ""
});
};
@ -107,18 +139,46 @@ function Edit({
}
};
}, [audioUrl]);
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxs)("div", {
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxs)("div", {
...(0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.useBlockProps)({
className: "audio-player"
}),
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.RichText, {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.InspectorControls, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxs)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.PanelBody, {
title: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Informations", "carhop-blocks"),
initialOpen: true,
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.TextControl, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Titre", "carhop-blocks"),
value: title,
onChange: value => setAttributes({
title: value
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.TextControl, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Légende", "carhop-blocks"),
value: caption,
onChange: handleCaptionChange
}), audioId ? isSavingCaption ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.Notice, {
status: "info",
isDismissible: false,
children: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Sauvegarde…", "carhop-blocks")
}) : saveMessage ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.Notice, {
status: "success",
isDismissible: false,
children: saveMessage
}) : null : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.Notice, {
status: "info",
isDismissible: false,
children: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Média externe : la légende n'est pas synchronisée dans la médiathèque.", "carhop-blocks")
})]
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.RichText, {
className: "audio-player__title",
value: title,
onChange: value => setAttributes({
title: value
}),
tagName: "h4"
}), !audioUrl ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.MediaPlaceholder, {
}), !audioUrl ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.MediaPlaceholder, {
icon: "format-audio",
onSelect: onSelectAudio,
onSelectURL: onSelectURL,
@ -128,22 +188,22 @@ function Edit({
title: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Fichier audio", "carhop-blocks"),
instructions: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Téléchargez un fichier audio, sélectionnez-en un depuis la médiathèque ou insérez-en un depuis une URL.", "carhop-blocks")
}
}) : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.Fragment, {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxs)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.BlockControls, {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.MediaReplaceFlow, {
}) : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxs)(react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.Fragment, {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxs)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.BlockControls, {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.MediaReplaceFlow, {
mediaId: audioId,
mediaURL: audioUrl,
allowedTypes: ["audio"],
accept: "audio/*",
onSelectURL: onSelectURL,
onSelect: onSelectAudio
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.ToolbarButton, {
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_2__.ToolbarButton, {
onClick: onRemoveAudio,
children: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Retirer", "carhop-blocks")
})]
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)("div", {
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)("div", {
className: "audio-player-preview",
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)("audio", {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)("audio", {
ref: audioRef,
className: "js-plyr",
src: audioUrl,
@ -151,17 +211,16 @@ function Edit({
children: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)("Votre navigateur ne supporte pas l'élément audio.", "carhop-blocks")
})
})]
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsxs)("p", {
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsxs)("p", {
className: "audio-player__details",
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)("span", {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)("span", {
className: "audio-player__details__label",
children: "Audio"
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)("span", {
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_7__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_1__.RichText, {
className: "audio-player__details__caption",
children: caption ? caption + " — " : ""
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_5__.jsx)("span", {
className: "audio-player__details__description",
children: description !== null && description !== void 0 ? description : ""
value: caption,
onChange: value => handleCaptionChange(value),
tagName: "span"
})]
})]
});
@ -314,6 +373,26 @@ module.exports = window["wp"]["components"];
/***/ }),
/***/ "@wordpress/core-data":
/*!**********************************!*\
!*** external ["wp","coreData"] ***!
\**********************************/
/***/ ((module) => {
module.exports = window["wp"]["coreData"];
/***/ }),
/***/ "@wordpress/data":
/*!******************************!*\
!*** external ["wp","data"] ***!
\******************************/
/***/ ((module) => {
module.exports = window["wp"]["data"];
/***/ }),
/***/ "@wordpress/element":
/*!*********************************!*\
!*** external ["wp","element"] ***!

File diff suppressed because one or more lines are too long

View File

@ -4,22 +4,63 @@ import {
MediaPlaceholder,
BlockControls,
MediaReplaceFlow,
InspectorControls,
} from "@wordpress/block-editor";
import { ToolbarButton } from "@wordpress/components";
import { useEffect, useRef } from "@wordpress/element";
import {
ToolbarButton,
PanelBody,
TextControl,
Notice,
} from "@wordpress/components";
import { useEffect, useRef, useState } from "@wordpress/element";
import { useDispatch } from "@wordpress/data";
import { store as coreStore } from "@wordpress/core-data";
import "./editor.scss";
import { RichText } from "@wordpress/block-editor";
export default function Edit({ attributes, setAttributes }) {
const { audioUrl, audioId, title, description, caption } = attributes;
const { audioUrl, audioId, title, caption } = attributes;
const audioRef = useRef(null);
const plyrInstance = useRef(null);
const { saveEntityRecord } = useDispatch(coreStore);
const [isSavingCaption, setIsSavingCaption] = useState(false);
const [saveMessage, setSaveMessage] = useState("");
const saveCaptionToMedia = async (newCaption) => {
if (!audioId) return;
try {
setIsSavingCaption(true);
setSaveMessage("");
await saveEntityRecord("postType", "attachment", {
id: audioId,
caption: newCaption,
});
setSaveMessage(
__("Légende mise à jour dans la médiathèque.", "carhop-blocks")
);
} catch (e) {
setSaveMessage(
__(
"Erreur lors de la mise à jour dans la médiathèque.",
"carhop-blocks"
)
);
} finally {
setIsSavingCaption(false);
}
};
const handleCaptionChange = (value) => {
setAttributes({ caption: value });
if (audioId) {
void saveCaptionToMedia(value);
}
};
const onSelectAudio = (media) => {
setAttributes({
audioUrl: media.url,
audioId: media.id,
// Récupérer les métadonnées depuis la médiathèque
description: media.description || "",
caption: media.caption || "",
});
};
@ -35,7 +76,6 @@ export default function Edit({ attributes, setAttributes }) {
setAttributes({
audioUrl: "",
audioId: 0,
description: "",
caption: "",
});
};
@ -78,6 +118,41 @@ export default function Edit({ attributes, setAttributes }) {
return (
<div {...useBlockProps({ className: "audio-player" })}>
<InspectorControls>
<PanelBody
title={__("Informations", "carhop-blocks")}
initialOpen={true}
>
<TextControl
label={__("Titre", "carhop-blocks")}
value={title}
onChange={(value) => setAttributes({ title: value })}
/>
<TextControl
label={__("Légende", "carhop-blocks")}
value={caption}
onChange={handleCaptionChange}
/>
{audioId ? (
isSavingCaption ? (
<Notice status="info" isDismissible={false}>
{__("Sauvegarde…", "carhop-blocks")}
</Notice>
) : saveMessage ? (
<Notice status="success" isDismissible={false}>
{saveMessage}
</Notice>
) : null
) : (
<Notice status="info" isDismissible={false}>
{__(
"Média externe : la légende n'est pas synchronisée dans la médiathèque.",
"carhop-blocks"
)}
</Notice>
)}
</PanelBody>
</InspectorControls>
<RichText
className="audio-player__title"
value={title}
@ -131,12 +206,12 @@ export default function Edit({ attributes, setAttributes }) {
)}
<p className="audio-player__details">
<span className="audio-player__details__label">Audio</span>
<span className="audio-player__details__caption">
{caption ? caption + " — " : ""}
</span>
<span className="audio-player__details__description">
{description ?? ""}
</span>
<RichText
className="audio-player__details__caption"
value={caption}
onChange={(value) => handleCaptionChange(value)}
tagName="span"
/>
</p>
</div>
);