'Turning a Wordpress post_meta table into an easier to use View
I'm using Wordpress and trying to create a view to make reviewing and analyzing my resort data a little easier. Resort data is stored in the post_meta table in Wordpress and referenced in a custom post type known as "resorts". The following query gives me the result set I want to parse:
SELECT a.id, a.post_type, a.post_title, b.post_id, b.meta_key, b.meta_value
FROM alpinezone_postmeta b
INNER JOIN alpinezone_posts a ON a.id = b.post_id
WHERE a.post_type = "resorts"
What I want to do with this result set is have each unique meta_key of a set I define become a column and then each row should be a unique b.post_id (or a.id), which corresponds to an individual resort's record.
So ultimately I end up with:
post_title | phone_num | state |
resort1 | 800-200-1111 | Vermont |
resort2 | 800-200-2222 | New Hampshire |
resort 3 | 800-200-2323 | Maine |
Basically ...... I'm not that great at MySQL so trying to figure out the best way to handle this. I do have a list of all the meta_key I want to place into columns, there are 36 of them capturing a range of information.
EDIT: Some more detail.
Current Structure - shows what table it comes from as well
*alpinezone_posts alpinezone_postmeta alpinezone_postmeta*
post_title meta_key meta_value
----------------------------------------------------------------
sugarloaf snow_phone 888-234-2222
sugarloaf vertical_feet 2300
sugarloaf site_url sugarloaf.com
wachusett snow_phone 888-111-2222
wachusett vertical_feet 1000
wachusett site_url wachusett.com
These two tables are joined on post_id from table alpinezone_postmeta and id from table alpinezone_posts.
Only want results where the post_type in table alpinezone_posts is = "resorts"
How I want it to look in new view
post_title snow_phone vertical_feet site_url
-------------------------------------------------------
sugarloaf 888-234-2222 2300 sugarloaf.com
wachusett 888-111-2222 1000 wachusett.com
Solution 1:[1]
I understand you have one post for each resort, each with a more or less complete set of metadata. If that's correct, then here's how you can build a query that produces the table you describe. It's not really elegant, but it works without using another programming language or Excel (Excel might be able to make what you want from an export of the post_meta table, but my Excel-fu is not good enough...)
SELECT posts.title,
m1.meta_value as <your meta key 1>,
m2.meta_value as <your meta key 2>,
m3.meta_value as <your meta key 3>,
...
FROM alpinezone_posts
LEFT OUTER JOIN alpinezone_postmeta AS m1 ON alpinezone_posts.id = m1.post_id,
LEFT OUTER JOIN alpinezone_postmeta AS m2 ON alpinezone_posts.id = m2.post_id,
LEFT OUTER JOIN alpinezone_postmeta AS m3 ON alpinezone_posts.id = m3.post_id,
...
WHERE
m1.meta_key = <your meta key 1>
AND m2.meta_key = <your meta key 2>
AND m3.meta_key = <your meta key 3>
...
Using LEFT OUTER JOIN instead of INNER JOIN makes sure you get a result row for each resort even if you don't have a value for every meta_key.
If you can use PHP and an HTML table would help you, you could also loop all posts and use the get_post_custom() function.
Solution 2:[2]
Here's a stored procedure I wrote that takes a given post type and pivots all related postmeta data. You don't need to know the meta keys, it will figure them all out for you.
This isn't the fastest query, and we use it only for migration and deep dives into data, but it does the job.
Note that this temporarily resets the max length of the concat function so you can build a large SQL statement:
CREATE PROCEDURE `wp_posts_pivot`(IN post_type_filter varchar(50))
BEGIN
/* allow longer concat */
declare max_len_original INT default 0;
set max_len_original = @@group_concat_max_len;
set @@group_concat_max_len=100000;
SET @sql = NULL;
SELECT
GROUP_CONCAT(DISTINCT CONCAT('MAX(IF(pm.meta_key = ''',
meta_key,
''', pm.meta_value, NULL)) AS `',
meta_key,
'`'))
INTO @sql FROM
wp_posts p
INNER JOIN
wp_postmeta AS pm ON p.id = pm.post_id
WHERE
p.post_type = post_type_filter;
SET @sql = CONCAT('SELECT p.id
, p.post_title
, ', @sql, '
FROM wp_posts p
LEFT JOIN wp_postmeta AS pm
ON p.id = pm.post_id
where p.post_type=\'',post_type_filter,'\'
GROUP BY p.id, p.post_title');
/* reset the default concat */
set @@group_concat_max_len= max_len_original;
/*
select @sql;
*/
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
You can then call this with a simple call such as this one, which will select a single row for each 'page' post type along with all meta values:
call wp_posts_pivot('page');
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Simon |
| Solution 2 | Chet at C2IT |
