Frage

Ich arbeite an einem Projekt, in dem ich einen benutzerdefinierten Beitragstyp und benutzerdefinierte Daten erstelle, die über Meta -Boxen eingegeben wurden, die meinem benutzerdefinierten Post -Typ zugeordnet sind. Aus irgendeinem Grund habe ich mich entschlossen, die Meta -Boxen so zu codieren, dass die Eingaben in jedem Metabox Teil eines Arrays sind. Zum Beispiel speichere ich Länge und Breitengrad:

<p> 
    <label for="latitude">Latitude:</label><br /> 
    <input type="text" id="latitude" name="coordinates[latitude]" class="full-width" value="" /> 
</p> 
<p>     
    <label for="longitude">Longitude:</label><br /> 
    <input type="text" id="longitude" name="coordinates[longitude]" class="full-width" value="" /> 
</p>

Aus irgendeinem Grund mochte es mir die Idee, für jeden Metabox einen einzigartigen Postmeta -Eintrag zu haben. Auf der save_post Hook, ich speichere die Daten wie so:

update_post_meta($post_id, '_coordinates', $_POST['coordinates']);

Ich habe das getan, weil ich drei Metaboxen habe und ich gerne nur 3 Postmeta -Werte für jeden Beitrag habe. Ich habe jetzt jedoch ein potenzielles Problem damit erkannt. Vielleicht möchte ich WP_Query verwenden, um bestimmte Beiträge nur diese Metawerte auszuziehen. Zum Beispiel möchte ich möglicherweise alle Beiträge mit Breitengradwerten über 50 erhalten. Wenn ich diese Daten einzeln in der Datenbank hatte, kann möglicherweise der Schlüssel verwendet werden latitude, Ich würde so etwas wie:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '50',
            'compare' => '>'
        )
    )
 );
$query = new WP_Query( $args );

Da habe ich den Breitengrad als Teil der _coordinates Postmeta, das würde nicht funktionieren.

Meine Frage ist also, gibt es eine Möglichkeit zu nutzen meta_query Um ein serialisiertes Array abzufragen, wie ich es in diesem Szenario habe?

War es hilfreich?

Lösung

Nein, es ist nicht möglich und könnte sogar gefährlich sein.

Ich empfehle Ihnen dringend, Ihre Daten zu unverzüglich und ändern Sie Ihre Speicherroutine. Etwas Ähnliches sollte Ihre Daten in das neue Format konvertieren:

$args = array(
    'post_type' => 'my-post-type',
    'meta_key' => '_coordinates',
    'posts_per_page' => -1
 );
$query = new WP_Query( $args );
if($query->have_posts()){
    while($query->have_posts()){
        $query->the_post();
        $c = get_post_meta($post->id,'_coordinates',true);
        add_post_meta($post->ID,'_longitude',$c['longitude']);
        add_post_meta($post->ID,'_latitude',$c['latitude']);
        delete_post_meta($post->ID,'_coordinates',$c);
    }
}

Dann können Sie mit individuellen Schlüsseln nach Abfragen abfragen

Wenn Sie mehrere Längsmittel und mehrere Breiten speichern müssen, können Sie mehrere Post -Meta mit demselben Namen speichern. Verwenden Sie einfach den dritten Parameter von get_post_meta, und es wird sie alle als Array zurückgeben

Warum können Sie nicht in serialisierten Daten abfragen?

MySQL sieht es nur als Zeichenfolge und kann es nicht in strukturierte Daten auseinanderbrechen. Es ist genau das, was der obige Code in strukturierte Daten unterteilt

Möglicherweise können Sie partielle Stücke des Datums abfragen, aber dies ist super zuverlässig, teuer, langsam und sehr zerbrechlich, mit vielen Kantenfällen. Serialisierte Daten sind für SQL -Abfragen nicht bestimmt und werden nicht regelmäßig und konstant formatiert.

Abgesehen von den Kosten für teilweise String -Suchvorgänge sind Post -Meta -Abfragen langsam, und serialisierte Daten können sich je nach Dingen wie der Inhaltsdauer ändern, wodurch die Suche unglaublich teuer, wenn nicht unmöglich von dem Wert, den Sie suchen

Ein Hinweis zum Speichern von Datensätzen/Entitäten/Objekten als serialisierte Objekte in Meta

Möglicherweise möchten Sie einen Transaktionsdatensatz in Post -Meta oder eine andere Art von Datenstruktur in Benutzer -Meta speichern und dann auf das obige Problem stoßen.

