So I'm trying to integrate a bit of Wordpress with a backend. Their MySQL schema isn't too great, especially when you add in Woocommerce.
I've come up with the following query:
SELECT wp.*
FROM wp_postmeta wp
INNER JOIN (SELECT post_id
FROM wp_postmeta
WHERE ( `meta_key` = '_shipping_method'
AND `meta_value` = 'free_shipping' )
OR ( `meta_key` = '_order_items'
AND `meta_value` LIKE '%search%' )) a
ON a.post_id = wp.post_id
ORDER BY wp.post_id DESC
To be run on this table http://i.imgur.com/YBaGq.jpg to select the right things for certain people.
Now when I var_dump this in PHP it comes out like so (truncated) - http://pastebin.com/WR3byT8k
Is there any way I can map this properly to an array so that I can use something simple like:
echo $content['_billing_first_name'];
echo $content['_billing_last_name'];
Which would output:
John
Citizen
Keep in mind all the content is dynamic, so I can't just use row numbers.
If you have a fixed set of meta keys you need to retrieve (not necessarily a fixed order), you can do it in the query itself by using a technique similar to a pivot table.
SELECT
post_id,
MAX(CASE WHEN meta_key = '_billing_first_name' THEN meta_value ELSE NULL END) AS _billing_first_name,
MAX(CASE WHEN meta_key = '_billing_last_name' THEN meta_value ELSE NULL END) AS _billing_last_name,
MAX(CASE WHEN meta_key = '_some_other_attribute' THEN meta_value ELSE NULL END) AS _some_other_attribute,
MAX(CASE WHEN meta_key = '_another_attribute' THEN meta_value ELSE NULL END) AS _another_attribute,
...
...
FROM wp_post_meta
GROUP BY post_id
The CASE statements determine which parameter you are pulling and assign it to a column. They are wrapped in MAX() aggregates simply to eliminate the NULLs which result when the keys don't match, collapsing it down to a single row with columns for each attribute rather than multiple rows with mostly NULL values.
Failing this (if your set of attributes is varies unexpectedly), you would need to iterate in code. That would be messy though.
In PHP:
Using PHP, if you have an array of the meta post keys you want to retrieve, you can loop over all rows and if the meta_key is one you want, store the meta_value onto an array:
// Assumes your WP query results are already stored into the array $your_db_rows
// Will hold your final processed results
$output = array();
// If you want only a specific set of meta_key names rather than all meta_key names
$keys_you_want = array('_billing_first_name','_billing_last_name','_some_other_attribute');
// Loops over the result set
foreach ($your_db_rows_array as $row) {
// If the current row holds one of the meta_key you are looking for
if (in_array($row['meta_key'], $keys_you_want)) {
// Put it onto the output array using the meta_key as the array key
$output[$row['meta_key'] = $row['meta_value'];
}
// Otherwise do nothing...
}
var_dump($output);
To get all meta_key, just leave out the in_array() test and the $keys_you_want array. That will store every meta_key encountered onto $output.
// Loops over the result set for all values of meta_key, not a specific set
foreach ($your_db_rows_array as $row) {
// Put it onto the output array using the meta_key as the array key
$output[$row['meta_key'] = $row['meta_value'];
}
var_dump($output);
Related
I'm having an issue with creating custom fields after data has already been added to the DB. I've been looking at this for a while and my brain has shut down. I'll try and explain the best I can.
I have 2 tables, custom_fields and custom_fields_values. I also sort these fields via a table column. When I pull them from the db I have to join the tables in order to have the results show in the same order as the fields. If I don't then data gets mixed up.
$customfield = $pdo->prepare("SELECT * FROM custom_fields ORDER BY fieldorder ASC");
$customfield->execute();
$customfield = $customfield->fetchAll(PDO::FETCH_ASSOC);
$customfieldvals = $pdo->prepare("SELECT vals.* FROM custom_fields_values vals JOIN custom_fields fields ON fields.id = vals.fieldid WHERE vals.related_system=:relsystem ORDER BY fields.fieldorder ASC");
$customfieldvals->bindParam(':relsystem', $get_system['id'], PDO::PARAM_STR);
$customfieldvals->execute();
$customfieldvals = $customfieldvals->fetchAll(PDO::FETCH_ASSOC);
I then have a foreach loop that does properly display the data. The issue is, when I add a new custom field that does not have a value because it was created in the custom_fields table, but NOT in the custom_fields_values table so it doesn't match at ON fields.id = vals.fieldid. If I resort the fields while this has no value, it takes the value of another field. Essentially, because it doesn't match at the id level of fields and fieldid of values, everything gets messed up.
How can I make it to where if it does not have a value row created, it will just show NULL no matter what instead of taking the value of another field?
EDIT
Am I going about this the right way or is there a better way to have the custom field value follow the custom field rather than the JOIN method?
You have to use Left Join in to your query. Left Join will return null If it does not found value for custom field into custom_fields_values table.
So Query will look like this.
$customfieldvals = $pdo->prepare("SELECT vals.* FROM custom_fields_values vals LEFT JOIN custom_fields fields ON fields.id = vals.fieldid WHERE vals.related_system=:relsystem ORDER BY fields.fieldorder ASC");
I didn't think about this initially, but instead of calling a separate query for just values I totally removed the $customfieldvals query and changed the $customfield query. This instead locks the value to the field rather than just linking them.
$customfield = $pdo->prepare("SELECT * FROM custom_fields fields LEFT JOIN custom_fields_values vals ON fields.id = vals.fieldid WHERE vals.related_system=:relsystem ORDER BY fieldorder ASC");
$customfields->bindParam(':relsystem', $_GET['id'], PDO::PARAM_STR);
$customfield->execute();
$customfield = $customfield->fetchAll(PDO::FETCH_ASSOC);
and then my foreach:
foreach ($customfield as $fields) {...
This allowed me to call
$fields['value']
rather than
$customfieldvals[$key]['value']
I would like some help iterating through an object that is stored in the meta_value column of my wp_postmeta table.
I have ID's stored in the column and I would like to use those ID's in an inner SELECT that will go and get the Page Title that is associated with each ID.
Here is my SQL:
SELECT p.ID, p.post_title, p.post_status, p.post_type, pm.meta_key, pm.meta_value
FROM wp_posts p, wp_postmeta pm
WHERE p.ID = pm.post_id
AND pm.meta_key = topic_related_topics
AND pm.meta_value != ''
ORDER BY p.post_title, p.post_type desc
Here is an example of what is brought back:
1313,ADIPIC ACID,draft,post,topic_related_topics,
a:5:
{i:0;s:3:"961";
i:1;s:4:"1313";
i:2;s:3:"975";i:
Basically I need to know the title that is associated with ID 961. The title resides in the wp_posts table.
The value you are seeing in the database is an array that has been serialized to a string by PHP. The i stands for "integer" and the s stands for "string", with the number following the s indicating how long the string is. In this case, even though "961" is an integer, it is being stored as a string in the first place of a an array with 5 elements (it looks like you chopped the last 2 off).
There isn't a good way to unserialize the data in SQL, so you will need to do it in PHP and then make a second query to get the title. You can use the WordPress function maybe_unserialize() to convert it back into an array.
global $wpdb;
$sql = "your sql....";
$rows = $wpdb->get_results( $wpdb->prepare( $sql, $your_args ) );
foreach( $rows as $row ){
// convert to an array
$ids = maybe_unserialize( $row->meta_value );
// loop through the array
foreach( $ids as $id ){
// fetch the titles
$sql = "SELECT post_title FROM $wpdb->posts WHERE ID = %d";
$title = $wpdb->get_var( $wpdb->prepare( $sql, $id ) );
}
}
A more standard way of doing it would be to just use get_post_meta() to fetch the array, and have WordPress handle the serialization internally. The other big advantage here is that if you are using caching, support for it is already built into these functions.
Lastly if you do want to be able to fetch it all in a single SQL query, you will need some additional logic, likely hooked to the saving of the meta value. In addition to having it save as an array, you can grab the single value you want to JOIN on and save it in its own meta_key. With a single value you can then join the posts table to the postmeta to accomplish what you are looking for.
I am trying to show the sum of meta_value (which is numeric) for all the instances where post_id is the same in table postmeta. From looking at other replies the following seems to be what should do this but I just get nothing returned
<?php
global $wpdb;
$data = $wpdb->query("
SELECT SUM(meta_value)
FROM $wpdb->postmeta
WHERE `post_id` = $post_id
");
echo $data;
?>
I can't figure out what is wrong with this when compared to other answers. Any pointers?
Thanks
Well... Are you connected to the database? And when you're including object properties inside a string, it's good form to encase them in braces, like so:
$data = $wpdb->query("SELECT SUM(meta_value)
FROM {$wpdb->postmeta}
WHERE `post_id` = $post_id
");
Encapsulate your php variables if they are complex, so:
FROM {$wpdb->postmeta}
For SELECTing, you should use $wpdb->get_results() instead of $wpdb->query().
$wpdb->query() "… returns an integer corresponding to the number of rows affected/selected."
http://codex.wordpress.org/Class_Reference/wpdb#SELECT_Generic_Results
OK, I have changed the code to reflect the above including he encapsulation and using get_results instead of query but now just get 'Array' as the returned result.
global $wpdb;
$data = $wpdb->get_results("
SELECT SUM($wpdb->postmeta.meta_value)
FROM {$wpdb->postmeta}
WHERE `post_id` = the_id()
");
echo $data;
Do I need to use a foreach() loop to cycle the resultant array? I have also checked there is data and also that the_id() is valid
I have a table (wp_postmeta), which contains four columns (meta_id, post_id, meta_key, meta_value). meta_key contains a field called neighborhood_value and the values for neighborhood_value are stored under the meta_value column. How do I retrieve the contents of neighborhood_value from my table and use them as a variable? Any support is appreciated
Ok, as everything is meta, thecode will also be "meta" :)
UPDATE - now when I know what you use to connect to DB I can change my answer to be more specific.
global $wpdb;
$sql = "SELECT meta_key, meta_value FROM $wpdb->postmeta WHERE post_id=XXX";
$retMeta = array();
$results = $wpdb->get_results($sql);
foreach ($results as $resultRow)
{
if (!isset($retMeta[$resultRow['meta_key']]))
{
$retMeta[$resultRow['meta_key']] = array();
}
$retMeta[$resultRow['meta_key']][] = $resultRow['meta_value'];
}
The resulting $retMeta will be two dimensional array, and then you will be able to access your neighbourhood value by using $retMeta['neighbourhood_value'][0] (of course first you have to check if this is set - isset($retMeta['neighbourhood_value'])).
UPDATE2
For script imporing data, it'll look like that:
$sql = "SELECT meta_key, meta_value FROM wp_postmeta WHERE post_id=XXX";
$retMeta = array();
$result = mysql_query($sql);
while ($resultRow= mysql_fetch_assoc($result))
{
if (!isset($retMeta[$resultRow['meta_key']]))
{
$retMeta[$resultRow['meta_key']] = array();
}
$retMeta[$resultRow['meta_key']][] = $resultRow['meta_value'];
}
mysql_free_result($result);
But you should use WP_Query anyway, to maintain portability (the wp_postmeta doesn't have to be named that way, it can be wp2_postmeta etc).
If I understand correctly, you want to key a list of keys from meta_value?
I would do this in php: (assuming you are using some sort of framework that supports this construct. This example works with the codeigniter framework))
$sql = "SELECT distinct meta_value FROM wp_postmeta"
$result = $db->query($sql)
foreach ($result->reult() as $row) {
$mydata[] = $row->meta_value;
}
$mydata is now array containing all of your meta_value values.
I was doing same as the following.
<?php foreach($values as $value)
{
$myVarname[$value[valuefield]]=$value[valuefield];
}
$myVarname[field1]="Cow";
$myVarname[field2]="dog";
?>
If you're working with Wordpress template files such as loop.php etc., just use the handy get_post_meta() function.
You don't specify what language you want to use for your variables - but if it happens to be SQL in MySQL, here's how you "Retrieve Value From MySQL Table and Save in Variable":
select #var_name := column_name from table_name where other_column = 5;
This does the select, and as a side-effect assigns the value of the user variable #var_name to the value of column_name.
or
select #var_name := count(*) from other_table where other_column > 5;
which sets #var_name to the number of records that matched the condition.
HI all,
I am trying to figure out how to put this into words even, but I am wanting to know how to format the output from each table separately in a "multiple table" mysql query. The output from the table1 "wall" is formatted within a while loop, but the content from table2 "actions" is already formatted(as 1 line of text with links) before it is inserted into the table(column action_body), so inside the loop I would only be outputting the action_date and action_body columns from the actions table.
I am probably not using the correct sql method(if Im doing anything right at all, that is) for the results I need, so feel free to correct my novice example, or suggest a new way to approach this.
Query:
$query = "SELECT wall.wall_id, wall.wall_owner_id, wall.wall_user_id,
wall.wall_post_date, wall.wall_post_content, actions.action_id,
actions.action_date, actions.action_user_id, actions.action_title,
actions.action_body FROM wall, actions
ORDER BY wall.wall_post_date, actions.action_date DESC";
$result = mysql_query($query);
while( $rows = mysql_fetch_assoc($result) {
// What to put here
}
Any help is appreciated, thanks, Lea
Update after comments
SELECT w.* FROM (
(SELECT
'w' as type,
wall_id as id,
wall_owner_id as owner_id,
wall_user_id as user_id,
wall_post_date as post_date,
NULL as title,
wall_post_content as content
FROM wall
WHERE wall_owner_id = x # user id of owner
)
UNION
(SELECT
'a' as type,
action_id as id,
action_user_id as owner_id,
NULL as user_id,
action_post_date as post_date,
action_title as title,
action_body as content
FROM actions
WHERE action_user_id = x # user id of owner
)
) w
ORDER BY w.post_date DESC
Because you don't JOIN on a specific field, you're gonna get every row-row combination of the two tables, which is a whole lot more data than you probably want.
You'd be better of by doing 2 queries, one for each table. While looping through the result of each table, you can collect the data you want in one array, with the field you want to sort it by as array key.
Then you sort the array, and loop through it to print it out.