Entwicklung eines Wordpress-Such-Plugins - Best Practices

7

Auf der Suche nach einer Antwort auf meine Frage habe ich mich für diesen StackExchange registriert. :) :)

Meine Frage ist nicht einfach, deshalb muss ich ganz am Anfang beginnen. Aber um Ihnen eine Vorstellung davon zu geben, worum es in diesem Beitrag geht: Währenddessen funktioniert mein Plugin, aber der Code gefällt mir nicht. Ich denke, es gibt bessere Möglichkeiten, dies zu lösen, und deshalb suche ich nach WordPress-Ninjas, die mir mit guten Tipps und Best Practices helfen können. Ich versuche wirklich, in die Tiefen von WordPress einzudringen, aber es ist ziemlich schwierig. Vielen Dank im Voraus!


Was mein Plugin tun soll

Der Benutzer dieses Plugins sollte in der Lage sein, einen Shortcode zu verwenden, um ein Suchformular für bestimmte Beitragstypen anzuzeigen. Das Plugin wird nur auf den Seiten benötigt, die diesen Shortcode enthalten.

Die Beitragstypen werden über die Seite mit den Plugin-Einstellungen erstellt. Jeder Beitrag dieses Typs hat einen Titel, Inhalt und mehrere benutzerdefinierte Felder aus dem acf-Plugin. Für jeden Beitragstyp gibt es einen Shortcode. Das Suchformular enthält ein Feld zum Durchsuchen aller Beitragsfelder des angegebenen Beitragstyps. Die anderen beiden können verwendet werden, um die Ergebnisse durch zwei Schlüsselwörter zu begrenzen (z. B. den Speicherort, bei dem es sich um ein ACF-Feld handelt).

Die Ergebnisse werden über Ajax geladen und unter dem Suchformular angezeigt.


Was ich schon gemacht habe

Ich versuche diese Frage nicht zu groß zu halten. Ich spezifiziere also nicht jeden einzelnen Aspekt. Folgendes sollte gut funktionieren:

  • Erstellen Sie am Post-Typ in der PHP-Datei des Plugins. Im Moment ist ein statischer Beitragstyp ausreichend.
  • Erstellen Sie einen Shortcode, der das Suchformular und einen leeren Container für die Ergebnisse druckt.
  • Die Ajax-Anfrage funktioniert über Javascript und liefert die erwarteten Ergebnisse.

Benutzerdefinierte Felder durchsuchen

Das war ziemlich schwierig, aber ich habe ein funktionierendes Code-Snippet gefunden und verstehe, was es tut. Das Problem hierbei ist, dass ich nur ACF-Felder mit meinem spezifischen Suchformular durchsuchen möchte. Ich möchte die Suche auf der vorhandenen Website nicht berühren.

Zuerst habe ich versucht zu überprüfen, auf welcher Site sich der Benutzer befindet, und eine if-Anweisung mit is_page () verwendet, bevor ich die Suchabfrage ändere. Aber da ich Ajax benutze, scheint das hier bei mir nicht zu funktionieren ...

Meine Problemumgehung besteht darin, zu Beginn jeder Ajax-Suchabfrage eine globale Variable festzulegen. Jetzt überprüfe ich, ob diese Variable gesetzt ist, bevor ich die Suchabfrage ändere. Am Ende meiner Ajax-Funktion habe ich diese Variable auf false zurückgesetzt. Ja, ich denke, es gibt einen besseren Weg, dies zu lösen, aber ich weiß nicht wie ...

Die Funktionen, die meine Suchabfrage ändern, sind folgende:

/ **
 * Erweitern Sie die WordPress-Suche um benutzerdefinierte Felder
 * *
 * http://adambalee.com
 * /

/ **
 * Beiträge und Postmeta-Tabellen verbinden
 * *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_join
 * /
Funktion cf_search_join ($ join) {
    global $ wpdb;
    // $ cwlistpage = (is_page ('list'));

    globaler $ testcheck;
    $ cwlistpage = $ testcheck;

    if ($ cwlistpage) {    
        $ join. = 'LEFT JOIN'. $ wpdb-> postmeta. ' AUF '. $ wpdb-> Beiträge. '.ID ='. $ wpdb-> postmeta. '.post_id';
    }}

    return $ join;
}}
add_filter ('posts_join', 'cf_search_join');

/ **
 * Ändern Sie die Suchabfrage mit posts_where
 * *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_where
 * /