Die Lösung hier besteht nicht darin, es in einzelne Post -Meta zu unterteilen, sondern zu erkennen, dass es niemals von Anfang an Meta sein sollte, sondern ein benutzerdefinierter Post -Typ. Beispielsweise kann ein Protokoll oder Datensatz ein benutzerdefinierter Post -Typ sein, mit dem ursprünglichen Beitrag als Elternteil oder über eine Taxonomie -Begriff

Sicherheits- und serialisierte Objekte

Speichern serialisierter PHP -Objekte über die serialize Funktion kann gefährlich sein, was unglücklich ist, wenn ein Objekt an WordPress übergeben wird, bedeutet, dass es serialisiert wird. Dies liegt daran, dass wenn das Objekt de-serialisiert wird, ein Objekt erstellt wird und alle seine Weckmethoden und Konstrukteure ausgeführt werden. Dies scheint nicht wie eine große Sache zu sein, bis ein Benutzer es schafft, eine sorgfältig gefertigte Eingabe zu schleichen, was zu einer Remote-Codeausführung führt, wenn die Daten aus der Datenbank gelesen und von WordPress deserialisiert werden.

Dies kann vermieden werden, indem JSON stattdessen verwendet wird, was auch die Abfragen erleichtert, aber es ist viel einfacher/schneller, die Daten korrekt zu speichern und strukturierte serialisierte Daten zunächst zu vermeiden.

Andere Tipps

Ich bin auch in diese Situation stoße. Hier was ich getan habe:

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => sprintf(':"%s";', $value),
            'compare' => 'LIKE'
        )
    )
);

Ich hoffe das hilft

Sie werden wirklich die Fähigkeit verlieren, Ihre Daten auf effiziente Weise bei der Serialisierung der Einträge in die WP -Datenbank abzufragen.

Die allgemeine Leistungseinsparung und Gewinne, die Sie durch Serialisierung erreichen, wird in einem großen Teil nicht auffällig sein. Sie können eine etwas kleinere Datenbankgröße erhalten, aber die Kosten für SQL -Transaktionen werden stark sein, wenn Sie diese Felder jemals abfragen und versuchen, sie auf nützliche, sinnvolle Weise zu vergleichen.

Speichern Sie stattdessen die Serialisierung für Daten, die Sie nicht in dieser Art abfragen möchten, sondern würden stattdessen nur durch den direkten WP -API -Aufruf passiv zugreifen get_post_meta() - Aus dieser Funktion können Sie einen serialisierten Eintrag auspacken, um auch auf die Array -Eigenschaften zuzugreifen.

In der Tat den Wert von zugewiesen Stimmt wie in;

$meta = get_post_meta( $post->ID, 'key', true );

Gibt die Daten als Array zurück, das für Sie zugänglich ist, um sie nach normal zu iterieren.

Sie können sich auf andere Datenbank-/Site -Optimierungen wie Caching, CSS und JS Minification und die Verwendung von Diensten wie CDN konzentrieren, wenn Sie benötigen. Um nur ein paar zu nennen .... WordPress Codex ist ein guter Ausgangspunkt, um mehr zu diesem Thema aufzudecken: HIER

Ich habe mich gerade mit serialisierten Feldern befasst und könnte sie abfragen. Verwenden Sie nicht die Meta_Query, sondern eine SQL -Abfrage.

global $wpdb; 

$search = serialize('latitude').serialize(50);

