FEATURE Introducing the thumbnail focal point plugin with its features
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
9483cd8e79
commit
17811c8091
File diff suppressed because one or more lines are too long
|
|
@ -72,7 +72,12 @@ $issue_related_articles = get_field('articles', $last_issue->ID);
|
|||
|
||||
<div class="block-dernieres-dynamiques__issue-thumbnail-wrapper">
|
||||
<div class="block-dernieres-dynamiques__issue-thumbnail">
|
||||
<?php echo get_the_post_thumbnail($last_issue->ID, 'full'); ?>
|
||||
<?php
|
||||
$focal_position = safe_get_thumbnail_focal_point_css($last_issue->ID);
|
||||
echo get_the_post_thumbnail($last_issue->ID, 'full', [
|
||||
'style' => 'object-fit: cover; object-position: ' . esc_attr($focal_position) . ';'
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<div class="card-background"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -72,7 +72,12 @@ $issue_related_articles = get_field('articles', $last_issue->ID);
|
|||
|
||||
<div class="block-dernieres-dynamiques__issue-thumbnail-wrapper">
|
||||
<div class="block-dernieres-dynamiques__issue-thumbnail">
|
||||
<?php echo get_the_post_thumbnail($last_issue->ID, 'full'); ?>
|
||||
<?php
|
||||
$focal_position = safe_get_thumbnail_focal_point_css($last_issue->ID);
|
||||
echo get_the_post_thumbnail($last_issue->ID, 'full', [
|
||||
'style' => 'object-fit: cover; object-position: ' . esc_attr($focal_position) . ';'
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<div class="card-background"></div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -81,10 +81,14 @@ $query = new WP_Query(array(
|
|||
</div>
|
||||
|
||||
<div class="card-revue__issue-thumbnail-wrapper">
|
||||
<?php $post_thumbnail_id = get_the_post_thumbnail(get_the_ID(), 'full'); ?>
|
||||
<div class="card-revue__issue-thumbnail">
|
||||
<?php if ($post_thumbnail_id) : ?>
|
||||
<?php echo $post_thumbnail_id; ?>
|
||||
<?php if (has_post_thumbnail()) : ?>
|
||||
<?php
|
||||
$focal_position = safe_get_thumbnail_focal_point_css();
|
||||
echo get_the_post_thumbnail(get_the_ID(), 'full', [
|
||||
'style' => 'object-fit: cover; object-position: ' . esc_attr($focal_position) . ';'
|
||||
]);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="card-background"></div>
|
||||
|
|
|
|||
|
|
@ -81,10 +81,14 @@ $query = new WP_Query(array(
|
|||
</div>
|
||||
|
||||
<div class="card-revue__issue-thumbnail-wrapper">
|
||||
<?php $post_thumbnail_id = get_the_post_thumbnail(get_the_ID(), 'full'); ?>
|
||||
<div class="card-revue__issue-thumbnail">
|
||||
<?php if ($post_thumbnail_id) : ?>
|
||||
<?php echo $post_thumbnail_id; ?>
|
||||
<?php if (has_post_thumbnail()) : ?>
|
||||
<?php
|
||||
$focal_position = safe_get_thumbnail_focal_point_css();
|
||||
echo get_the_post_thumbnail(get_the_ID(), 'full', [
|
||||
'style' => 'object-fit: cover; object-position: ' . esc_attr($focal_position) . ';'
|
||||
]);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="card-background"></div>
|
||||
|
|
|
|||
143
plugins/dynamiques-thumbnail-focal-point/QUICKSTART.md
Normal file
143
plugins/dynamiques-thumbnail-focal-point/QUICKSTART.md
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
# 🚀 Guide de démarrage rapide
|
||||
|
||||
## Installation rapide
|
||||
|
||||
1. Activez le plugin dans WordPress
|
||||
2. C'est tout ! Le plugin fonctionne automatiquement 🎉
|
||||
|
||||
## Utilisation
|
||||
|
||||
### Pour l'éditeur classique (avec ACF)
|
||||
|
||||
1. **Éditez un article/page** avec une image mise en avant
|
||||
2. **Trouvez la meta box "Image mise en avant"** dans la sidebar
|
||||
3. **Le focal point picker apparaît sous l'image** automatiquement
|
||||
4. **Cliquez sur l'image** pour définir le point focal
|
||||
5. **Enregistrez** votre article
|
||||
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ Image mise en avant │
|
||||
├─────────────────────────────────┤
|
||||
│ [Image de la thumbnail] │
|
||||
│ ┌─┴─┐ │
|
||||
│ │ + │ ← Point focal │
|
||||
│ └───┘ │
|
||||
│ │
|
||||
│ ───────────────────────── │
|
||||
│ Point focal de recadrage │
|
||||
│ [Picker interactif] │
|
||||
│ Position : 65% / 40% │
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Pour l'éditeur Gutenberg
|
||||
|
||||
1. **Définissez une image mise en avant**
|
||||
2. **Ouvrez le panneau "Point focal de la miniature"** dans la sidebar
|
||||
3. **Cliquez sur l'image** pour définir le focal point
|
||||
4. Le point focal est **sauvegardé automatiquement**
|
||||
|
||||
## Utilisation dans vos templates
|
||||
|
||||
### Méthode simple
|
||||
|
||||
```php
|
||||
<?php
|
||||
// Récupérer la position CSS directement
|
||||
$focal_position = get_thumbnail_focal_point_css();
|
||||
|
||||
// Utiliser avec object-position
|
||||
the_post_thumbnail('large', [
|
||||
'style' => 'object-fit: cover; object-position: ' . $focal_position
|
||||
]);
|
||||
?>
|
||||
```
|
||||
|
||||
### Avec background-image
|
||||
|
||||
```php
|
||||
<div style="
|
||||
background-image: url(<?php echo get_the_post_thumbnail_url(); ?>);
|
||||
background-size: cover;
|
||||
background-position: <?php echo get_thumbnail_focal_point_css(); ?>;
|
||||
height: 400px;
|
||||
">
|
||||
<h1><?php the_title(); ?></h1>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Fonctions disponibles
|
||||
|
||||
| Fonction | Retour | Exemple |
|
||||
| ----------------------------------------- | ---------------------------- | -------------------------- |
|
||||
| `get_thumbnail_focal_point($post_id)` | `['x' => 0.65, 'y' => 0.40]` | Valeurs brutes (0 à 1) |
|
||||
| `get_thumbnail_focal_point_css($post_id)` | `"65% 40%"` | Format CSS prêt à l'emploi |
|
||||
|
||||
**Note** : `$post_id` est optionnel. Si omis, utilise l'article courant.
|
||||
|
||||
## Exemples de cas d'usage
|
||||
|
||||
### 1. Cards d'articles
|
||||
|
||||
```php
|
||||
<article class="card">
|
||||
<?php
|
||||
the_post_thumbnail('medium', [
|
||||
'class' => 'card-image',
|
||||
'style' => 'width: 100%; height: 200px; object-fit: cover; object-position: ' . get_thumbnail_focal_point_css()
|
||||
]);
|
||||
?>
|
||||
<h2><?php the_title(); ?></h2>
|
||||
</article>
|
||||
```
|
||||
|
||||
### 2. Hero banner
|
||||
|
||||
```php
|
||||
<section class="hero" style="
|
||||
background-image: url(<?php echo get_the_post_thumbnail_url(null, 'full'); ?>);
|
||||
background-position: <?php echo get_thumbnail_focal_point_css(); ?>;
|
||||
background-size: cover;
|
||||
">
|
||||
<div class="hero-content">
|
||||
<h1><?php the_title(); ?></h1>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
### 3. Grille responsive
|
||||
|
||||
```php
|
||||
<div class="image-grid">
|
||||
<?php while (have_posts()): the_post(); ?>
|
||||
<div class="grid-item">
|
||||
<?php
|
||||
the_post_thumbnail('large', [
|
||||
'style' => 'object-fit: cover; object-position: ' . get_thumbnail_focal_point_css()
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php endwhile; ?>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Format des données
|
||||
|
||||
Les données sont stockées dans la table `wp_postmeta` :
|
||||
|
||||
```json
|
||||
{
|
||||
"x": 0.65,
|
||||
"y": 0.4
|
||||
}
|
||||
```
|
||||
|
||||
Où :
|
||||
|
||||
- `x: 0` = gauche, `x: 0.5` = centre, `x: 1` = droite
|
||||
- `y: 0` = haut, `y: 0.5` = milieu, `y: 1` = bas
|
||||
|
||||
## Support
|
||||
|
||||
Pour plus de détails, consultez le fichier `README.md` ou `example-usage.php`.
|
||||
187
plugins/dynamiques-thumbnail-focal-point/README.md
Normal file
187
plugins/dynamiques-thumbnail-focal-point/README.md
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
# Plugin Dynamiques Focal Point
|
||||
|
||||
Plugin WordPress pour ajouter un point focal personnalisable aux images mises en avant (thumbnails).
|
||||
|
||||
## Installation
|
||||
|
||||
1. Activer le plugin dans l'administration WordPress
|
||||
2. Le plugin fonctionne automatiquement avec :
|
||||
- **L'éditeur Gutenberg** : un panneau React apparaît dans la sidebar
|
||||
- **L'éditeur classique (avec ACF)** : le focal point picker s'intègre directement dans la meta box "Image mise en avant"
|
||||
|
||||
## Caractéristiques techniques
|
||||
|
||||
- ✅ Utilise le composant officiel `FocalPointPicker` de WordPress
|
||||
- ✅ Interface React pour une expérience utilisateur moderne
|
||||
- ✅ **S'intègre directement dans la meta box native de thumbnail** (pas de meta box séparée !)
|
||||
- ✅ Compatible avec tous les post types supportant les thumbnails
|
||||
- ✅ Fonctionne avec ACF et l'éditeur classique
|
||||
- ✅ Sauvegarde automatique dans les post meta
|
||||
|
||||
## Utilisation dans l'éditeur
|
||||
|
||||
### Avec l'éditeur Gutenberg
|
||||
|
||||
Après avoir défini une image mise en avant pour votre article/page :
|
||||
|
||||
1. Ouvrez le panneau "Point focal de la miniature" dans la sidebar
|
||||
2. Cliquez sur l'image pour définir le point focal
|
||||
3. Le point focal sera sauvegardé automatiquement
|
||||
|
||||
### Avec l'éditeur classique (ou avec ACF)
|
||||
|
||||
Après avoir défini une image mise en avant :
|
||||
|
||||
1. Allez dans la meta box **"Image mise en avant"** (celle qui est native à WordPress)
|
||||
2. Le focal point picker apparaît automatiquement **en dessous de l'image**
|
||||
3. Cliquez sur l'image pour définir le point focal (utilise le composant React `FocalPointPicker`)
|
||||
4. Enregistrez votre article/page pour sauvegarder le point focal
|
||||
|
||||
**Avantages** :
|
||||
|
||||
- 🎯 Tout est au même endroit - pas besoin de chercher une autre meta box
|
||||
- 🚀 Interface native et familière
|
||||
- ⚡ Rechargement automatique si vous changez l'image mise en avant
|
||||
|
||||
## Utilisation dans le thème
|
||||
|
||||
### Récupérer les valeurs du focal point
|
||||
|
||||
```php
|
||||
<?php
|
||||
$focal_point = get_post_meta(get_the_ID(), 'thumbnail_focal_point', true);
|
||||
|
||||
if ($focal_point && is_array($focal_point)) {
|
||||
$x = $focal_point['x'] ?? 0.5; // Valeur entre 0 et 1
|
||||
$y = $focal_point['y'] ?? 0.5; // Valeur entre 0 et 1
|
||||
|
||||
// Convertir en pourcentage
|
||||
$x_percent = ($x * 100) . '%';
|
||||
$y_percent = ($y * 100) . '%';
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
### Exemple 1 : Appliquer le focal point avec object-position
|
||||
|
||||
```php
|
||||
<?php
|
||||
$focal_point = get_post_meta(get_the_ID(), 'thumbnail_focal_point', true);
|
||||
$object_position = '50% 50%'; // Valeur par défaut (centre)
|
||||
|
||||
if ($focal_point && is_array($focal_point)) {
|
||||
$x_percent = ($focal_point['x'] * 100);
|
||||
$y_percent = ($focal_point['y'] * 100);
|
||||
$object_position = $x_percent . '% ' . $y_percent . '%';
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="post-thumbnail">
|
||||
<?php
|
||||
the_post_thumbnail('large', [
|
||||
'style' => 'object-fit: cover; object-position: ' . esc_attr($object_position) . ';'
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
```
|
||||
|
||||
### Exemple 2 : Utiliser le focal point comme background-position
|
||||
|
||||
```php
|
||||
<?php
|
||||
$focal_point = get_post_meta(get_the_ID(), 'thumbnail_focal_point', true);
|
||||
$bg_position = '50% 50%';
|
||||
|
||||
if ($focal_point && is_array($focal_point)) {
|
||||
$x_percent = ($focal_point['x'] * 100);
|
||||
$y_percent = ($focal_point['y'] * 100);
|
||||
$bg_position = $x_percent . '% ' . $y_percent . '%';
|
||||
}
|
||||
|
||||
$thumbnail_url = get_the_post_thumbnail_url(get_the_ID(), 'large');
|
||||
?>
|
||||
|
||||
<div class="post-thumbnail-bg"
|
||||
style="background-image: url(<?php echo esc_url($thumbnail_url); ?>);
|
||||
background-position: <?php echo esc_attr($bg_position); ?>;
|
||||
background-size: cover;">
|
||||
</div>
|
||||
```
|
||||
|
||||
### Exemple 3 : Fonction helper réutilisable
|
||||
|
||||
Ajoutez cette fonction dans votre `functions.php` :
|
||||
|
||||
```php
|
||||
<?php
|
||||
/**
|
||||
* Obtenir le focal point d'un post
|
||||
*
|
||||
* @param int|null $post_id ID du post (null pour le post courant)
|
||||
* @return array Tableau avec 'x' et 'y' (valeurs entre 0 et 1)
|
||||
*/
|
||||
function get_thumbnail_focal_point($post_id = null) {
|
||||
if (!$post_id) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$focal_point = get_post_meta($post_id, 'thumbnail_focal_point', true);
|
||||
|
||||
// Valeurs par défaut (centre de l'image)
|
||||
if (!$focal_point || !is_array($focal_point)) {
|
||||
return ['x' => 0.5, 'y' => 0.5];
|
||||
}
|
||||
|
||||
return [
|
||||
'x' => $focal_point['x'] ?? 0.5,
|
||||
'y' => $focal_point['y'] ?? 0.5
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtenir le focal point formaté pour CSS
|
||||
*
|
||||
* @param int|null $post_id ID du post (null pour le post courant)
|
||||
* @return string Format "50% 50%" pour object-position ou background-position
|
||||
*/
|
||||
function get_thumbnail_focal_point_css($post_id = null) {
|
||||
$focal_point = get_thumbnail_focal_point($post_id);
|
||||
$x_percent = ($focal_point['x'] * 100);
|
||||
$y_percent = ($focal_point['y'] * 100);
|
||||
|
||||
return $x_percent . '% ' . $y_percent . '%';
|
||||
}
|
||||
?>
|
||||
```
|
||||
|
||||
Puis dans vos templates :
|
||||
|
||||
```php
|
||||
<div class="post-thumbnail">
|
||||
<?php
|
||||
the_post_thumbnail('large', [
|
||||
'style' => 'object-fit: cover; object-position: ' . get_thumbnail_focal_point_css() . ';'
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Support des post types
|
||||
|
||||
Le plugin enregistre automatiquement les métadonnées du focal point pour tous les post types publics qui supportent les images mises en avant (thumbnails).
|
||||
|
||||
## Données sauvegardées
|
||||
|
||||
Les données sont sauvegardées dans les post meta sous la clé `thumbnail_focal_point` au format :
|
||||
|
||||
```json
|
||||
{
|
||||
"x": 0.5,
|
||||
"y": 0.5
|
||||
}
|
||||
```
|
||||
|
||||
Où `x` et `y` sont des nombres décimaux entre 0 et 1 :
|
||||
|
||||
- `x: 0` = gauche, `x: 0.5` = centre, `x: 1` = droite
|
||||
- `y: 0` = haut, `y: 0.5` = milieu, `y: 1` = bas
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
/**
|
||||
* Styles pour le focal point picker dans Gutenberg
|
||||
*/
|
||||
|
||||
/* Conteneur principal dans le panneau featured image */
|
||||
#gutenberg-focal-point-inline-root {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#gutenberg-focal-point-inline-root > div {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
/* Titre */
|
||||
#gutenberg-focal-point-inline-root strong {
|
||||
display: block;
|
||||
margin-bottom: 12px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: #1e1e1e;
|
||||
}
|
||||
|
||||
/* Instructions */
|
||||
#gutenberg-focal-point-inline-root p {
|
||||
margin: 0 0 12px;
|
||||
font-size: 13px;
|
||||
color: #757575;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* FocalPointPicker */
|
||||
#gutenberg-focal-point-inline-root .components-focal-point-picker {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
/* Position actuelle */
|
||||
#gutenberg-focal-point-inline-root p:last-child {
|
||||
margin-top: 12px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#gutenberg-focal-point-inline-root p:last-child strong {
|
||||
display: inline;
|
||||
color: #2271b1;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* S'assurer que le picker s'affiche correctement */
|
||||
.editor-post-featured-image {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
/* Ajustements responsive */
|
||||
@media (max-width: 781px) {
|
||||
#gutenberg-focal-point-inline-root > div {
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* Styles personnalisés pour le focal point picker intégré
|
||||
*/
|
||||
|
||||
/* Conteneur principal du focal point picker */
|
||||
#thumbnail-focal-point-inline-root {
|
||||
padding: 0;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
/* Ajuster l'espacement dans la meta box */
|
||||
#postimagediv .inside #thumbnail-focal-point-inline-root {
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #dcdcde;
|
||||
}
|
||||
|
||||
/* Titre du focal point picker */
|
||||
#thumbnail-focal-point-inline-root strong {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
font-size: 13px;
|
||||
color: #1d2327;
|
||||
}
|
||||
|
||||
/* Texte d'instructions */
|
||||
#thumbnail-focal-point-inline-root p {
|
||||
margin: 0 0 12px;
|
||||
font-size: 12px;
|
||||
color: #646970;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Conteneur du FocalPointPicker */
|
||||
#thumbnail-focal-point-inline-root .components-focal-point-picker {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
/* Ajuster la hauteur du picker si nécessaire */
|
||||
#thumbnail-focal-point-inline-root .components-focal-point-picker__wrapper {
|
||||
/* max-height: 300px; */
|
||||
}
|
||||
|
||||
/* Position actuelle */
|
||||
#thumbnail-focal-point-inline-root p:last-child {
|
||||
margin-bottom: 0;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* Style pour la valeur de position */
|
||||
#thumbnail-focal-point-inline-root p:last-child strong {
|
||||
display: inline;
|
||||
color: #2271b1;
|
||||
font-weight: 600;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Responsive - ajuster sur petits écrans */
|
||||
@media screen and (max-width: 782px) {
|
||||
#thumbnail-focal-point-inline-root {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
#postimagediv .inside #thumbnail-focal-point-inline-root {
|
||||
padding-top: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation de chargement */
|
||||
#thumbnail-focal-point-inline-root.loading {
|
||||
opacity: 0.6;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-element'), 'version' => '5e8f7612c40c2f842dc7');
|
||||
|
|
@ -0,0 +1 @@
|
|||
(()=>{"use strict";const e=window.wp.element,t=window.wp.components,n=(window.wp.apiFetch,window.ReactJSXRuntime),o=({postId:o,thumbnailUrl:i,initialFocalPoint:a})=>{const[l,d]=(0,e.useState)(a);return(0,e.useEffect)(()=>{let e=document.getElementById("thumbnail_focal_point_x"),t=document.getElementById("thumbnail_focal_point_y"),n=document.getElementById("thumbnail_focal_point_nonce");e||(e=document.createElement("input"),e.type="hidden",e.name="thumbnail_focal_point_x",e.id="thumbnail_focal_point_x",document.querySelector("form#post").appendChild(e)),t||(t=document.createElement("input"),t.type="hidden",t.name="thumbnail_focal_point_y",t.id="thumbnail_focal_point_y",document.querySelector("form#post").appendChild(t)),n||(n=document.createElement("input"),n.type="hidden",n.name="thumbnail_focal_point_nonce",n.id="thumbnail_focal_point_nonce",n.value=window.thumbnailFocalPointData?.nonce||"",document.querySelector("form#post").appendChild(n)),e.value=l.x,t.value=l.y},[l]),(0,n.jsxs)("div",{style:{marginTop:"15px",paddingTop:"15px",borderTop:"1px solid #dcdcde"},children:[(0,n.jsx)("div",{style:{marginBottom:"10px"},children:(0,n.jsx)("strong",{style:{fontSize:"13px",color:"#1d2327"},children:"Point focal de recadrage"})}),(0,n.jsx)("p",{style:{marginBottom:"12px",fontSize:"12px",color:"#646970",marginTop:"8px"},children:"Cliquez sur l'image pour définir le point focal utilisé lors du recadrage."}),(0,n.jsx)("div",{style:{marginBottom:"10px"},children:(0,n.jsx)(t.FocalPointPicker,{url:i,value:l,onChange:e=>{d(e)}})}),(0,n.jsxs)("p",{style:{fontSize:"12px",color:"#646970",marginTop:"8px"},children:["Position :"," ",(0,n.jsxs)("strong",{style:{color:"#2271b1"},children:[Math.round(100*l.x),"% / ",Math.round(100*l.y),"%"]})]})]})};if(window.addEventListener("DOMContentLoaded",()=>{!function(){const t=document.getElementById("postimagediv");if(!t)return;const i=t.querySelector("#set-post-thumbnail");if(!i||!window.thumbnailFocalPointData)return;if(!i.querySelector("img"))return;let a=document.getElementById("thumbnail-focal-point-inline-root");if(!a){a=document.createElement("div"),a.id="thumbnail-focal-point-inline-root";const e=t.querySelector(".inside");e?e.appendChild(a):t.appendChild(a)}const{postId:l,thumbnailUrl:d,focalPointX:c,focalPointY:r}=window.thumbnailFocalPointData;(0,e.render)((0,n.jsx)(o,{postId:l,thumbnailUrl:d,initialFocalPoint:{x:c,y:r}}),a)}(),"undefined"!=typeof jQuery&&(jQuery(document).on("ajaxSuccess",function(e,t,n){n.data&&"string"==typeof n.data&&-1!==n.data.indexOf("action=set-post-thumbnail")&&setTimeout(()=>{location.reload()},300)}),jQuery(document).on("click","#remove-post-thumbnail",function(){setTimeout(()=>{location.reload()},500)}))}),"undefined"!=typeof wp&&wp.media){const e=wp.media.featuredImage;if(e&&e.frame){const t=e.frame;wp.media.featuredImage.frame=function(){return this._frame||(this._frame=t.apply(this,arguments),this._frame.on("select",function(){})),this._frame}}}})();
|
||||
|
|
@ -0,0 +1 @@
|
|||
<?php return array('dependencies' => array('react-jsx-runtime', 'wp-components', 'wp-data', 'wp-element'), 'version' => 'ef86dc326873b7e4dd13');
|
||||
1
plugins/dynamiques-thumbnail-focal-point/build/index.js
Normal file
1
plugins/dynamiques-thumbnail-focal-point/build/index.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
(()=>{"use strict";const e=window.wp.element,t=window.wp.components,o=window.wp.data,r=window.ReactJSXRuntime,n=()=>{const{featuredImageId:e,featuredImageUrl:n,focalPoint:i}=(0,o.useSelect)(e=>{const t=e("core/editor").getEditedPostAttribute("featured_media"),o=t?e("core").getMedia(t):null,r=e("core/editor").getEditedPostAttribute("meta");return{featuredImageId:t,featuredImageUrl:o?.source_url||null,focalPoint:r?.thumbnail_focal_point||{x:.5,y:.5}}}),{editPost:d}=(0,o.useDispatch)("core/editor");return e&&n?(0,r.jsxs)("div",{style:{marginTop:"16px",paddingTop:"16px",borderTop:"1px solid #ddd"},children:[(0,r.jsx)("div",{style:{marginBottom:"12px"},children:(0,r.jsx)("strong",{style:{fontSize:"13px",color:"#1e1e1e"},children:"Point focal de recadrage"})}),(0,r.jsx)("p",{style:{marginBottom:"12px",fontSize:"13px",color:"#757575"},children:"Cliquez sur l'image pour définir le point focal utilisé lors du recadrage automatique."}),(0,r.jsx)(t.FocalPointPicker,{url:n,value:i,onChange:e=>{d({meta:{thumbnail_focal_point:e}})}}),(0,r.jsxs)("p",{style:{marginTop:"12px",fontSize:"12px",color:"#757575"},children:["Position :"," ",(0,r.jsxs)("strong",{style:{color:"#2271b1"},children:[Math.round(100*i.x),"% / ",Math.round(100*i.y),"%"]})]})]}):null};function i(){const t=document.querySelector('.editor-post-featured-image, [aria-label="Featured image"]');if(!t)return!1;if(!t.querySelector("img"))return!1;let o=document.getElementById("gutenberg-focal-point-inline-root");return o||(o=document.createElement("div"),o.id="gutenberg-focal-point-inline-root",t.appendChild(o)),(0,e.render)((0,r.jsx)(n,{}),o),!0}const d=new MutationObserver(()=>{i()});window.addEventListener("DOMContentLoaded",()=>{setTimeout(()=>{i()&&document.querySelector(".editor-styles-wrapper, .edit-post-visual-editor")&&d.observe(document.body,{childList:!0,subtree:!0})},500)});let l=0;const a=setInterval(()=>{(i()||l>10)&&clearInterval(a),l++},500)})();
|
||||
161
plugins/dynamiques-thumbnail-focal-point/example-usage.php
Normal file
161
plugins/dynamiques-thumbnail-focal-point/example-usage.php
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Exemples d'utilisation du plugin Focal Point
|
||||
*
|
||||
* Ces exemples peuvent être utilisés dans vos templates WordPress
|
||||
*/
|
||||
|
||||
// ============================================
|
||||
// EXEMPLE 1 : Utiliser object-position avec la thumbnail
|
||||
// ============================================
|
||||
?>
|
||||
|
||||
<!-- Dans votre template (ex: single.php, archive.php, etc.) -->
|
||||
<article class="post-card">
|
||||
<?php if (has_post_thumbnail()): ?>
|
||||
<div class="post-thumbnail">
|
||||
<?php
|
||||
$focal_position = get_thumbnail_focal_point_css();
|
||||
the_post_thumbnail('large', [
|
||||
'style' => 'width: 100%; height: 300px; object-fit: cover; object-position: ' . esc_attr($focal_position) . ';'
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h2><?php the_title(); ?></h2>
|
||||
<div class="excerpt"><?php the_excerpt(); ?></div>
|
||||
</article>
|
||||
|
||||
<?php
|
||||
// ============================================
|
||||
// EXEMPLE 2 : Utiliser background-position
|
||||
// ============================================
|
||||
?>
|
||||
|
||||
<div class="hero-banner" style="
|
||||
background-image: url(<?php echo esc_url(get_the_post_thumbnail_url(null, 'full')); ?>);
|
||||
background-size: cover;
|
||||
background-position: <?php echo esc_attr(get_thumbnail_focal_point_css()); ?>;
|
||||
min-height: 400px;
|
||||
">
|
||||
<h1><?php the_title(); ?></h1>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// ============================================
|
||||
// EXEMPLE 3 : CSS externe avec variable personnalisée
|
||||
// ============================================
|
||||
$focal_point = get_thumbnail_focal_point();
|
||||
?>
|
||||
|
||||
<div class="custom-image" style="
|
||||
--focal-x: <?php echo esc_attr($focal_point['x'] * 100); ?>%;
|
||||
--focal-y: <?php echo esc_attr($focal_point['y'] * 100); ?>%;
|
||||
">
|
||||
<?php the_post_thumbnail('large'); ?>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.custom-image img {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
object-fit: cover;
|
||||
object-position: var(--focal-x) var(--focal-y);
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
// ============================================
|
||||
// EXEMPLE 4 : Utilisation dans une boucle WP_Query
|
||||
// ============================================
|
||||
$query = new WP_Query([
|
||||
'post_type' => 'post',
|
||||
'posts_per_page' => 6
|
||||
]);
|
||||
|
||||
if ($query->have_posts()):
|
||||
while ($query->have_posts()): $query->the_post();
|
||||
?>
|
||||
<div class="grid-item">
|
||||
<?php
|
||||
$focal_position = get_thumbnail_focal_point_css(get_the_ID());
|
||||
if (has_post_thumbnail()):
|
||||
?>
|
||||
<div class="item-image">
|
||||
<?php
|
||||
the_post_thumbnail('medium', [
|
||||
'style' => 'width: 100%; height: 200px; object-fit: cover; object-position: ' . esc_attr($focal_position) . ';'
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<h3><?php the_title(); ?></h3>
|
||||
</div>
|
||||
<?php
|
||||
endwhile;
|
||||
wp_reset_postdata();
|
||||
endif;
|
||||
|
||||
// ============================================
|
||||
// EXEMPLE 5 : Avec ACF Repeater
|
||||
// ============================================
|
||||
if (have_rows('articles_slider')):
|
||||
while (have_rows('articles_slider')): the_row();
|
||||
$post_object = get_sub_field('article');
|
||||
if ($post_object):
|
||||
$post_id = $post_object->ID;
|
||||
$focal_position = get_thumbnail_focal_point_css($post_id);
|
||||
?>
|
||||
<div class="slide">
|
||||
<?php
|
||||
echo get_the_post_thumbnail($post_id, 'large', [
|
||||
'style' => 'object-fit: cover; object-position: ' . esc_attr($focal_position) . ';'
|
||||
]);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
endwhile;
|
||||
endif;
|
||||
|
||||
// ============================================
|
||||
// EXEMPLE 6 : Classes CSS avec attributs data
|
||||
// ============================================
|
||||
$focal_point = get_thumbnail_focal_point();
|
||||
?>
|
||||
|
||||
<div
|
||||
class="responsive-image"
|
||||
data-focal-x="<?php echo esc_attr($focal_point['x']); ?>"
|
||||
data-focal-y="<?php echo esc_attr($focal_point['y']); ?>">
|
||||
<?php the_post_thumbnail('large'); ?>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.responsive-image {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 16/9;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.responsive-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
object-position:
|
||||
calc(var(--focal-x, 0.5) * 100%) calc(var(--focal-y, 0.5) * 100%);
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
// Appliquer les valeurs de focal point aux variables CSS
|
||||
document.querySelectorAll('.responsive-image').forEach(el => {
|
||||
const x = el.dataset.focalX || 0.5;
|
||||
const y = el.dataset.focalY || 0.5;
|
||||
el.style.setProperty('--focal-x', x);
|
||||
el.style.setProperty('--focal-y', y);
|
||||
});
|
||||
</script>
|
||||
208
plugins/dynamiques-thumbnail-focal-point/index.php
Normal file
208
plugins/dynamiques-thumbnail-focal-point/index.php
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Plugin Name: Dynamiques Focal Point
|
||||
* Description: Un plugin pour ajouter un point focal à l'image de la thumbnail
|
||||
* Author: Deligraph
|
||||
* Text Domain: dynamiques-thumbnail-focal-point
|
||||
*/
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
// Enregistrer les métadonnées pour les post types "revues" et "articles"
|
||||
add_action('init', function () {
|
||||
$supported_post_types = ['revues', 'articles'];
|
||||
|
||||
foreach ($supported_post_types as $post_type) {
|
||||
register_post_meta($post_type, 'thumbnail_focal_point', [
|
||||
'show_in_rest' => [
|
||||
'schema' => [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'x' => ['type' => 'number'],
|
||||
'y' => ['type' => 'number'],
|
||||
],
|
||||
],
|
||||
],
|
||||
'single' => true,
|
||||
'type' => 'object',
|
||||
'auth_callback' => function (): bool {
|
||||
return current_user_can('edit_posts');
|
||||
}
|
||||
]);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Obtenir le focal point d'un post
|
||||
*
|
||||
* @param int|null $post_id ID du post (null pour le post courant)
|
||||
* @return array Tableau avec 'x' et 'y' (valeurs entre 0 et 1)
|
||||
*/
|
||||
function get_thumbnail_focal_point($post_id = null)
|
||||
{
|
||||
if (!$post_id) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$focal_point = get_post_meta($post_id, 'thumbnail_focal_point', true);
|
||||
|
||||
// Valeurs par défaut (centre de l'image)
|
||||
if (!$focal_point || !is_array($focal_point)) {
|
||||
return ['x' => 0.5, 'y' => 0.5];
|
||||
}
|
||||
|
||||
return [
|
||||
'x' => isset($focal_point['x']) ? $focal_point['x'] : 0.5,
|
||||
'y' => isset($focal_point['y']) ? $focal_point['y'] : 0.5
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtenir le focal point formaté pour CSS
|
||||
*
|
||||
* @param int|null $post_id ID du post (null pour le post courant)
|
||||
* @return string Format "50% 50%" pour object-position ou background-position
|
||||
*/
|
||||
function get_thumbnail_focal_point_css($post_id = null)
|
||||
{
|
||||
$focal_point = get_thumbnail_focal_point($post_id);
|
||||
$x_percent = ($focal_point['x'] * 100);
|
||||
$y_percent = ($focal_point['y'] * 100);
|
||||
|
||||
return $x_percent . '% ' . $y_percent . '%';
|
||||
}
|
||||
|
||||
// Enqueue pour l'éditeur Gutenberg (pour "revues" et "articles")
|
||||
add_action('enqueue_block_editor_assets', function () {
|
||||
$screen = get_current_screen();
|
||||
$supported_post_types = ['revues', 'articles'];
|
||||
|
||||
if (!$screen || !in_array($screen->post_type, $supported_post_types)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$asset_file = include(plugin_dir_path(__FILE__) . 'build/index.asset.php');
|
||||
|
||||
wp_enqueue_script(
|
||||
'thumbnail-focal-point-panel',
|
||||
plugin_dir_url(__FILE__) . 'build/index.js',
|
||||
$asset_file['dependencies'],
|
||||
$asset_file['version'],
|
||||
true
|
||||
);
|
||||
|
||||
// Charger les styles personnalisés pour Gutenberg
|
||||
wp_enqueue_style(
|
||||
'thumbnail-focal-point-gutenberg-css',
|
||||
plugin_dir_url(__FILE__) . 'assets/focal-point-gutenberg.css',
|
||||
['wp-components'],
|
||||
'1.0.0'
|
||||
);
|
||||
|
||||
// Optionnel : Enqueue les styles si nécessaire
|
||||
if (file_exists(plugin_dir_path(__FILE__) . 'build/index.css')) {
|
||||
wp_enqueue_style(
|
||||
'thumbnail-focal-point-panel-style',
|
||||
plugin_dir_url(__FILE__) . 'build/index.css',
|
||||
[],
|
||||
$asset_file['version']
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// Enqueue pour l'éditeur classique (inline dans la meta box de thumbnail, pour "revues" et "articles")
|
||||
add_action('admin_enqueue_scripts', function ($hook) {
|
||||
// Seulement sur les pages d'édition de post
|
||||
if (!in_array($hook, ['post.php', 'post-new.php'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $post;
|
||||
if (!$post) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier que c'est un post type supporté
|
||||
$supported_post_types = ['revues', 'articles'];
|
||||
$post_type = get_post_type($post);
|
||||
if (!in_array($post_type, $supported_post_types)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Charger le fichier asset pour les dépendances
|
||||
$asset_file = include(plugin_dir_path(__FILE__) . 'build/focal-point-inline.asset.php');
|
||||
|
||||
wp_enqueue_script(
|
||||
'thumbnail-focal-point-inline',
|
||||
plugin_dir_url(__FILE__) . 'build/focal-point-inline.js',
|
||||
$asset_file['dependencies'],
|
||||
$asset_file['version'],
|
||||
true
|
||||
);
|
||||
|
||||
// Charger les styles des composants WordPress
|
||||
wp_enqueue_style('wp-components');
|
||||
|
||||
// Charger les styles personnalisés
|
||||
wp_enqueue_style(
|
||||
'thumbnail-focal-point-inline-css',
|
||||
plugin_dir_url(__FILE__) . 'assets/focal-point-inline.css',
|
||||
['wp-components'],
|
||||
'1.0.0'
|
||||
);
|
||||
|
||||
// Passer les données au JavaScript
|
||||
$focal_point = get_post_meta($post->ID, 'thumbnail_focal_point', true);
|
||||
$x = isset($focal_point['x']) ? $focal_point['x'] : 0.5;
|
||||
$y = isset($focal_point['y']) ? $focal_point['y'] : 0.5;
|
||||
|
||||
$thumbnail_id = get_post_thumbnail_id($post->ID);
|
||||
$thumbnail_url = $thumbnail_id ? wp_get_attachment_image_url($thumbnail_id, 'large') : '';
|
||||
|
||||
wp_localize_script('thumbnail-focal-point-inline', 'thumbnailFocalPointData', [
|
||||
'postId' => $post->ID,
|
||||
'thumbnailUrl' => $thumbnail_url,
|
||||
'focalPointX' => $x,
|
||||
'focalPointY' => $y,
|
||||
'nonce' => wp_create_nonce('thumbnail_focal_point_save')
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
// Sauvegarder les données de la meta box
|
||||
add_action('save_post', function ($post_id) {
|
||||
// Vérifications de sécurité
|
||||
if (!isset($_POST['thumbnail_focal_point_nonce'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wp_verify_nonce($_POST['thumbnail_focal_point_nonce'], 'thumbnail_focal_point_save')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!current_user_can('edit_post', $post_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Sauvegarder les données
|
||||
if (isset($_POST['thumbnail_focal_point_x']) && isset($_POST['thumbnail_focal_point_y'])) {
|
||||
$x = floatval($_POST['thumbnail_focal_point_x']);
|
||||
$y = floatval($_POST['thumbnail_focal_point_y']);
|
||||
|
||||
// S'assurer que les valeurs sont entre 0 et 1
|
||||
$x = max(0, min(1, $x));
|
||||
$y = max(0, min(1, $y));
|
||||
|
||||
update_post_meta($post_id, 'thumbnail_focal_point', [
|
||||
'x' => $x,
|
||||
'y' => $y
|
||||
]);
|
||||
}
|
||||
});
|
||||
20857
plugins/dynamiques-thumbnail-focal-point/package-lock.json
generated
Normal file
20857
plugins/dynamiques-thumbnail-focal-point/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
14
plugins/dynamiques-thumbnail-focal-point/package.json
Normal file
14
plugins/dynamiques-thumbnail-focal-point/package.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "dynamiques-thumbnail-focal-point",
|
||||
"version": "1.0.0",
|
||||
"description": "Un plugin pour ajouter un point focal à l'image de la thumbnail",
|
||||
"scripts": {
|
||||
"build": "wp-scripts build",
|
||||
"start": "wp-scripts start",
|
||||
"lint:js": "wp-scripts lint-js",
|
||||
"format:js": "wp-scripts format-js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@wordpress/scripts": "^30.24.0"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
import { render, useState, useEffect } from "@wordpress/element";
|
||||
import { FocalPointPicker } from "@wordpress/components";
|
||||
import apiFetch from "@wordpress/api-fetch";
|
||||
|
||||
const InlineFocalPointPicker = ({ postId, thumbnailUrl, initialFocalPoint }) => {
|
||||
const [focalPoint, setFocalPoint] = useState(initialFocalPoint);
|
||||
|
||||
// Mettre à jour les champs cachés pour la sauvegarde
|
||||
useEffect(() => {
|
||||
// Créer ou mettre à jour les champs cachés
|
||||
let inputX = document.getElementById("thumbnail_focal_point_x");
|
||||
let inputY = document.getElementById("thumbnail_focal_point_y");
|
||||
let inputNonce = document.getElementById("thumbnail_focal_point_nonce");
|
||||
|
||||
if (!inputX) {
|
||||
inputX = document.createElement("input");
|
||||
inputX.type = "hidden";
|
||||
inputX.name = "thumbnail_focal_point_x";
|
||||
inputX.id = "thumbnail_focal_point_x";
|
||||
document.querySelector("form#post").appendChild(inputX);
|
||||
}
|
||||
|
||||
if (!inputY) {
|
||||
inputY = document.createElement("input");
|
||||
inputY.type = "hidden";
|
||||
inputY.name = "thumbnail_focal_point_y";
|
||||
inputY.id = "thumbnail_focal_point_y";
|
||||
document.querySelector("form#post").appendChild(inputY);
|
||||
}
|
||||
|
||||
if (!inputNonce) {
|
||||
inputNonce = document.createElement("input");
|
||||
inputNonce.type = "hidden";
|
||||
inputNonce.name = "thumbnail_focal_point_nonce";
|
||||
inputNonce.id = "thumbnail_focal_point_nonce";
|
||||
inputNonce.value = window.thumbnailFocalPointData?.nonce || "";
|
||||
document.querySelector("form#post").appendChild(inputNonce);
|
||||
}
|
||||
|
||||
inputX.value = focalPoint.x;
|
||||
inputY.value = focalPoint.y;
|
||||
}, [focalPoint]);
|
||||
|
||||
const handleChange = (newFocalPoint) => {
|
||||
setFocalPoint(newFocalPoint);
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: "15px", paddingTop: "15px", borderTop: "1px solid #dcdcde" }}>
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<strong style={{ fontSize: "13px", color: "#1d2327" }}>Point focal de recadrage</strong>
|
||||
</div>
|
||||
<p style={{ marginBottom: "12px", fontSize: "12px", color: "#646970", marginTop: "8px" }}>
|
||||
Cliquez sur l'image pour définir le point focal utilisé lors du recadrage.
|
||||
</p>
|
||||
<div style={{ marginBottom: "10px" }}>
|
||||
<FocalPointPicker url={thumbnailUrl} value={focalPoint} onChange={handleChange} />
|
||||
</div>
|
||||
<p style={{ fontSize: "12px", color: "#646970", marginTop: "8px" }}>
|
||||
Position :{" "}
|
||||
<strong style={{ color: "#2271b1" }}>
|
||||
{Math.round(focalPoint.x * 100)}% / {Math.round(focalPoint.y * 100)}%
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Fonction pour injecter le focal point picker dans la meta box de thumbnail
|
||||
function injectFocalPointPicker() {
|
||||
// Attendre que la meta box de thumbnail soit chargée
|
||||
const thumbnailDiv = document.getElementById("postimagediv");
|
||||
|
||||
if (!thumbnailDiv) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Chercher le lien de la thumbnail pour vérifier qu'il y a une image
|
||||
const thumbnailLink = thumbnailDiv.querySelector("#set-post-thumbnail");
|
||||
|
||||
if (!thumbnailLink || !window.thumbnailFocalPointData) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vérifier s'il y a une image
|
||||
const hasImage = thumbnailLink.querySelector("img");
|
||||
|
||||
if (!hasImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Créer le conteneur pour notre composant React
|
||||
let container = document.getElementById("thumbnail-focal-point-inline-root");
|
||||
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = "thumbnail-focal-point-inline-root";
|
||||
|
||||
// Trouver la div inside qui contient le contenu
|
||||
const insideDiv = thumbnailDiv.querySelector(".inside");
|
||||
|
||||
if (insideDiv) {
|
||||
// Injecter après tous les enfants existants de .inside
|
||||
insideDiv.appendChild(container);
|
||||
} else {
|
||||
// Fallback : injecter directement dans postimagediv
|
||||
thumbnailDiv.appendChild(container);
|
||||
}
|
||||
}
|
||||
|
||||
const { postId, thumbnailUrl, focalPointX, focalPointY } = window.thumbnailFocalPointData;
|
||||
|
||||
// Render le composant React
|
||||
render(
|
||||
<InlineFocalPointPicker
|
||||
postId={postId}
|
||||
thumbnailUrl={thumbnailUrl}
|
||||
initialFocalPoint={{ x: focalPointX, y: focalPointY }}
|
||||
/>,
|
||||
container
|
||||
);
|
||||
}
|
||||
|
||||
// Initialiser quand le DOM est prêt
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
injectFocalPointPicker();
|
||||
|
||||
// Écouter l'événement AJAX de WordPress pour le changement de featured image
|
||||
if (typeof jQuery !== "undefined") {
|
||||
jQuery(document).on("ajaxSuccess", function (event, xhr, settings) {
|
||||
// Vérifier si c'est l'AJAX de set featured image
|
||||
if (
|
||||
settings.data &&
|
||||
typeof settings.data === "string" &&
|
||||
settings.data.indexOf("action=set-post-thumbnail") !== -1
|
||||
) {
|
||||
// WordPress a sauvegardé la nouvelle thumbnail, on peut recharger
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 300);
|
||||
}
|
||||
});
|
||||
|
||||
// Écouter aussi la suppression de thumbnail
|
||||
jQuery(document).on("click", "#remove-post-thumbnail", function () {
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Hook dans la media library pour détecter quand une image est sélectionnée
|
||||
if (typeof wp !== "undefined" && wp.media) {
|
||||
// Stocker la référence du frame original
|
||||
const originalFeaturedImage = wp.media.featuredImage;
|
||||
|
||||
if (originalFeaturedImage && originalFeaturedImage.frame) {
|
||||
const originalFrame = originalFeaturedImage.frame;
|
||||
|
||||
// Remplacer la méthode frame
|
||||
wp.media.featuredImage.frame = function () {
|
||||
if (this._frame) return this._frame;
|
||||
|
||||
this._frame = originalFrame.apply(this, arguments);
|
||||
|
||||
// Écouter la sélection dans le frame
|
||||
this._frame.on("select", function () {
|
||||
// L'utilisateur a sélectionné une image
|
||||
// Ne rien faire ici, on attend l'AJAX success
|
||||
});
|
||||
|
||||
return this._frame;
|
||||
};
|
||||
}
|
||||
}
|
||||
1
plugins/dynamiques-thumbnail-focal-point/src/index.js
Normal file
1
plugins/dynamiques-thumbnail-focal-point/src/index.js
Normal file
|
|
@ -0,0 +1 @@
|
|||
import "./thumbnail-focal-point";
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
import { render, useState, useEffect } from "@wordpress/element";
|
||||
import { FocalPointPicker } from "@wordpress/components";
|
||||
import { useSelect, useDispatch } from "@wordpress/data";
|
||||
|
||||
const InlineGutenbergFocalPointPicker = () => {
|
||||
// Récupérer l'ID et l'URL de l'image mise en avant
|
||||
const { featuredImageId, featuredImageUrl, focalPoint } = useSelect((select) => {
|
||||
const featuredMedia = select("core/editor").getEditedPostAttribute("featured_media");
|
||||
const media = featuredMedia ? select("core").getMedia(featuredMedia) : null;
|
||||
const meta = select("core/editor").getEditedPostAttribute("meta");
|
||||
|
||||
return {
|
||||
featuredImageId: featuredMedia,
|
||||
featuredImageUrl: media?.source_url || null,
|
||||
focalPoint: meta?.thumbnail_focal_point || { x: 0.5, y: 0.5 },
|
||||
};
|
||||
});
|
||||
|
||||
const { editPost } = useDispatch("core/editor");
|
||||
|
||||
// Ne rien afficher si pas d'image mise en avant
|
||||
if (!featuredImageId || !featuredImageUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ marginTop: "16px", paddingTop: "16px", borderTop: "1px solid #ddd" }}>
|
||||
<div style={{ marginBottom: "12px" }}>
|
||||
<strong style={{ fontSize: "13px", color: "#1e1e1e" }}>Point focal de recadrage</strong>
|
||||
</div>
|
||||
<p style={{ marginBottom: "12px", fontSize: "13px", color: "#757575" }}>
|
||||
Cliquez sur l'image pour définir le point focal utilisé lors du recadrage automatique.
|
||||
</p>
|
||||
<FocalPointPicker
|
||||
url={featuredImageUrl}
|
||||
value={focalPoint}
|
||||
onChange={(value) => {
|
||||
editPost({
|
||||
meta: {
|
||||
thumbnail_focal_point: value,
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
<p style={{ marginTop: "12px", fontSize: "12px", color: "#757575" }}>
|
||||
Position :{" "}
|
||||
<strong style={{ color: "#2271b1" }}>
|
||||
{Math.round(focalPoint.x * 100)}% / {Math.round(focalPoint.y * 100)}%
|
||||
</strong>
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// Fonction pour injecter le focal point picker dans le panneau de featured image
|
||||
function injectGutenbergFocalPointPicker() {
|
||||
// Chercher le panneau de featured image
|
||||
const featuredImagePanel = document.querySelector('.editor-post-featured-image, [aria-label="Featured image"]');
|
||||
|
||||
if (!featuredImagePanel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Vérifier qu'il y a une image
|
||||
const hasImage = featuredImagePanel.querySelector("img");
|
||||
if (!hasImage) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Créer le conteneur s'il n'existe pas
|
||||
let container = document.getElementById("gutenberg-focal-point-inline-root");
|
||||
|
||||
if (!container) {
|
||||
container = document.createElement("div");
|
||||
container.id = "gutenberg-focal-point-inline-root";
|
||||
featuredImagePanel.appendChild(container);
|
||||
}
|
||||
|
||||
// Render le composant React
|
||||
render(<InlineGutenbergFocalPointPicker />, container);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Observer pour détecter quand le panneau de featured image est ajouté/modifié
|
||||
const observer = new MutationObserver(() => {
|
||||
injectGutenbergFocalPointPicker();
|
||||
});
|
||||
|
||||
// Démarrer l'observation quand le DOM est prêt
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
// Essayer d'injecter immédiatement
|
||||
setTimeout(() => {
|
||||
if (injectGutenbergFocalPointPicker()) {
|
||||
// Si réussi, continuer à observer pour les changements
|
||||
const editorRoot = document.querySelector(".editor-styles-wrapper, .edit-post-visual-editor");
|
||||
if (editorRoot) {
|
||||
observer.observe(document.body, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
|
||||
// Réessayer périodiquement pendant les premières secondes
|
||||
let retryCount = 0;
|
||||
const retryInterval = setInterval(() => {
|
||||
if (injectGutenbergFocalPointPicker() || retryCount > 10) {
|
||||
clearInterval(retryInterval);
|
||||
}
|
||||
retryCount++;
|
||||
}, 500);
|
||||
10
plugins/dynamiques-thumbnail-focal-point/webpack.config.js
Normal file
10
plugins/dynamiques-thumbnail-focal-point/webpack.config.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
const defaultConfig = require("@wordpress/scripts/config/webpack.config");
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
...defaultConfig,
|
||||
entry: {
|
||||
index: path.resolve(process.cwd(), "src", "index.js"),
|
||||
"focal-point-inline": path.resolve(process.cwd(), "src", "focal-point-inline.js"),
|
||||
},
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user