J'essaie de résoudre ce problème depuis plus d'un an et j'ai essayé de nombreuses façons et je n'ai pas réussi à le faire fonctionner. J'apprécierais vraiment si quelqu'un pouvait m'aider avec ça. Voici ce que j'essaie de faire ...
Je dois créer 15 métaboxes personnalisés pour l'écran d'écriture sur mon type d'article personnalisé pour les diaporamas (lom_slideshow). Chaque metabox sera le même, à l'exception du nombre de diapositives (par exemple, diapositive 1, diapositive 2 ...). Je voudrais que les métaboxes sauvegardent chaque champ dans le champ personnalisé séparé.
Voici les champs qui doivent être dans chaque metabox:
La diapositive 2 sera la même, mais toutes les valeurs de champ personnalisées seront ajoutées avec "slide2-" au lieu de "slide1-"
La seule autre considération à prendre en compte est que j'aimerais qu'ils soient dans la colonne de contenu principale et visibles uniquement dans mon type de publication personnalisé Diaporama (lom_slideshow).
Comme je l'ai dit, j'ai essayé ce nombre de fois et je n'ai jamais réussi. Je me suis rapproché par le passé et j'ai réussi à faire fonctionner le tout, sauf que je ne pouvais pas afficher plusieurs instances du WYSIWYG sur la page. Je n'ai plus ce code parce que je l'ai changé plusieurs fois depuis. J'ai finalement décidé d'utiliser le plugin More Fields pour le faire à la place de mon propre code et de le tester avec 5 méta-boîtes pour le développement, mais lorsque j'ai essayé de l'implémenter avec les 15 boîtes, j'avais besoin du plugin qui ravageait mes tables de base de données. Je ne veux vraiment pas un autre plugin.
Je cherche en fait quelqu'un pour me dire simplement comment le coder. Je n'ai pas besoin de liens vers des didacticiels, car je suis convaincu de les avoir tous essayés, à moins qu'ils ne soient publiés au cours de la dernière heure environ.
Voici un peu ce que j’essayais au départ d’aider: Créer un diaporama avec un type de message personnalisé avec des méta-boîtes personnalisées?
EAMann m'a fourni une réponse très complète, mais c'était en dehors de mes compétences et je ne pouvais pas le mettre en œuvre. J’ai simplifié ma demande jusqu’à cette question dans l’espoir d’en finir avec cela.
Pour résoudre des problèmes complexes, il existe une sorte d’approche normalisée/bien connue: divisez votre problème complexe en un ensemble de problèmes plus petits. Les petits problèmes sont plus faciles à résoudre. Si vous avez résolu chaque petit problème, vous avez déjà le plus souvent déjà résolu votre problème complexe.
Jusqu'ici pour la théorie. Vérifions vos besoins. J'aligne dans mes propres mots ce que vous avez décrit ci-dessus:
Alors, comment coder ça? Je pense que la partie la plus importante est qu'avant de commencer à coder, vous décidez de ce que vous voulez vraiment réaliser et de la manière de diviser le problème en parties plus petites. La liste ci-dessus n'est peut-être pas complète, c'est simplement ce que je pourrais lire de votre question. Et le format est assez peu spécifique. C'est juste plus ou moins une répétition de ce que vous avez écrit mais un peu ordonné en points simples.
Alors, vérifiez si ce sont vos besoins et étendez cette liste à tout ce que vous jugez utile.
Une fois terminé, la prochaine étape consiste à voir comment ces éléments nécessaires pourraient être exprimés en mots simples et en tant que liste des fonctionnalités de votre plugin.
Semble assez simple maintenant, non? J'ai probablement manqué quelque chose ici, alors vérifiez bien avant de continuer. Comme écrit, avant de commencer à coder, décidez-vous simplement en termes simples. Ne pensez même pas quelles parties posent problème et lesquelles ne le sont pas, ou comment coder des détails tels que la dénomination d'éléments HTML Input. Je sais que c'est difficile si vous essayez déjà depuis si longtemps de tout recommencer à zéro, car de nombreuses idées vous reviennent.
Prenez un crayon et du papier. Cela aide souvent à prendre une décision.
Comme vous pouvez le constater, je n’ai pas précisé ici la nécessité d’un Metabox ou d’un type de message personnalisé. Il est trop spécifique d’apprendre d’abord sur les parties de votre problème. Metabox ou Custom Post Type est très concret, il est peut-être déjà possible de coder le plugin. J'ai donc gardé cela pour le moment et j'ai essayé de décrire brièvement mais précisément les besoins. Le Metabox ou similaire est quelque chose qui pourrait jouer un rôle dans la conception. Voyons voir.
Une fois que vous savez ce que vous souhaitez/souhaitez réaliser, vous pouvez décider de la conception du plug-in. Cela pourrait être fait en dessinant une petite image. Identifiez simplement les composants de votre liste de fonctionnalités et définissez-les les uns par rapport aux autres. Comme vous pouvez le constater, vous n’avez pas besoin de faire de beaux arts;):
Excusez ma mauvaise écriture, j'espère que cela peut être lu. Dans tous les cas, vous pouvez créer votre propre image, ceci n'est qu'un exemple. Les dessins peuvent varier, donc si vous ne le dessiniez pas de la même manière, c'est tout à fait normal.
J'aime faire le début de l'étape de conception sur papier car cela aide à avoir une meilleure vue d'ensemble du problème et c'est beaucoup plus rapide sur papier que sur ordinateur.
Vous pouvez donc maintenant comparer votre liste avec votre conception et vérifier si toutes les caractéristiques de la liste sont couvertes par les parties que vous avez dans la conception. Ma liste et mon image sont bonnes jusqu'à présent. Je continue donc, mais ne sautez pas cette étape. Sinon, vous ne savez pas si vous avez oublié quelque chose. Et comme vous commencez à coder, il est beaucoup plus difficile de changer quelque chose qui est déjà codé qu'une image ou une liste.
Maintenant, ce plugin devient plus concret dans l'esprit. Après un peu de conception, c'est probablement le bon moment pour commencer à coder. Comme nous avons la liste en haut, je pourrais passer en revue et réfléchir à chaque point séparément et procéder à un recoupement avec la conception afin que je sache comment les parties sont en relation les unes avec les autres.
Parce que si chaque partie est terminée, le plugin est prêt sans avoir à se décider en une seule fois, ce qui était le problème initial.
Je fais un peu de codage dans le style des commentaires et quelques exemples de code. C'est une première idée d'implémentation et le code n'a pas été testé. C'est juste pour me salir les mains et pour que vous ayez probablement un exemple illustrant comment - mais non obligé - cela peut être écrit. J'ai tendance à être trop spécifique parfois, alors faites attention à moi. Lorsque j'écris du code, je le réécris assez souvent lors de sa création, mais je ne peux pas le rendre visible lors de la création de l'exemple de code. Alors gardez cela à l'esprit. Si vous voyez quelque chose à faire plus simplement, choisissez votre itinéraire. Vous devez modifier et étendre votre code ultérieurement, il ne s'agit donc que d'un exemple de code.
Juste une classe qui gère les opérations de base, comme l’enregistrement de points d’accroché et la fourniture au diaporama de ses diapositives et des métaboxes pour l’éditeur. C'est ici que tout commence. Les plugins sont démarrés à un seul point de code. J'appelle ça bootstrap:
<?php
/** Plugin Headers ... */
return SlideshowPlugin::bootstrap();
class SlideshowPlugin {
/** @var Slideshow */
private $slideshow;
/** @var SlideshowMetaboxes */
private $metaboxes;
/** @var SlideshowPlugin */
static $instance;
static public function bootstrap() {
$pluginNeeded = (is_admin() && /* more checks based your needs */ );
if (!$pluginNeeded)
return;
}
if (NULL === self::$instance) {
// only load the plugin code while it's really needed:
require_once('library/Slideshow.php');
require_once('library/SlideshowSlide.php');
require_once('library/Store.php');
require_once('library/Metaboxes.php');
require_once('library/Metabox.php');
require_once('library/Form.php');
// ...
self::$instance = new SlideshowPlugin();
}
return self::$instance;
}
private function addAction($action, $parameters = 0, $priority = 10) {
$callback = array($this, $action);
if (!is_callable($callback)) {
throw new InvalidArgumentExeception(sprintf('Plugin %s does not supports the %s action.', __CLASS__, $action));
}
add_action($action, $callback, $parameters, $priority);
}
public function __construct() {
$this->addAction('admin_init');
}
/**
* @return bool
*/
private function isEditorRequest() {
// return if or not the request is the editor page
}
/**
* @-wp-hook
*/
public function admin_init() {
// register anything based on custom post type and location in the admin.
// I don't care about the details with CPT right now.
// It's just that editorAction is called when we're on the slideshow
// editor page:
if ($this->isEditorRequest()) {
$this->editorAction();
}
}
private function getPostID() {
// ... code goes here to get post id for request
return $postID;
}
private function getSlideshow() {
is_null($this->slideshow)
&& ($postID = $this->getPostID())
&& $slideshow = new Slideshow($postID)
;
return $slideshow;
}
private function getMetaboxes() {
is_null($this->metaboxes)
&& ($slideshow = $this->getSlideshow())
&& $this->metaboxes = new SlideshowMetaboxes($slideshow)
;
return $this->metaboxes;
}
private function editorAction() {
$metaboxes = $this->getMetaboxes();
}
}
Donc, cette classe de plugins est déjà assez complète. Je n'ai pas précisé comment récupérer le postID, mais il est déjà encapsulé dans une fonction propre. À côté de cela, je n'ai pas codé pour vérifier si c'était la bonne page pour afficher l'éditeur, mais il y a déjà du code de raccord pour cela.
À la fin, la méthode editorAction () est appelée si la demande se trouve sur la page de l'éditeur de type de publication personnalisée et dans laquelle les métaboxes sont acquis. C'est tout. Le plugin devrait être assez complet maintenant. Il a le diaporama et prend soin des metaboxes. Par rapport au design, ce sont les parties qui sont liées au plugin. Comparez avec l'image:
Semble complet. Travail fait sur cette partie.
Un diaporama est 1: 1 mappé à un post. Donc, il faut avoir le Post ID. Le diaporama peut gérer la conservation des données, il s’agit donc essentiellement d’un type de données. Il stocke toutes les valeurs dont vous avez besoin. C'est un type de donnéescompounddans le sens où il consiste en 0 à N diapositives. Une diapositive est à nouveau un autre type de données qui contient les informations pour chaque diapositive.
La diapositive est alors utilisée par un metabox et probablement une forme.
J'ai également choisi de mettre en œuvre le stockage et la récupération des données du diaporama dans ces types de données (la zoneStoredans la conception). C'est en quelque sorte sale car il mélange des types de données et des objets réels.
Mais comme le magasin est connecté au diaporama et aux diapositivesseulementdans la conception, je les ai connectés les uns aux autres. Probablement trop proche pour l'avenir, mais pour une première mise en œuvre, je pense que c'est une approche valable pour le moment. Comme il s’agit de la première approche, il ne faudra pas beaucoup de temps après sa refactorisation, alors même avec certains problèmes, je suis assez confiant que la direction est la bonne:
class SlideshowSlide {
private $slideshow;
private $index;
public $number, $hide, $type, $title, $image, $wysiwyg, $embed
public function __construct($slideshow, $index) {
$this->slideshow = $slideshow;
$this->index = $index;
}
public function getSlideshow() { return $this->slideshow; }
public function getIndex() { return $this->index; }
}
class Slideshow implements Countable, OuterIterator {
private $postID;
private $slides = array();
private function loadSlidesCount() {
$postID = $this->postID;
// implement the loading of the count of slides here
}
private function loadSlide($index) {
$postID = $this->postID;
// implement the loading of slide data here
$data = ... ;
$slide = new SlideshowSlide($this, $index);
$slide->setData($data); // however this is done.
return $slide;
}
private function loadSlides() {
$count = $this->loadSlidesCount();
$slides = array();
$index = 0;
while(($index < $count) && ($slide = $this->loadSlide($index++)))
FALSE === $slide || $slides[] = $slide
;
$this->slides = $slides;
}
public function __construct($postID) {
$this->postID = $postID;
$this->loadSlides();
}
public function count() {
return count($this->slides);
}
public function getInnerIterator() {
return new ArrayIterator($this->slides);
}
private function touchIndex($index) {
$index = (int) $index;
if ($index < 0 || $index >= count($this->slides) {
throw new InvalidArgumentExpression(sprintf('Invalid index %d.', $index));
}
return $index;
}
public function getSlide($index) {
$index = $this->touchIndex($index);
return $this->slides[$index];
}
}
Les classes Slideshow et Slide sont également assez complètes mais manquent également de code. C'est juste pour montrer mon idée d'avoir les propriétés/méthodes et quelques éléments de manipulation ainsi que la manière dont la récupération de données pourrait être implémentée.
Le Metabox doit savoir quelle diapositive il représente. Il faut donc connaître le diaporama et la diapositive concrète. Le diaporama peut être fourni par le plug-in, la diapositive peut être représentée par l'index (par exemple 0 ... N où N est le nombre de diapositives dans le diaporama - 1).
class Metabox {
public function __construct(SlideshowSlide $slide) {
}
}
La classe Metabox étend en quelque sorte la classe de plugin. Il fait aussi une partie du travail qui pourrait être fait par la classe plugin, mais comme je voulais l'avoir représenter la diapositive dans le contexte du plugin tout en pouvant avoir plusieurs instances, j'ai choisi cette façon.
La Metabox doit maintenant gérer la logique de requête: elle représente une Metabox qui est en quelque sorte sortie mais qui est également entrée car elle doit gérer la saisie de formulaire.
La bonne chose à faire est que les détails ne sont pas traités car les sorties et les entrées de formulaire sont effectuées par les objets de formulaire.
Donc probablement si j'avais codé cette classe jusqu'à la fin, je l'aurais complètement enlevée. Je ne sais pas maintenant. Pour le moment, il représente le Metabox sur la page de l'éditeur pour une diapositive spécifique.
class Metaboxes
private $slideshow;
private $boxes;
public function __construct(Slideshow $slideshow) {
$this->slideshow = $slideshow;
$this->editorAction();
}
private function createMetaboxes() {
$slides = $this->slideshow;
$boxes = array();
foreach($slides as $slide) {
$boxes[] = new Metabox($slide);
}
$this->boxes = $boxes;
}
private function editorAction() {
$this->createMetaboxes();
}
J'ai seulement écrit un peu de code ici jusqu'à présent. La classe Metaboxes agit en tant que gestionnaire pour tous les métaboxes. Le représentant du diaporama en tant que Metabox représente une diapositive.
Ce code de remplacement ne fait pas beaucoup mais instancie un Metabox par diapositive. Il peut et doit faire plus à la fin.
Vous voudrez peut-être utiliser le Composite Pattern ici, donc effectuer une action sur un objet Metaboxes fera la même action sur chaque Metabox qu'il transporte. Comparable à l'instanciation, où il crée de nouveaux Metabox. Il n'est donc pas nécessaire de traiter ultérieurement avec chaque Metabox, mais uniquement avec l'objet Metabox. Juste une idée.
Le formulaire est probablement la chose la plus complexe que vous ayez pour gérer les éléments et les lignes de code. Il doit résumer vos données pour pouvoir être traitées via le navigateur. Donc, il doit être capable de gérer plusieurs instances. Vous pouvez y parvenir en préfixant les noms des éléments de formulaire (car ils doivent être uniques) avec un préfixe genreal (par exemple, "slide"), puis un identifiant (l'index de la diapositive, je le nomme ici comme vous voulez pouvoir changer le numéro, par exemple, pour avoir une clé de tri), puis l'identificateur de la valeur réelle (par exemple, "numéro" ou "masquer").
Voyons voir: un formulaire connaît son préfixe, son numéro et tous les champs qu'il contient. Cela correspond assez bien aux types de données Slideshow et Slide mentionnés ci-dessus. Quelques petits codes:
/**
* SlideForm
*
* Draw a Form based on Slide Data and a Form definition. Process it's Input.
*/
class SlideForm {
/** @var Slide */
private $slide;
private $prefix = 'slide';
public function __construct(Slide $slide) {
$this->slide = $slide;
}
private function inputNamePrefix() {
$index = $this->slide->getIndex();
$prefix = $this->prefix;
return sprintf('%s-%d-', $prefix, $index);
}
private function inputName($name) {
return $this->inputNamePrefix().$name;
}
private function printInput(array $element) {
list($type, $parameters) = $element;
$function = 'printInput'.$type;
$callback = array($this, $function)
call_user_func_array($callback, $parameters);
}
private function printInputText($value, $name, $label, $size = 4) {
$inputName = $this->inputName($name);
?>
<label for="<?php echo $inputName ; ?>">
<?php echo htmlspecialchars($label); ?>:
</label>
<input type="text"
name="<?php echo $inputName; ?>"
size="<?php echo $size; ?>"
value="<?php echo htmlspecialchars($value); ?>">
<?php
}
private function printInputCheckbox($value, $name, $label, ... ) { ... }
private function printInputRadio($value, $name, $label, ... ) { ... }
private function printInputImage($value, $name, $label, ... ) { ... }
private function printInputWysiwyg($value, $name, $label, ... ) { ... }
private function printInputTextarea($value, $name, $label, ... ) { ... }
// ...
private function mapSlideValueTo(array $element) {
$slide = $this->slide;
list($type, $parameters) = $element;
list($name) = $parameters;
$value = $slide->$name;
array_unshift($parameters, $value);
$element[1] = $parameters;
return $element;
}
/**
* @return array form definition
*/
private function getForm() {
// Form Definition
$form = array(
array(
'Text',
array(
'number', 'Number'
),
array(
'Checkbox',
array(
'hide', 'Display', 'Hide This Slide'
),
),
array(
'Radio',
array(
'type', 'Type', array('Image', 'Video')
),
),
array(
'Text',
array(
'title', 'Title', 16
),
),
// ...
);
return $form;
}
public function printFormHtml() {
$form = $this->getForm();
foreach($form as $element) {
$element = $this->mapSlideValueTo($element);
$this->printInput($element);
}
}
public function processFormElement($element) {
list($type, $parameters) = $element;
list($name) = $parameters;
$inputName = $this->inputName($name);
$map = array(
'Text' => 'String',
'Checkbox' => 'Checkbox',
'Radio' => 'Radio',
);
// I would need to continue to code there.
throw new Exception('Continue to code: Process Form Input based on Form Definition');
}
public function processForm() {
$form = $this->getForm();
foreach($form as $element) {
$this->processFormElement($element); // <- this function needs to be coded
}
}
// ...
}
Cette classe est assez grande maintenant car elle s’occupe de trois choses à la fois:
Il est plus sage de diviser cela en trois parties. Je vous laisse ça. Il montre déjà comment vous pouvez encapsuler la fonctionnalité de formulaire dans des tâches plus petites afin qu'il soit plus facile de répondre à vos besoins. Par exemple. dans le cas où la sortie de la forme de l'élément d'entrée d'image nécessite des ajustements, elle peut être facilement étendue/polie. Même chose pour WYSIWYG. Vous pouvez modifier l’implémentation ultérieurement car elle n’interférera pas beaucoup pour vos diaporamas et types de diapositives.
Le principe sous-jacent à cela s'appelle égalementSéparation des problèmes, et c’est à peu près comme cela que j’ai commencé ma réponse: divisez le problème en problèmes plus petits. Ces problèmes séparés sont plus faciles à résoudre.
J'espère que cela aide pour le moment. En fin de compte, je ne suis même pas revenu aux types de messages personnalisés. Je sais qu'ils doivent entrer dans le plugin, mais avec un nouveau design, il est probablement facile de trouver l'endroit où écrire le code.
Je sais que vous avez dit que vous ne vouliez pas d'un autre plug-in, mais je vous recommanderais de vérifier les "boîtes à méta Verve" ou les "modèles de champs personnalisés", ce dernier offrant de nombreuses options, mais verve possède une interface glisser-déposer agréable.
Pour ce qui est de votre problème de base de données, pouvez-vous expliquer pourquoi vous avez besoin de plusieurs champs wysiwyg et pourquoi cela affecte la base de données? J'ai utilisé plus de 40 champs personnalisés sur certaines pages et je n'ai constaté aucun problème.
En ce qui concerne le diaporama, j’ai fait quelque chose de similaire et j’ai dû écrire le mien en utilisant les types jquery et query_post. Par exemple, cela montre une publication aléatoire dans le curseur pour le type de publication personnalisée appelée "films". Vous pouvez ajouter des méta-valeurs personnalisées à l'aide de get_post_meta.
<?php $Rand_posts = query_posts('post_type=movies&posts_per_page=5&orderby=Rand');
foreach($Rand_posts as $post) :
?>