$query = $wpdb->prepare("SELECT `post_id`
FROM `wp_postmeta`
WHERE `post_id` IN (SELECT `ID` FROM `wp_posts` WHERE `post_type` = 'my-post-type')
AND `meta_key` = '_coordinates'
AND `meta_value` LIKE '%s'",'%'.$search.'%');

$ids = $wpdb->get_col($query);

$args = array(
    'post__in' => $ids
    'post_type' => 'team' //add the type because the default will be 'post'
);

$posts = get_posts($args);

Die Abfrage sucht zunächst nach Post mit dem passenden post_type, sodass die Menge an wp_postmeta -Datensätzen geringer ist, um zu filtern. Dann habe ich eine Where -Aussage hinzugefügt, um die Zeilen durch Filtern weiter zu reduzieren meta_key

Die IDs landen nach Bedarf in einem Array für Get_Posts gut.

Ps. MySQL v5.6 oder höher ist für eine gute Unterabfrage erforderlich

Dieses Beispiel hat mir wirklich geholfen. Es gilt speziell für das S2Members -Plugin (das Benutzermetadaten serialisiert). Sie können jedoch einen Teil eines serialisierten Arrays innerhalb des meta_key abfragen.

Es funktioniert mit der MySQL Regexp -Funktion.

Hier ist die Quelle

Hier ist der Code, der alle in den USA leben. Ich modifizierte es leicht, um eines meiner benutzerdefinierten Registrierungsfelder abzufragen, und ließ es in kürzester Zeit funktionieren.

  <?php
global $wpdb;
$users = $wpdb->get_results ("SELECT `user_id` as `ID` FROM `" . $wpdb->usermeta . 
          "` WHERE `meta_key` = '" . $wpdb->prefix . "s2member_custom_fields' AND 
           `meta_value` REGEXP '.*\"country_code\";s:[0-9]+:\"US\".*'");
if (is_array ($users) && count ($users) > 0)
    {
        foreach ($users as $user)
            {
                $user = /* Get full User object now. */ new WP_User ($user->ID);
                print_r($user); /* Get a full list of properties when/if debugging. */
            }
    }
?>

Ich denke, es gibt 2 Lösungen, die versuchen können, das Problem der Ergebnisse zu lösen, die sowohl als String als auch als Ganzzahlen gespeichert werden. Es ist jedoch wichtig zu sagen, wie andere betonten, dass es nicht möglich ist, die Integrität der als Ganzzahl gespeicherten Ergebnisse zu gewährleisten, da diese Werte, die als serialisierte Arrays gespeichert sind, der Index und die Werte genau mit demselben Muster gespeichert werden. Beispiel:

array(37,87);

wird als serialisiertes Array wie dieses gespeichert

a:2:{i:0;i:37;i:1;i:87;}

Beachten Sie das i:0 als erste Position des Arrays und i:37 als erster Wert. Das Muster ist das gleiche. Aber gehen wir zu den Lösungen


1) Regexp -Lösung

Diese Lösung funktioniert für mich unabhängig davon, ob der Metawert als Zeichenfolge oder Zahl / ID gespeichert wird. Allerdings verwendet es REGEXP, was nicht so schnell ist wie verwendet LIKE

$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '\;i\:' . $value . '\;|\"' . $value . '\";',
            'compare' => 'REGEXP'
        )
    )
);

2) Lösung

Ich bin mir nicht sicher über den Leistungsunterschied, aber dies ist eine Lösung, die verwendet LIKE und funktioniert auch sowohl für Zahlen als auch für Zeichenfolgen

 $args = array(
        'post_type' => 'my-post-type',
        'meta_query' => array(
            'relation' => 'OR',
            array(
                'key' => 'latitude',
                'value' => sprintf(':"%s";', $value),
                'compare' => 'LIKE'
            ),
            array(
                'key' => 'latitude',
                'value' => sprintf(';i:%d;', $value),
                'compare' => 'LIKE'
            )
        )
    );

Nach dem Lesen einiger Tipps zum Ausführen von a WP_Query Filterung durch serialisierte Arrays, so habe ich es endlich gemacht: Durch das Erstellen eines Arrays von mit Kommas getrennten Werten unter Verwendung des Implodens in Verbindung mit a $wpdb benutzerdefinierte SQL -Abfrage mit Verwendung FIND_IN_SET So durchsuchen Sie die von Kommas getrennte Liste nach dem angeforderten Wert.

(Dies ähnelt der Antwort von Tomas, aber für die SQL -Abfrage ist es etwas weniger leistungsintensiv)

1. in Funktionen.php:

In Ihrer functions.php -Datei (oder wo immer Sie das Metabox einrichten) in der yourname_save_post() Funktionsutz

update_post_meta($post->ID, 'checkboxArray', implode(",", $checkboxArray)); //adding the implode

So erstellen Sie das Array, das mit Kommas getrennte Werte enthält.

Sie möchten auch Ihre Ausgangsvariable in der yourname_post_meta() Admin -Meta -Box -Konstruktionsfunktion zu

$checkboxArray = explode(",", get_post_custom($post->ID)["checkboxArray"][0]); //adding the explode

2. In der Vorlage -PHP -Datei:

Test: Wenn Sie a ausführen get_post_meta( $id ); Das solltest du sehen checkboxArray als ein Array, das Ihr Komma enthält, trennte sich anstelle eines serialisierten Arrays.

Jetzt erstellen wir unsere benutzerdefinierte SQL -Abfrage mithilfe $wpdb.

global $wpdb;

$search = $post->ID;