Funktion cf_search_where ($ where) {
    global $ pagenow, $ wpdb;
    // $ cwlistpage = (is_page ('list'));

    globaler $ testcheck;
    $ cwlistpage = $ testcheck;

    if ($ cwlistpage) {
        $ where = preg_replace (
            "/\(\s*".$wpdb->posts.".post_title\s+LIKE\s*(\'[^\'‹+\')\s*\)/",
            "(". $ wpdb-> posts. ". post_title LIKE $ 1) OR (". $ wpdb-> postmeta. ". meta_value LIKE $ 1)", $ where);
    }}

    return $ where;
}}
add_filter ('posts_where', 'cf_search_where');

/ **
 * Vermeiden Sie Duplikate
 * *
 * http://codex.wordpress.org/Plugin_API/Filter_Reference/posts_distinct
 * /
Funktion cf_search_distinct ($ where) {
    global $ wpdb;
    // $ cwlistpage = (is_page ('list'));

    globaler $ testcheck;
    $ cwlistpage = $ testcheck;

    if ($ cwlistpage) {
        return "DISTINCT";
    }}

    return $ where;
}}
add_filter ('posts_distinct', 'cf_search_distinct');

Begrenzen Sie die Ergebnisse durch benutzerdefinierte Felder

Alle Felder des Formulars sind optional. Ein leeres Formular gibt alle Beiträge dieses Beitragstyps zurück. Das erste Feld sollte jedes Feld der Beiträge nach dem Schlüsselwort durchsuchen. Das zweite und dritte Feld sollten die Ergebnisse auf das Feld beschränken, das dieses Schlüsselwort enthält. Ich habe das mit if-Anweisungen gelöst und weiß, dass es eine bessere Lösung geben muss.

/**
* Search with AJAX
*/
function cwlist_click_search() {
global $testcheck;
$testcheck = true;

$searchterm = $_POST['query'];
$searchlocation = $_POST['location'];
$searchdegree = $_POST['degree'];

// WP_Query arguments
$args = array (
    'post_type' => 'offers',
    'post_status' => 'publish',
    's' => $searchterm
);

$query = new WP_Query( $args );

ob_start();

// The Loop
if ( $query->have_posts() ) : ?>
  <br><br><p>
   <?php while ( $query->have_posts() ) : $query->the_post();
        if( ($searchlocation == NULL) || in_array(trim(strtolower($searchlocation)), array_map('strtolower', get_field('offer_location')))):
            if( ($searchdegree == NULL) || (trim(strtolower($searchdegree)) === strtolower(get_field('offer_degree')))):?>

     Titel: <?php the_title(); ?> <br>
     Abschluss: <?php the_field('offer_degree'); ?> <br>
     Ort: <?php the_field('offer_location'); ?> <br>
     Anbieter: <?php the_field('offer_provider'); ?> <br>
     <?php if(get_field('offer_subtitle')): ?>
     - <?php the_field('offer_subtitle'); ?> <br>
     <?php endif; ?>
     <br>

    <?php endif; endif; endwhile; ?>
    </p>
<?php else: ?>
    <!-- no posts found -->
    Keine Angebote gefunden
<?php endif;

// Restore original Post Data
wp_reset_postdata();

$content = ob_get_clean();

echo $content;
die();

$testcheck = false;
}
add_action( 'wp_ajax_nopriv_cwlist_click_search', 'cwlist_click_search' );
add_action( 'wp_ajax_cwlist_click_search', 'cwlist_click_search' );

WP Debug

Wenn ich das Plugin aktiviere, erscheinen auf der Startseite viele Zeilen wie die folgenden:

Hinweis: Es wird versucht, die Eigenschaft eines Nichtobjekts in C: \ Users \ CWalt \ Documents \ gitlab \ steuerazubi \ wordpress \ wp-Includes \ query.php in Zeile 4520 abzurufen. Hinweis: Es wird versucht, die Eigenschaft eines Nichtobjekts in C: \ abzurufen Benutzer \ CWalt \ Dokumente \ gitlab \ steuerazubi \ wordpress \ wp-includes \ query.php in Zeile 4522 Hinweis: Es wird versucht, die Eigenschaft eines Nichtobjekts in C: \ Benutzer \ CWalt \ Dokumente \ gitlab \ steuerazubi \ wordpress \ wp- abzurufen enthält \ query.php in Zeile 4524 ...

Ich habe das Debuggen aktiviert, um ein gutes Plugin zu erstellen. Was könnte ich möglicherweise falsch gemacht haben?


Weitere Beitragstypen

