Very rough initial commit of taxonomy for everyone's hacking pleasure. There be dragons. see #4189

git-svn-id: http://svn.automattic.com/wordpress/trunk@5510 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
ryan 2007-05-22 05:12:38 +00:00
parent 3ed5b0a01e
commit 634a33c206
8 changed files with 214 additions and 122 deletions

View File

@ -282,27 +282,14 @@ function category_exists($cat_name) {
} }
function tag_exists($tag_name) { function tag_exists($tag_name) {
global $wpdb; return is_term($tag_name, 'post_tag');
if (! $tag_nicename = sanitize_title($tag_name))
return 0;
return (int) $wpdb->get_var("SELECT cat_ID FROM $wpdb->categories WHERE category_nicename = '$tag_nicename' AND ( type & " . TAXONOMY_TAG . " != 0 )");
} }
function wp_create_tag($tag_name) { function wp_create_tag($tag_name) {
if ( $id = tag_exists($tag_name) ) if ( $id = tag_exists($tag_name) )
return $id; return $id;
$tag_array = array('cat_name' => $tag_name, 'type' => TAXONOMY_TAG);
if ( $id = category_object_exists($tag_name) ) { $tag_id = add_term($tag_name, 'post_tag');
$category = get_category($id);
$tag_array['type'] = $category->type | $tag_array['type'];
$tag_array['cat_ID'] = $id;
$id = wp_update_category($tag_array);
return $id;
} else {
return wp_insert_category($tag_array);
}
} }
function wp_delete_user($id, $reassign = 'novalue') { function wp_delete_user($id, $reassign = 'novalue') {

View File

@ -664,16 +664,13 @@ function get_tags_to_edit( $post_id ) {
if ( !$post_id ) if ( !$post_id )
return false; return false;
$tags = $wpdb->get_results( " $tags = wp_get_post_tags($post_id);
SELECT category_id, cat_name
FROM $wpdb->categories, $wpdb->post2cat
WHERE $wpdb->post2cat.category_id = cat_ID AND $wpdb->post2cat.post_id = '$post_id' AND rel_type = 'tag'
" );
if ( !$tags ) if ( !$tags )
return false; return false;
foreach ( $tags as $tag ) foreach ( $tags as $tag )
$tag_names[] = $tag->cat_name; $tag_names[] = $tag->name;
$tags_to_edit = join( ', ', $tag_names ); $tags_to_edit = join( ', ', $tag_names );
$tags_to_edit = attribute_escape( $tags_to_edit ); $tags_to_edit = attribute_escape( $tags_to_edit );
$tags_to_edit = apply_filters( 'tags_to_edit', $tags_to_edit ); $tags_to_edit = apply_filters( 'tags_to_edit', $tags_to_edit );

View File

@ -10,20 +10,29 @@ if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') ) {
$charset_collate .= " COLLATE $wpdb->collate"; $charset_collate .= " COLLATE $wpdb->collate";
} }
$wp_queries="CREATE TABLE $wpdb->categories ( $wp_queries="CREATE TABLE $wpdb->terms (
cat_ID bigint(20) NOT NULL auto_increment, term_id bigint(20) NOT NULL auto_increment,
cat_name varchar(55) NOT NULL default '', name varchar(55) NOT NULL default '',
category_nicename varchar(200) NOT NULL default '', slug varchar(200) NOT NULL default '',
category_description longtext NOT NULL, term_group bigint(10) NOT NULL default 0,
category_parent bigint(20) NOT NULL default '0', PRIMARY KEY (term_id),
category_count bigint(20) NOT NULL default '0', UNIQUE KEY slug (slug)
link_count bigint(20) NOT NULL default '0', ) $charset_collate;
tag_count bigint(20) NOT NULL default '0', CREATE TABLE $wpdb->term_taxonomy (
posts_private tinyint(1) NOT NULL default '0', term_taxonomy_id bigint(20) NOT NULL auto_increment,
links_private tinyint(1) NOT NULL default '0', term_id bigint(20) NOT NULL default 0,
type tinyint NOT NULL default '1', taxonomy varchar(32) NOT NULL default '',
PRIMARY KEY (cat_ID), description longtext NOT NULL,
KEY category_nicename (category_nicename) parent bigint(20) NOT NULL default 0,
count bigint(20) NOT NULL default 0,
PRIMARY KEY (term_taxonomy_id),
UNIQUE KEY (term_id, taxonomy)
) $charset_collate;
CREATE TABLE $wpdb->term_relationships (
object_id bigint(20) NOT NULL default 0,
term_taxonomy_id bigint(20) NOT NULL default 0,
PRIMARY KEY (object_id),
KEY (term_taxonomy_id)
) $charset_collate; ) $charset_collate;
CREATE TABLE $wpdb->comments ( CREATE TABLE $wpdb->comments (
comment_ID bigint(20) unsigned NOT NULL auto_increment, comment_ID bigint(20) unsigned NOT NULL auto_increment,
@ -45,13 +54,6 @@ CREATE TABLE $wpdb->comments (
KEY comment_approved (comment_approved), KEY comment_approved (comment_approved),
KEY comment_post_ID (comment_post_ID) KEY comment_post_ID (comment_post_ID)
) $charset_collate; ) $charset_collate;
CREATE TABLE $wpdb->link2cat (
rel_id bigint(20) NOT NULL auto_increment,
link_id bigint(20) NOT NULL default '0',
category_id bigint(20) NOT NULL default '0',
PRIMARY KEY (rel_id),
KEY link_id (link_id,category_id)
) $charset_collate;
CREATE TABLE $wpdb->links ( CREATE TABLE $wpdb->links (
link_id bigint(20) NOT NULL auto_increment, link_id bigint(20) NOT NULL auto_increment,
link_url varchar(255) NOT NULL default '', link_url varchar(255) NOT NULL default '',
@ -86,14 +88,6 @@ CREATE TABLE $wpdb->options (
PRIMARY KEY (option_id,blog_id,option_name), PRIMARY KEY (option_id,blog_id,option_name),
KEY option_name (option_name) KEY option_name (option_name)
) $charset_collate; ) $charset_collate;
CREATE TABLE $wpdb->post2cat (
rel_id bigint(20) NOT NULL auto_increment,
post_id bigint(20) NOT NULL default '0',
category_id bigint(20) NOT NULL default '0',
rel_type varchar(64) NOT NULL default 'category',
PRIMARY KEY (rel_id),
KEY post_id (post_id,category_id)
) $charset_collate;
CREATE TABLE $wpdb->postmeta ( CREATE TABLE $wpdb->postmeta (
meta_id bigint(20) NOT NULL auto_increment, meta_id bigint(20) NOT NULL auto_increment,
post_id bigint(20) NOT NULL default '0', post_id bigint(20) NOT NULL default '0',

View File

@ -459,10 +459,8 @@ function wp_get_post_tags( $post_id = 0 ) {
$post_id = (int) $post_id; $post_id = (int) $post_id;
if ( !isset( $tag_cache[$blog_id][$post_id] ) ) $tags = get_object_terms($post_id, 'post_tag');
update_post_category_cache( $post_id ); // loads $tag_cache return $tags;
return $tag_cache[$blog_id][$post_id];
} }
function wp_get_recent_posts($num = 10) { function wp_get_recent_posts($num = 10) {
@ -793,75 +791,10 @@ function wp_set_post_tags( $post_id = 0, $tags = '', $append = false ) {
if ( !$post_id ) if ( !$post_id )
return false; return false;
// prevent warnings for unintialized variables
$tag_ids = array();
if ( empty($tags) ) if ( empty($tags) )
$tags = array(); $tags = array();
$tags = (is_array($tags)) ? $tags : explode( ',', $tags ); $tags = (is_array($tags)) ? $tags : explode( ',', $tags );
add_term_relationship($tags, $post_id, 'post_tag');
foreach ( $tags as $tag ) {
$tag = trim( $tag );
if ( !$tag_slug = sanitize_title( $tag ) )
continue; // discard
if ( !$tag_id = tag_exists( $tag ) )
$tag_id = wp_create_tag( $tag );
$tag_ids[] = $tag_id;
}
if ( empty($tag_ids) && ( !empty($tags) || $append ) )
return false;
$tag_ids = array_unique( $tag_ids );
// First the old tags
$old_tags = $wpdb->get_col("
SELECT category_id
FROM $wpdb->post2cat
WHERE post_id = '$post_id' AND rel_type = 'tag'");
if ( !$old_tags ) {
$old_tags = array();
} else {
$old_tags = array_unique( $old_tags );
}
// Delete any?
$delete_tags = array_diff( $old_tags, $tag_ids);
if ( $delete_tags && !$append ) {
foreach ( $delete_tags as $del ) {
$wpdb->query("
DELETE FROM $wpdb->post2cat
WHERE category_id = '$del'
AND post_id = '$post_id'
AND rel_type = 'tag'
");
}
}
// Add any?
$add_tags = array_diff( $tag_ids, $old_tags );
if ( $add_tags ) {
foreach ( $add_tags as $new_tag ) {
$new_tag = (int) $new_tag;
if ( !empty($new_tag) )
$wpdb->query("
INSERT INTO $wpdb->post2cat (post_id, category_id, rel_type)
VALUES ('$post_id', '$new_tag', 'tag')");
}
}
// Update category counts.
$all_affected_tags = array_unique( array_merge( $tag_ids, $old_tags ) );
foreach ( $all_affected_tags as $tag_id ) {
$count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->post2cat, $wpdb->posts WHERE $wpdb->posts.ID=$wpdb->post2cat.post_id AND post_status = 'publish' AND post_type = 'post' AND category_id = '$tag_id' AND rel_type = 'tag'" );
$wpdb->query( "UPDATE $wpdb->categories SET tag_count = '$count', type = type | " . TAXONOMY_TAG . " WHERE cat_ID = '$tag_id'" );
if ( $count == 0 )
$wpdb->query( "UPDATE $wpdb->categories SET type = type & ~". TAXONOMY_TAG . " WHERE cat_ID = '$tag_id'" );
clean_category_cache( $tag_id );
do_action( 'edit_category', $tag_id );
do_action( 'edit_tag', $tag_id );
}
} }
function wp_set_post_categories($post_ID = 0, $post_categories = array()) { function wp_set_post_categories($post_ID = 0, $post_categories = array()) {

174
wp-includes/taxonomy.php Normal file
View File

@ -0,0 +1,174 @@
<?php
// TODO: add_term(), edit_term(), and remove_term() work with terms within context of
// taxonomies. insert_term(), update_term(), delete_term() work with just the terms table.
// insert_term_taxonomy(), update_term_taxonomy(), and delete_term_taxonomy() work
// with just the term taxonomy table. Right now we only have add_term().
/**
* Adds a new term to the database. Optionally marks it as an alias of an existing term.
* @param string $term The term to add.
* @param string $taxonomy The taxonomy to which to add the term
* @param int|string $alias_of The id or slug of the new term's alias.
*/
function add_term( $term, $taxonomy, $args = array() ) {
global $wpdb;
$slug = sanitize_title($term);
$defaults = array( 'alias_of' => '', 'description' => '', 'parent' => 0);
$args = wp_parse_args($args, $defaults);
extract($args);
$term_group = 0;
if ( $alias_of ) {
$alias = $wpdb->fetch_row("SELECT term_id, term_group FROM $wpdb->terms WHERE slug = '$alias_of'");
if ( $alias->term_group ) {
// The alias we want is already in a group, so let's use that one.
$term_group = $alias->term_group;
} else {
// The alias isn't in a group, so let's create a new one and firstly add the alias term to it.
$term_group = $wpdb->get_var("SELECT MAX() term_group FROM $wpdb->terms GROUP BY term_group") + 1;
$wpdb->query("UPDATE $wpdb->terms SET term_group = $term_group WHERE term_id = $alias->term_id");
}
}
if ( ! $term_id = is_term($slug) ) {
$wpdb->query("INSERT INTO $wpdb->terms (name, slug, term_group) VALUES ('$term', '$slug', '$term_group')");
$term_id = (int) $wpdb->insert_id;
}
$tt_id = $wpdb->get_var("SELECT tt.term_taxonomy_id FROM $wpdb->term_taxonomy AS tt INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id WHERE tt.taxonomy = '$taxonomy' AND t.term_id = $term_id");
if ( !empty($tt_id) )
return $term_id;
$wpdb->query("INSERT INTO $wpdb->term_taxonomy (term_id, taxonomy, description, parent, count) VALUES ('$term_id', '$taxonomy', '$description', '$parent', '0')");
// TODO: Maybe return both term_id and tt_id.
return $term_id;
}
/**
* Removes a term from the database.
*/
function remove_term() {}
/**
* Returns the index of a defined term, or 0 (false) if the term doesn't exist.
*/
function is_term($term, $taxonomy = '') {
global $wpdb;
if ( ! $term = sanitize_title($term) )
return 0;
return $wpdb->get_var("SELECT term_id FROM $wpdb->terms WHERE slug = '$term'");
}
/**
* Given an array of terms, returns those that are defined term slugs. Ignores integers.
* @param array $terms The term slugs to check for a definition.
*/
function get_defined_terms($terms) {
global $wpdb;
foreach ( $terms as $term ) {
if ( !is_int($term) )
$searches[] = $term;
}
$terms = "'" . implode("', '", $searches) . "'";
return $wpdb->get_col("SELECT slug FROM $wpdb->terms WHERE slug IN ($terms)");
}
/**
* Relates an object (post, link etc) to a term and taxonomy type. Creates the term and taxonomy
* relationship if it doesn't already exist. Creates a term if it doesn't exist (using the slug).
* @param array|int|string $term The slug or id of the term.
* @param int $object_id The object to relate to.
* @param array|string $taxonomies The context(s) in which to relate the term to the object.
*/
function add_term_relationship($terms, $object_id, $taxonomies) {
global $wpdb;
if ( !is_array($taxonomies) )
$taxonomies = array($taxonomies);
if ( !is_array($terms) )
$terms = array($terms);
$defined_terms = get_defined_terms($terms);
foreach ( $terms as $term ) {
if ( !is_int($term) ) {
if ( !isset($defined_terms[$term]) )
$new_terms[] = $term;
$slugs[] = $term;
} else {
$term_ids[] = $term;
}
}
$term_clause = isset($term_ids) ? 'tt.term_id IN (' . implode(', ', $term_ids) . ')' : '';
if ( isset($slugs) ) {
if ($term_clause) {
$term_clause .= ' OR ';
}
$term_clause .= "t.slug IN ('" . implode("', '", $slugs) . "')";
$term_join = "INNER JOIN $wpdb->terms AS t ON tt.term_id = t.term_id";
} else {
$term_join = '';
}
// Now add or increment the term taxonomy relationships. This is inefficient at the moment.
foreach ( $taxonomies as $taxonomy ) {
foreach ( $terms as $term ) {
add_term($term, $taxonomy);
}
}
$taxonomies = "'" . implode("', '", $taxonomies) . "'";
// Finally, relate the term and taxonomy to the object.
// Use IGNORE to avoid dupe warnings for now.
$wpdb->query("INSERT IGNORE INTO $wpdb->term_relationships(object_id, term_taxonomy_id) SELECT '$object_id', term_taxonomy_id FROM $wpdb->term_taxonomy AS tt $term_join WHERE ($term_clause) AND tt.taxonomy IN ($taxonomies)");
}
/**
* Returns the terms associated with the given object(s), in the supplied taxonomies.
* @param int|array $object_id The id of the object(s)) to retrieve for.
* @param string|array $taxonomies The taxonomies to retrieve terms from.
* @return array The requested term data.
*/
function get_object_terms($object_id, $taxonomy) {
global $wpdb;
$taxonomies = ($single_taxonomy = !is_array($taxonomy)) ? array($taxonomy) : $taxonomy;
$object_ids = ($single_object = !is_array($object_id)) ? array($object_id) : $object_id;
$taxonomies = "'" . implode("', '", $taxonomies) . "'";
$object_ids = implode(', ', $object_ids);
if ( $taxonomy_data = $wpdb->get_results("SELECT t.* FROM $wpdb->terms AS t INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = t.term_id INNER JOIN $wpdb->term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ($taxonomies) AND tr.object_id IN ($object_ids)") ) {
if ($single_taxonomy && $single_object) {
// Just one kind of taxonomy for one object.
return $taxonomy_data;
} else {
foreach ($taxonomy_data as $data) {
if ($single_taxonomy) {
// Many objects, one taxonomy type.
$return[$data->object_id][] = $data;
} elseif ($single_object) {
// One object, many taxonomies.
$return[$data->taxonomy][] = $data;
} else {
// Many objects, many taxonomies.
$return[$data->object_id][$data->taxonomy][] = $data;
}
}
return $return;
}
} else {
return array();
}
}
?>

View File

@ -3,6 +3,6 @@
// This holds the version number in a separate file so we can bump it without cluttering the SVN // This holds the version number in a separate file so we can bump it without cluttering the SVN
$wp_version = '2.3-alpha'; $wp_version = '2.3-alpha';
$wp_db_version = 5200; $wp_db_version = 5495;
?> ?>

View File

@ -34,6 +34,9 @@ class wpdb {
var $optiongroups; var $optiongroups;
var $optiongroup_options; var $optiongroup_options;
var $postmeta; var $postmeta;
var $terms;
var $term_taxonomy;
var $term_relationships;
var $charset; var $charset;
var $collate; var $collate;

View File

@ -116,6 +116,9 @@ $wpdb->links = $wpdb->prefix . 'links';
$wpdb->options = $wpdb->prefix . 'options'; $wpdb->options = $wpdb->prefix . 'options';
$wpdb->postmeta = $wpdb->prefix . 'postmeta'; $wpdb->postmeta = $wpdb->prefix . 'postmeta';
$wpdb->usermeta = $wpdb->prefix . 'usermeta'; $wpdb->usermeta = $wpdb->prefix . 'usermeta';
$wpdb->terms = $wpdb->prefix . 'terms';
$wpdb->term_taxonomy = $wpdb->prefix . 'term_taxonomy';
$wpdb->term_relationships = $wpdb->prefix . 'term_relationships';
if ( defined('CUSTOM_USER_TABLE') ) if ( defined('CUSTOM_USER_TABLE') )
$wpdb->users = CUSTOM_USER_TABLE; $wpdb->users = CUSTOM_USER_TABLE;
@ -168,6 +171,7 @@ require (ABSPATH . WPINC . '/cron.php');
require (ABSPATH . WPINC . '/version.php'); require (ABSPATH . WPINC . '/version.php');
require (ABSPATH . WPINC . '/deprecated.php'); require (ABSPATH . WPINC . '/deprecated.php');
require (ABSPATH . WPINC . '/script-loader.php'); require (ABSPATH . WPINC . '/script-loader.php');
require (ABSPATH . WPINC . '/taxonomy.php');
if (strpos($_SERVER['PHP_SELF'], 'install.php') === false) { if (strpos($_SERVER['PHP_SELF'], 'install.php') === false) {
// Used to guarantee unique hash cookies // Used to guarantee unique hash cookies