$query = "SELECT * FROM wp_posts
          WHERE FIND_IN_SET( $search, (
              SELECT wp_postmeta.meta_value FROM wp_postmeta
              WHERE wp_postmeta.meta_key = 'blogLocations'
              AND wp_postmeta.post_id = wp_posts.ID )
          )
          AND ( wp_posts.post_type = 'post' )
          AND ( wp_posts.post_status = 'publish' );";

$posts = $wpdb->get_results($query);

foreach ($posts as $post) {
    //your post content here
}

Beachten Sie die FIND_IN_SET, Hier passiert die Magie.

Jetzt ... da ich benutze SELECT * Dies kehrt zurück Alle Postdaten und innerhalb der foreach Sie können wiedergeben, was Sie davon wollen (machen Sie a print_r($posts); Wenn Sie nicht wissen, was enthalten ist. Es wird nicht "die Schleife" für Sie eingerichtet (ich bevorzuge es so), kann aber leicht geändert werden, um die Schleife einzurichten, wenn Sie es vorziehen (schauen Sie sich an setup_postdata($post); Im Codex müssen Sie sich wahrscheinlich ändern SELECT * Um nur Post -IDs auszuwählen und $wpdb->get_results zum richtigen $wpdb Typ - siehe den Codex für $wpdb Auch für Informationen zu das Thema).

WHELP, es brauchte ein bisschen Mühe, aber seitdem wp_query Unterstützt es nicht 'compare' => 'IN' Serialisierte oder von Kommas getrennte Werte Diese Shim ist die beste Option!

Hoffe das hilft jemandem.

Wenn Sie die verwenden like Vergleichsbetreiber in Ihrer Meta -Abfrage sollte es gut funktionieren, in ein serialisiertes Array zu schauen.

$wp_user_search = new WP_User_Query(array(
    'meta_query' => array(
        array(
            'key'     => 'wp_capabilities',
            'value'   => 'subscriber',
            'compare' => 'not like'
            )
        )
    )
);

führt zu:

[query_where] => WHERE 1=1 AND (
  ( wp_usermeta.meta_key = 'wp_capabilities' 
  AND CAST(wp_usermeta.meta_value AS CHAR) NOT LIKE '%subscriber%' )

Wenn meine Meta -Daten Array -Typ sind, verwende ich diese Methode für Abfrage nach Meta:

$args = array(
    'post_type' => 'fotobank',
    'posts_per_page' => -1,
    'meta_query' => array(
            array(
                   'key' => 'collections',
                   'value' => ':"'.$post->ID.'";',
                   'compare' => 'LIKE'
            )
     )
);
$fotos = new WP_Query($args);

Ich wurde neugierig auf die obigen Antworten, wo die meta_query zielte auf den Schlüssel latitude Anstatt von _coordinates. Musste prüfen, ob es in Meta -Abfragen wirklich möglich war, um einen bestimmten Schlüssel in einem serialisierten Array abzuzielen. :)

Das war offensichtlich nicht der Fall.

Beachten Sie also, dass der richtige Schlüssel zum Ziel ist _coordinates Anstatt von latitude.

$args = array(
     'post_type' => 'my-post-type',
     'meta_query' => array(
         array(
             'key' => '_coordinates',
             'value' => sprintf(':"%s";', $value),
             'compare' => 'LIKE'
         )
     )
 );

ANMERKUNGEN:

  1. Dieser Ansatz ermöglicht es nur, genaue Übereinstimmungen abzuzielen. Also Dinge wie Alle Breiten mehr als 50 sind nicht möglich.

  2. Um Substring -Übereinstimmungen einzuschließen, könnte man gebrauchen 'value' => sprintf(':"%%%s%%";', $value),. (nicht getestet)

Ich habe die gleiche Frage. Vielleicht brauchen Sie den Parameter "Typ"? Schauen Sie sich diese verwandte Frage an:Benutzerdefinierte Feldabfrage - Metawert ist Array

Vielleicht versuchen Sie:

    $args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => '50',
            'compare' => '>',
            'type' => 'numeric'
        )
    )
    );

Ich bin auf etwas Ähnliches gestoßen, als ich das Magic Fields -Plugin benutzte. Dies könnte den Trick machen

$values_serialized = serialize(array('50'));
$args = array(
    'post_type' => 'my-post-type',
    'meta_query' => array(
        array(
            'key' => 'latitude',
            'value' => $values_serialized,
            'compare' => '>'
        )
    )
);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit wordpress.stackexchange
scroll top