Kennen Sie einen guten Ansatz, mit dem der Benutzer über das WordPress-Backend mehr Beitragstypen angeben kann? Der Benutzer sollte in der Lage sein, verschiedene Suchseiten für verschiedene Beitragstypen über Shortcodes zu erstellen.


Vielen Dank für das Lesen. Ich bin dankbar für jeden kleinen Hinweis.

Christoph
quelle

Antworten:

1

Ich habe Ihren Beitrag vollständig durchgelesen, ich sehe sicherlich nichts besonders Falsches daran, aber es klingt für mich so, als wären Sie frustrierter darüber, wie er angelegt wurde.

Ich persönlich habe einen großen objektorientierten Programmierhintergrund, der es mir ermöglicht, eine Struktur aufzubauen und meinen Code viel wiederverwendbarer zu machen. Mein Vorschlag an Sie wäre, einen objektorientierten Ansatz für Ihr nächstes Plugin oder die Umstrukturierung dieses Plugins zu versuchen, über das Sie in der ursprünglichen Frage geschrieben haben.

Wordpress Plugin Boiler Plate ist das, was ich von ganzem Herzen empfehlen kann. Normalerweise gehe ich zunächst zu wwpb.me , um ein Plugin-Skelett für mich zu erstellen , das von Anfang an funktionsfähig ist. Füllen Sie einfach das Formular aus, laden Sie es herunter und extrahieren Sie es in Ihr Plugin-Verzeichnis Ihrer WordPress-Installation.

Sobald Sie Ihr Laufskelett installiert haben, würde ich vorschlagen, dieses Tutorial zu lesen. Es ist eine gute Einführung in den Aufbau des soeben heruntergeladenen Laufskeletts:

Beschleunigen Sie die Entwicklung mit dem WordPress Plugin Boilerplate pt1

Das WordPress Plugin Boilerplate Teil 2: Entwickeln eines Plugins

Das WordPress Plugin Boilerplate Teil 3: Die letzten Schritte

Nachdem Sie sich das kurz angesehen haben, möchte ich normalerweise eine Datenklasse erstellen, in der alle meine benutzerdefinierten Datenbankabfragen gespeichert sind, z.

<?php 

class example_Events_Data {
  private $wpdb;

  public function __construct() {
    global $wpdb;
    $this->wpdb = $wpdb;
  }

  public function get_events($start_date = null, $end_date = null) {
    $query = "SELECT wp_example_event.id, wp_example_event.name, wp_example_event.description, wp_example_event.date, wp_example_event.end_date, wp_example_event_type.id as event_type_id, wp_example_event_type.type as event_type
              FROM wp_example_event
              JOIN wp_example_event_type on wp_example_event.type_id = wp_example_event_type.id
              ORDER BY wp_example_event.name ASC";
    $events = $this->wpdb->get_results($query, ARRAY_A);
    return $events;
  }

Um dies dann in Ihren Administratoren / öffentlich zugänglichen Controllern zu verwenden, ist es so einfach wie:

    <?php

class Example_Events_Admin {

/**
 * The ID of this plugin.
 *
 * @since    1.0.0
 * @access   private
 * @var      string    $plugin_name    The ID of this plugin.
 */
private $plugin_name;

/**
 * The version of this plugin.
 *
 * @since    1.0.0
 * @access   private
 * @var      string    $version    The current version of this plugin.
 */
private $version;

private $data;
private $utils;

/**
 * Initialize the class and set its properties.
 *
 * @since    1.0.0
 * @param      string    $plugin_name       The name of this plugin.
 * @param      string    $version    The version of this plugin.
 */
public function __construct( $plugin_name, $version ) {

    $this->plugin_name = $plugin_name;
    $this->version = $version;
    $this->data = new example_Events_Data();

}

Ich erstelle mir auch gerne eine Utility-Klasse, die sehr häufig verwendete Funktionen in meinem Plugin enthält, z. B. Regeln zur Formularvalidierung, die auf genau dieselbe Weise implementiert und verwendet werden.

Sie fügen sie einfach mit require_once in Ihre Haupt-Plugin-Datei ein und instanziieren sie bei Bedarf.

Durch die Verwendung der Datenklasse kann ich alle meine Datenaufrufe an einem Ort zentralisieren und während der gesamten Plugin-Entwicklung verwenden.

Die Verwendung dieser Methoden hat meine Entwicklungszeit erheblich verkürzt und die Wartung meiner Plugins erheblich vereinfacht.

Ich hoffe, Sie finden diese Antwort hilfreich!

Ryan Fletcher
quelle