Posts 2 Posts - Version 0.3

Version Description

  • store connections using a taxonomy instead of postmeta
  • more info
Download this release

Release Info

Developer scribu
Plugin Icon wp plugin Posts 2 Posts
Version 0.3
Comparing to
See all releases

Code changes from version 0.2 to 0.3

Files changed (10) hide show
  1. admin/admin.php +73 -24
  2. api.php +69 -119
  3. core.php +77 -0
  4. lang/posts-to-posts.pot +8 -8
  5. posts-to-posts.php +5 -4
  6. readme.txt +14 -7
  7. scb/Query.php +0 -75
  8. scb/QueryManipulation.php +81 -0
  9. scb/Util.php +10 -2
  10. scb/load.php +3 -2
admin/admin.php CHANGED
@@ -1,6 +1,8 @@
1
  <?php
2
 
3
- class P2P_Box {
 
 
4
 
5
  function init( $file ) {
6
  add_action( 'admin_print_styles-post.php', array( __CLASS__, 'scripts' ) );
@@ -8,10 +10,34 @@ class P2P_Box {
8
 
9
  add_action( 'add_meta_boxes', array( __CLASS__, 'register' ) );
10
 
11
- add_action( 'save_post', array( __CLASS__, 'save' ), 10, 2 );
12
  add_action( 'wp_ajax_p2p_search', array( __CLASS__, 'ajax_search' ) );
13
 
14
- scbUtil::add_uninstall_hook( $file, array( __CLASS__, 'uninstall' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  }
16
 
17
  function scripts() {
@@ -26,28 +52,42 @@ class P2P_Box {
26
  <?php
27
  }
28
 
29
- function save( $post_a, $post ) {
30
- if ( defined( 'DOING_AJAX' ) || defined( 'DOING_CRON' ) || empty( $_POST ) || 'revision' == $post->post_type )
 
31
  return;
32
 
33
- $connections = p2p_get_connected( 'any', 'from', $post_a, true );
34
 
35
- foreach ( p2p_get_connection_types( $post->post_type ) as $post_type ) {
36
  if ( !isset( $_POST['p2p_connected_ids_' . $post_type] ) )
37
  continue;
38
 
39
- $old_connections = (array) $connections[ $post_type ];
40
- $new_connections = explode( ',', $_POST[ 'p2p_connected_ids_' . $post_type ] );
41
 
42
- foreach ( array_diff( $old_connections, $new_connections ) as $post_b )
43
- p2p_disconnect( $post_a, $post_b );
44
 
45
- foreach ( array_diff( $new_connections, $old_connections ) as $post_b )
46
- p2p_connect( $post_a, $post_b );
47
  }
48
  }
49
 
 
 
 
 
 
 
 
 
 
 
50
  function register( $post_type ) {
 
 
 
 
51
  foreach ( p2p_get_connection_types( $post_type ) as $type ) {
52
  add_meta_box(
53
  'p2p-connections-' . $type,
@@ -63,7 +103,9 @@ class P2P_Box {
63
 
64
  function box( $post, $args ) {
65
  $post_type = $args['args'];
66
- $connected_ids = p2p_get_connected( $post_type, 'from', $post->ID );
 
 
67
  ?>
68
 
69
  <div class="p2p_metabox">
@@ -114,11 +156,24 @@ class P2P_Box {
114
  }
115
 
116
  function ajax_search() {
117
- $posts = new WP_Query( array(
118
- 'posts_per_page' => 5,
 
 
 
 
119
  's' => $_GET['q'],
120
- 'post_type' => $_GET['post_type']
121
- ) );
 
 
 
 
 
 
 
 
 
122
 
123
  $results = array();
124
  while ( $posts->have_posts() ) {
@@ -139,11 +194,5 @@ class P2P_Box {
139
 
140
  return scbUtil::objects_to_assoc( get_posts( $args ), 'ID', 'post_title' );
141
  }
142
-
143
- function uninstall() {
144
- global $wpdb;
145
-
146
- $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '" . P2P_META_KEY . "'" );
147
- }
148
  }
149
 
1
  <?php
2
 
3
+ class P2P_Admin {
4
+
5
+ private static $connections;
6
 
7
  function init( $file ) {
8
  add_action( 'admin_print_styles-post.php', array( __CLASS__, 'scripts' ) );
10
 
11
  add_action( 'add_meta_boxes', array( __CLASS__, 'register' ) );
12
 
13
+ add_action( 'save_post', array( __CLASS__, 'save' ), 10 );
14
  add_action( 'wp_ajax_p2p_search', array( __CLASS__, 'ajax_search' ) );
15
 
16
+ add_action( 'admin_notices', array( __CLASS__, 'migrate' ) );
17
+ }
18
+
19
+ function migrate() {
20
+ if ( !isset( $_GET['migrate_p2p'] ) || !current_user_can( 'administrator' ) )
21
+ return;
22
+
23
+ global $wpdb;
24
+
25
+ $rows = $wpdb->get_results( "
26
+ SELECT post_id as post_a, meta_value as post_b
27
+ FROM $wpdb->postmeta
28
+ WHERE meta_key = '_p2p'
29
+ " );
30
+
31
+ $grouped = array();
32
+ foreach ( $rows as $row )
33
+ $grouped[ $row->post_a ][] = $row->post_b;
34
+
35
+ foreach ( $grouped as $post_a => $post_b )
36
+ p2p_connect( $post_a, $post_b );
37
+
38
+ $wpdb->query( "DELETE FROM $wpdb->postmeta WHERE meta_key = '_p2p'" );
39
+
40
+ printf( "<div class='updated'><p>Migrated %s connections.</p></div>", count( $rows ) );
41
  }
42
 
43
  function scripts() {
52
  <?php
53
  }
54
 
55
+ function save( $post_a ) {
56
+ $current_ptype = get_post_type( $post_a );
57
+ if ( defined( 'DOING_AJAX' ) || defined( 'DOING_CRON' ) || empty( $_POST ) || 'revision' == $current_ptype )
58
  return;
59
 
60
+ self::cache_connections( $post_a );
61
 
62
+ foreach ( p2p_get_connection_types( $current_ptype ) as $post_type ) {
63
  if ( !isset( $_POST['p2p_connected_ids_' . $post_type] ) )
64
  continue;
65
 
66
+ $reciprocal = p2p_connection_type_is_reciprocal( $current_ptype, $post_type );
 
67
 
68
+ $old_connections = (array) @self::$connections[ $post_type ];
69
+ $new_connections = explode( ',', $_POST[ 'p2p_connected_ids_' . $post_type ] );
70
 
71
+ p2p_disconnect( $post_a, array_diff( $old_connections, $new_connections ), $reciprocal );
72
+ p2p_connect( $post_a, array_diff( $new_connections, $old_connections ), $reciprocal );
73
  }
74
  }
75
 
76
+ private function cache_connections( $post_id ) {
77
+ $posts = p2p_get_connected( $post_id, 'from', 'any', 'objects' );
78
+
79
+ $connections = array();
80
+ foreach ( $posts as $post )
81
+ $connections[ $post->post_type ][] = $post->ID;
82
+
83
+ self::$connections = $connections;
84
+ }
85
+
86
  function register( $post_type ) {
87
+ global $post;
88
+
89
+ self::cache_connections( $post->ID );
90
+
91
  foreach ( p2p_get_connection_types( $post_type ) as $type ) {
92
  add_meta_box(
93
  'p2p-connections-' . $type,
103
 
104
  function box( $post, $args ) {
105
  $post_type = $args['args'];
106
+
107
+ $connected_ids = @self::$connections[ $post_type ];
108
+
109
  ?>
110
 
111
  <div class="p2p_metabox">
156
  }
157
 
158
  function ajax_search() {
159
+ $post_type_name = $_GET['post_type'];
160
+
161
+ if ( !post_type_exists( $post_type_name ) )
162
+ die;
163
+
164
+ $args = array(
165
  's' => $_GET['q'],
166
+ 'post_type' => $post_type_name,
167
+ 'post_status' => 'any',
168
+ 'posts_per_page' => 5,
169
+ 'order' => 'ASC',
170
+ 'orderby' => 'title',
171
+ 'suppress_filters' => true,
172
+ 'update_post_term_cache' => false,
173
+ 'update_post_meta_cache' => false
174
+ );
175
+
176
+ $posts = new WP_Query( $args );
177
 
178
  $results = array();
179
  while ( $posts->have_posts() ) {
194
 
195
  return scbUtil::objects_to_assoc( get_posts( $args ), 'ID', 'post_title' );
196
  }
 
 
 
 
 
 
197
  }
198
 
api.php CHANGED
@@ -1,14 +1,14 @@
1
  <?php
2
 
3
  /**
4
- * Register a connection between two post types.
5
  * This creates the appropriate meta box in the admin edit screen
6
  *
7
  * @param string $post_type_a The first end of the connection
8
- * @param string $post_type_a The second end of the connection
9
- * @param bool $bydirectional Wether the connection should be bydirectional
10
  */
11
- function p2p_register_connection_type( $post_type_a, $post_type_b, $bydirectional = false ) {
12
  if ( !$ptype = get_post_type_object( $post_type_a ) )
13
  return;
14
 
@@ -22,7 +22,7 @@ function p2p_register_connection_type( $post_type_a, $post_type_b, $bydirectiona
22
 
23
  $ptype->can_connect_to = array_merge( $ptype->can_connect_to, $post_type_b );
24
 
25
- if ( $bydirectional )
26
  foreach ( $post_type_b as $ptype_b )
27
  p2p_register_connection_type( $ptype_b, $post_type_a, false );
28
  }
@@ -38,32 +38,48 @@ function p2p_get_connection_types( $post_type_a ) {
38
  return (array) @get_post_type_object( $post_type_a )->can_connect_to;
39
  }
40
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  /**
42
  * Connect a post to another one
43
  *
44
  * @param int $post_a The first end of the connection
45
- * @param int $post_b The second end of the connection
46
- * @param bool $bydirectional Wether the connection should be bydirectional
47
  */
48
- function p2p_connect( $post_a, $post_b, $bydirectional = false ) {
49
- add_post_meta( $post_a, P2P_META_KEY, $post_b );
50
 
51
- if ( $bydirectional )
52
- add_post_meta( $post_b, P2P_META_KEY, $post_a );
 
53
  }
54
 
55
  /**
56
  * Disconnect a post from another one
57
  *
58
  * @param int $post_a The first end of the connection
59
- * @param int $post_b The second end of the connection
60
- * @param bool $bydirectional Wether the connection should be bydirectional
61
  */
62
- function p2p_disconnect( $post_a, $post_b, $bydirectional = false ) {
63
- delete_post_meta( $post_a, P2P_META_KEY, $post_b );
64
 
65
- if ( $bydirectional )
66
- delete_post_meta( $post_b, P2P_META_KEY, $post_a );
 
67
  }
68
 
69
  /**
@@ -71,15 +87,14 @@ function p2p_disconnect( $post_a, $post_b, $bydirectional = false ) {
71
  *
72
  * @param int $post_a The first end of the connection
73
  * @param int $post_b The second end of the connection
74
- * @param bool $bydirectional Wether the connection should be bydirectional
75
  *
76
  * @return bool True if the connection exists, false otherwise
77
  */
78
- function p2p_is_connected( $post_a, $post_b, $bydirectional = false ) {
79
- $r = (bool) get_post_meta( $post_b, P2P_META_KEY, $post_a, true );
80
 
81
- if ( $bydirectional )
82
- $r = $r && p2p_is_connected( $post_b, $post_a );
83
 
84
  return $r;
85
  }
@@ -87,120 +102,55 @@ function p2p_is_connected( $post_a, $post_b, $bydirectional = false ) {
87
  /**
88
  * Get the list of connected posts
89
  *
90
- * @param string $post_type The post type of the connected posts.
91
- * @param string $direction The direction of the connection. Can be 'to' or 'from'
92
  * @param int $post_id One end of the connection
93
- * @param bool $grouped Wether the results should be grouped by post type
94
- *
95
- * @return array[int] if $grouped is True
96
- * @return array[string => array[int]] if $grouped is False
97
- */
98
- function p2p_get_connected( $post_type, $direction, $post_id, $grouped = false ) {
99
- global $wpdb;
100
-
101
- $post_id = absint( $post_id );
102
-
103
- if ( !$post_id || ( 'any' != $post_type && !post_type_exists( $post_type ) ) )
104
- return false;
105
-
106
- if ( 'to' == $direction ) {
107
- $col_a = 'post_id';
108
- $col_b = 'meta_value';
109
- } else {
110
- $col_b = 'post_id';
111
- $col_a = 'meta_value';
112
- }
113
-
114
- if ( 'any' == $post_type && $grouped ) {
115
- $query = "
116
- SELECT $col_a AS post_id, (
117
- SELECT post_type
118
- FROM $wpdb->posts
119
- WHERE $wpdb->posts.ID = $col_a
120
- ) AS type
121
- FROM $wpdb->postmeta
122
- WHERE meta_key = '" . P2P_META_KEY . "'
123
- AND $col_b = $post_id
124
- ";
125
-
126
- $connections = array();
127
- foreach ( $wpdb->get_results( $query ) as $row )
128
- $connections[$row->type][] = $row->post_id;
129
-
130
- return $connections;
131
- }
132
-
133
- $where = "
134
- WHERE meta_key = '" . P2P_META_KEY . "'
135
- AND $col_b = $post_id
136
- ";
137
-
138
- if ( 'any' != $post_type )
139
- $where .= $wpdb->prepare( "
140
- AND $col_a IN (
141
- SELECT ID
142
- FROM $wpdb->posts
143
- WHERE post_type = %s
144
- )
145
- ", $post_type );
146
-
147
- $connections = $wpdb->get_col( "
148
- SELECT $col_a
149
- FROM $wpdb->postmeta
150
- $where
151
- " );
152
-
153
- if ( $grouped )
154
- return array( $post_type => $connections );
155
-
156
- return $connections;
157
- }
158
-
159
- /**
160
- * Display the list of connected posts
161
- *
162
- * @param string $post_type The post type of the connected posts.
163
  * @param string $direction The direction of the connection. Can be 'to' or 'from'
164
- * @param int $post_id One end of the connection
165
- * @param callback(WP_Query) $callback the function used to do the actual displaying
 
 
 
166
  */
167
- function p2p_list_connected( $post_type = 'any', $direction = 'from', $post_id = '', $callback = '' ) {
168
- if ( !$post_id )
169
- $post_id = get_the_ID();
170
 
171
- $connected_post_ids = p2p_get_connected( $post_type, $direction, $post_id );
 
172
 
173
- if ( empty( $connected_post_ids ) )
174
- return;
175
 
176
  $args = array(
177
- 'post__in' => $connected_post_ids,
178
  'post_type'=> $post_type,
 
179
  'nopaging' => true,
180
  );
181
- $query = new WP_Query( $args );
182
 
183
- if ( empty( $callback ) )
184
- $callback = '_p2p_list_connected';
 
 
185
 
186
- call_user_func( $callback, $query );
 
187
 
188
- wp_reset_postdata();
189
  }
190
 
191
  /**
192
- * The default callback for p2p_list_connected()
193
- * Lists the posts as an unordered list
194
  *
195
- * @param WP_Query
196
  */
197
- function _p2p_list_connected( $query ) {
198
- if ( $query->have_posts() ) :
199
- echo '<ul>';
200
- while ( $query->have_posts() ) : $query->the_post();
201
- echo html( 'li', html_link( get_permalink( get_the_ID() ), get_the_title() ) );
202
- endwhile;
203
- echo '</ul>';
204
- endif;
 
 
205
  }
206
 
1
  <?php
2
 
3
  /**
4
+ * Register a connection between two post types.
5
  * This creates the appropriate meta box in the admin edit screen
6
  *
7
  * @param string $post_type_a The first end of the connection
8
+ * @param string|array $post_type_b The second end of the connection
9
+ * @param bool $reciprocal Wether the connection should be reciprocal
10
  */
11
+ function p2p_register_connection_type( $post_type_a, $post_type_b, $reciprocal = false ) {
12
  if ( !$ptype = get_post_type_object( $post_type_a ) )
13
  return;
14
 
22
 
23
  $ptype->can_connect_to = array_merge( $ptype->can_connect_to, $post_type_b );
24
 
25
+ if ( $reciprocal )
26
  foreach ( $post_type_b as $ptype_b )
27
  p2p_register_connection_type( $ptype_b, $post_type_a, false );
28
  }
38
  return (array) @get_post_type_object( $post_type_a )->can_connect_to;
39
  }
40
 
41
+ /**
42
+ * Check wether a connection type is reciprocal
43
+ *
44
+ * @param string $post_type_a The first end of the connection
45
+ * @param string $post_type_b The second end of the connection
46
+ *
47
+ * @return bool
48
+ */
49
+ function p2p_connection_type_is_reciprocal( $post_type_a, $post_type_b ) {
50
+ return
51
+ in_array( $post_type_b, p2p_get_connection_types( $post_type_a ) ) &&
52
+ in_array( $post_type_a, p2p_get_connection_types( $post_type_b ) );
53
+ }
54
+
55
  /**
56
  * Connect a post to another one
57
  *
58
  * @param int $post_a The first end of the connection
59
+ * @param int|array $post_b The second end of the connection
60
+ * @param bool $reciprocal Wether the connection is reciprocal or not
61
  */
62
+ function p2p_connect( $post_a, $post_b, $reciprocal = false ) {
63
+ Posts2Posts::connect( $post_a, $post_b );
64
 
65
+ if ( $reciprocal )
66
+ foreach ( $post_b as $single )
67
+ Posts2Posts::connect( $single, $post_a );
68
  }
69
 
70
  /**
71
  * Disconnect a post from another one
72
  *
73
  * @param int $post_a The first end of the connection
74
+ * @param int|array $post_b The second end of the connection
75
+ * @param bool $reciprocal Wether the connection is reciprocal or not
76
  */
77
+ function p2p_disconnect( $post_a, $post_b, $reciprocal = false ) {
78
+ Posts2Posts::disconnect( $post_a, $post_b );
79
 
80
+ if ( $reciprocal )
81
+ foreach ( $post_b as $single )
82
+ Posts2Posts::disconnect( $single, $post_a );
83
  }
84
 
85
  /**
87
  *
88
  * @param int $post_a The first end of the connection
89
  * @param int $post_b The second end of the connection
 
90
  *
91
  * @return bool True if the connection exists, false otherwise
92
  */
93
+ function p2p_is_connected( $post_a, $post_b, $reciprocal = false ) {
94
+ $r = Posts2Posts::is_connected( $post_a, $post_b );
95
 
96
+ if ( $reciprocal )
97
+ $r = $r && Posts2Posts::is_connected( $post_b, $post_a );
98
 
99
  return $r;
100
  }
102
  /**
103
  * Get the list of connected posts
104
  *
 
 
105
  * @param int $post_id One end of the connection
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  * @param string $direction The direction of the connection. Can be 'to' or 'from'
107
+ * @param string|array $post_type The post type of the connected posts.
108
+ * @param string $output Can be 'ids' or 'objects'
109
+ *
110
+ * @return array A list of post_ids if $output = 'ids'
111
+ * @return object A WP_Query instance otherwise
112
  */
113
+ function p2p_get_connected( $post_id, $direction = 'to', $post_type = 'any', $output = 'ids' ) {
114
+ $ids = Posts2Posts::get_connected( $post_id, $direction );
 
115
 
116
+ if ( empty( $ids ) )
117
+ return array();
118
 
119
+ if ( 'any' == $post_type && 'ids' == $output )
120
+ return $ids;
121
 
122
  $args = array(
123
+ 'post__in' => $ids,
124
  'post_type'=> $post_type,
125
+ 'post_status' => 'any',
126
  'nopaging' => true,
127
  );
 
128
 
129
+ $posts = get_posts( $args );
130
+
131
+ if ( 'objects' == $output )
132
+ return $posts;
133
 
134
+ foreach ( $posts as &$post )
135
+ $post = $post->ID;
136
 
137
+ return $posts;
138
  }
139
 
140
  /**
141
+ * Display the list of connected posts as an unordered list
 
142
  *
143
+ * @param array $args See p2p_get_connected()
144
  */
145
+ function p2p_list_connected( $post_id, $direction = 'to', $post_type = 'any' ) {
146
+ $posts = p2p_get_connected( $post_id, $direction, $post_type, 'objects' );
147
+
148
+ if ( empty( $posts ) )
149
+ return;
150
+
151
+ echo '<ul>';
152
+ foreach ( $posts as $post )
153
+ echo html( 'li', html_link( get_permalink( $post->ID ), get_the_title( $post->ID ) ) );
154
+ echo '</ul>';
155
  }
156
 
core.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ // Abstraction layer for connection storage
4
+
5
+ class Posts2Posts {
6
+ const TAX = 'p2p';
7
+
8
+ function init() {
9
+ add_action( 'init', array( __CLASS__, 'setup' ) );
10
+ add_action( 'delete_post', array( __CLASS__, 'delete_post' ) );
11
+ }
12
+
13
+ function setup() {
14
+ register_taxonomy( self::TAX, 'post', array( 'public' => false ) );
15
+ }
16
+
17
+ function delete_post( $post_id ) {
18
+ wp_delete_term( self::convert( 'term', $post_id ), self::TAX );
19
+ }
20
+
21
+ function connect( $post_a, $post_b ) {
22
+ if ( empty( $post_a ) )
23
+ return;
24
+
25
+ $terms = self::convert( 'term', $post_b );
26
+
27
+ if ( empty( $terms ) )
28
+ return;
29
+
30
+ wp_set_object_terms( $post_a, $terms, self::TAX, true );
31
+ }
32
+
33
+ function disconnect( $post_a, $post_b ) {
34
+ if ( empty( $post_a ) )
35
+ return;
36
+
37
+ $terms = self::convert( 'term', $post_b );
38
+
39
+ if ( empty( $terms ) )
40
+ return;
41
+
42
+ $list = wp_get_object_terms( $post_a, self::TAX, 'fields=names' );
43
+
44
+ wp_set_object_terms( $post_a, array_diff( $list, $terms ), self::TAX );
45
+ }
46
+
47
+ function is_connected( $post_a, $post_b ) {
48
+ $terms = self::convert( 'term', $post_b );
49
+
50
+ return is_object_in_term( $post_a, $terms, self::TAX );
51
+ }
52
+
53
+ function get_connected( $post_id, $direction ) {
54
+ if ( 'from' == $direction ) {
55
+ $terms = wp_get_object_terms( $post_id, self::TAX, array( 'fields' => 'names' ) );
56
+ return self::convert( 'post', $terms );
57
+ } else {
58
+ $term = get_term_by( 'slug', reset( self::convert( 'term', $post_id ) ), self::TAX )->term_id;
59
+ return get_objects_in_term( $term, self::TAX );
60
+ }
61
+ }
62
+
63
+ // Add a 'p' to avoid confusion with term ids
64
+ private function convert( $to, $ids ) {
65
+ $ids = array_filter( (array) $ids );
66
+
67
+ if ( 'term' == $to )
68
+ foreach ( $ids as &$id )
69
+ $id = 'p' . $id;
70
+ else
71
+ foreach ( $ids as &$id )
72
+ $id = substr( $id, 1 );
73
+
74
+ return $ids;
75
+ }
76
+ }
77
+
lang/posts-to-posts.pot CHANGED
@@ -1,4 +1,4 @@
1
- # Translation of the WordPress plugin Posts 2 Posts 0.2-alpha2 by scribu.
2
  # Copyright (C) 2010 scribu
3
  # This file is distributed under the same license as the Posts 2 Posts package.
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
@@ -6,9 +6,9 @@
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
- "Project-Id-Version: Posts 2 Posts 0.2-alpha2\n"
10
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/posts-to-posts\n"
11
- "POT-Creation-Date: 2010-07-15 18:49+0300\n"
12
  "PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,25 +16,25 @@ msgstr ""
16
  "Content-Type: text/plain; charset=utf-8\n"
17
  "Content-Transfer-Encoding: 8bit\n"
18
 
19
- #: admin/admin.php:54
20
  msgid "Connected"
21
  msgstr ""
22
 
23
- #: admin/admin.php:73
24
  msgid "No connections."
25
  msgstr ""
26
 
27
- #: admin/admin.php:92
28
  msgid "Search"
29
  msgstr ""
30
 
31
- #: admin/admin.php:100
32
  msgid ""
33
  "Start typing name of connected post type and click on it if you want to "
34
  "connect it."
35
  msgstr ""
36
 
37
- #: admin/admin.php:110
38
  msgid ""
39
  "Enter IDs of connected post types separated by commas, or turn on JavaScript!"
40
  msgstr ""
1
+ # Translation of the WordPress plugin Posts 2 Posts 0.3-alpha2 by scribu.
2
  # Copyright (C) 2010 scribu
3
  # This file is distributed under the same license as the Posts 2 Posts package.
4
  # FIRST AUTHOR <EMAIL@ADDRESS>, 2010.
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
+ "Project-Id-Version: Posts 2 Posts 0.3-alpha2\n"
10
  "Report-Msgid-Bugs-To: http://wordpress.org/tag/posts-to-posts\n"
11
+ "POT-Creation-Date: 2010-08-04 20:37+0300\n"
12
  "PO-Revision-Date: 2010-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
16
  "Content-Type: text/plain; charset=utf-8\n"
17
  "Content-Transfer-Encoding: 8bit\n"
18
 
19
+ #: admin/admin.php:94
20
  msgid "Connected"
21
  msgstr ""
22
 
23
+ #: admin/admin.php:115
24
  msgid "No connections."
25
  msgstr ""
26
 
27
+ #: admin/admin.php:134
28
  msgid "Search"
29
  msgstr ""
30
 
31
+ #: admin/admin.php:142
32
  msgid ""
33
  "Start typing name of connected post type and click on it if you want to "
34
  "connect it."
35
  msgstr ""
36
 
37
+ #: admin/admin.php:152
38
  msgid ""
39
  "Enter IDs of connected post types separated by commas, or turn on JavaScript!"
40
  msgstr ""
posts-to-posts.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
  Plugin Name: Posts 2 Posts
4
- Version: 0.2
5
  Plugin Author: scribu
6
  Description: Create connections between posts of different types
7
  Author URI: http://scribu.net/
@@ -26,16 +26,17 @@ You should have received a copy of the GNU General Public License
26
  along with this program. If not, see <http://www.gnu.org/licenses/>.
27
  */
28
 
29
- define( 'P2P_META_KEY', '_p2p' );
30
-
31
  require dirname( __FILE__ ) . '/scb/load.php';
32
 
33
  function _p2p_init() {
 
34
  require dirname( __FILE__ ) . '/api.php';
35
 
 
 
36
  if ( is_admin() ) {
37
  require dirname( __FILE__ ) . '/admin/admin.php';
38
- P2P_Box::init( __FILE__ );
39
  }
40
  }
41
  scb_init( '_p2p_init' );
1
  <?php
2
  /*
3
  Plugin Name: Posts 2 Posts
4
+ Version: 0.3
5
  Plugin Author: scribu
6
  Description: Create connections between posts of different types
7
  Author URI: http://scribu.net/
26
  along with this program. If not, see <http://www.gnu.org/licenses/>.
27
  */
28
 
 
 
29
  require dirname( __FILE__ ) . '/scb/load.php';
30
 
31
  function _p2p_init() {
32
+ require dirname( __FILE__ ) . '/core.php';
33
  require dirname( __FILE__ ) . '/api.php';
34
 
35
+ Posts2Posts::init();
36
+
37
  if ( is_admin() ) {
38
  require dirname( __FILE__ ) . '/admin/admin.php';
39
+ P2P_Admin::init( __FILE__ );
40
  }
41
  }
42
  scb_init( '_p2p_init' );
readme.txt CHANGED
@@ -4,26 +4,29 @@ Donate link: http://scribu.net/paypal
4
  Tags: cms, custom post types, relationships, many-to-many
5
  Requires at least: 3.0
6
  Tested up to: 3.0
7
- Stable tag: 0.1
8
 
9
  Create connections between posts
10
 
11
  == Description ==
12
 
13
- This plugin allows you to create relationships between posts of different types. The relationships are stored in the postmeta table.
14
 
15
- To register a connection between two post types, write:
16
 
17
  `
18
  function my_connection_types() {
19
- p2p_register_connection_type('book', 'author');
 
 
 
 
20
  }
21
  add_action('init', 'my_connection_types', 100);
22
  `
23
  <br>
24
 
25
- See [available functions](http://plugins.trac.wordpress.org/browser/posts-to-posts/tags/0.2/api.php).
26
-
27
 
28
  == Installation ==
29
 
@@ -47,9 +50,13 @@ Make sure your host is running PHP 5. The only foolproof way to do this is to ad
47
 
48
  == Changelog ==
49
 
 
 
 
 
50
  = 0.2 =
51
- * added p2p_list_connected() template tag
52
  * UI that supports multiple related posts. props [Patrik Bón](http://www.mrhead.sk/)
 
53
  * [more info](http://scribu.net/wordpress/posts-to-posts/p2p-0-2.html)
54
 
55
  = 0.1 =
4
  Tags: cms, custom post types, relationships, many-to-many
5
  Requires at least: 3.0
6
  Tested up to: 3.0
7
+ Stable tag: 0.3
8
 
9
  Create connections between posts
10
 
11
  == Description ==
12
 
13
+ This plugin allows you to create relationships between posts of different types. The relationships are stored in a hidden taxonomy.
14
 
15
+ To register a connection type, add this code in your theme's functions.php file:
16
 
17
  `
18
  function my_connection_types() {
19
+ if ( !function_exists('p2p_register_connection_type') )
20
+ return;
21
+
22
+ p2p_register_connection_type('book', 'author');
23
+ p2p_register_connection_type('library', 'book');
24
  }
25
  add_action('init', 'my_connection_types', 100);
26
  `
27
  <br>
28
 
29
+ Links: [API](http://plugins.trac.wordpress.org/browser/posts-to-posts/tags/0.3/api.php) | [Plugin News](http://scribu.net/wordpress/posts-to-posts) | [Author's Site](http://scribu.net)
 
30
 
31
  == Installation ==
32
 
50
 
51
  == Changelog ==
52
 
53
+ = 0.3 =
54
+ * store connections using a taxonomy instead of postmeta
55
+ * [more info](http://scribu.net/wordpress/posts-to-posts/p2p-0-3.html)
56
+
57
  = 0.2 =
 
58
  * UI that supports multiple related posts. props [Patrik Bón](http://www.mrhead.sk/)
59
+ * added p2p_list_connected() template tag
60
  * [more info](http://scribu.net/wordpress/posts-to-posts/p2p-0-2.html)
61
 
62
  = 0.1 =
scb/Query.php DELETED
@@ -1,75 +0,0 @@
1
- <?php
2
-
3
- // A decorator for the WP_Query class
4
- class scbQuery {
5
- protected $wp_query;
6
-
7
- public function __construct( $qv = '', $debug = false ) {
8
- if ( $debug )
9
- add_filter( 'posts_request', array( $this, '_debug' ), 999 );
10
-
11
- if ( empty( $qv ) ) {
12
- $this->_add_filters( true );
13
- } else {
14
- $this->_add_filters();
15
- $this->wp_query = new WP_Query( $qv );
16
- $this->_remove_filters();
17
- }
18
- }
19
-
20
- /*
21
- final public function __get( $key ) {
22
- return $this->wp_query->$key;
23
- }
24
-
25
- final public function __call( $name, $args ) {
26
- return call_user_func_array( array( $this->wp_query, $name ), $args );
27
- }
28
- */
29
-
30
- public function _debug( $query ) {
31
- remove_filter( current_filter(), array( $this, __FUNCTION__ ), 999 );
32
-
33
- debug( $query );
34
-
35
- return $query;
36
- }
37
-
38
- public function _add_filters( $runonce = false ) {
39
- if ( $runonce )
40
- foreach ( $this->_find_filters() as $filter )
41
- add_filter( $filter, array( $this, '_dispatch' ), 10, 10 );
42
- else
43
- foreach ( $this->_find_filters() as $filter )
44
- add_filter( $filter, array( $this, $filter ), 10, 10 );
45
- }
46
-
47
- public function _dispatch( $value ) {
48
- $filter = current_filter();
49
-
50
- remove_filter( $filter, array( $this, '_dispatch' ), 10, 10 );
51
-
52
- return $this->$filter( $value );
53
- }
54
-
55
- public function _remove_filters() {
56
- foreach ( $this->_find_filters() as $filter )
57
- remove_filter( $filter, array( $this, $filter ), 10, 10 );
58
- }
59
-
60
- private function _find_filters() {
61
- $filters = array();
62
-
63
- foreach ( _scb_get_public_methods( $this ) as $method )
64
- if ( '_' != substr( $method, 0, 1 ) )
65
- $filters[] = $method;
66
-
67
- return $filters;
68
- }
69
- }
70
-
71
- // Current scope is lost while calling external function
72
- function _scb_get_public_methods( $class ) {
73
- return get_class_methods( $class );
74
- }
75
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scb/QueryManipulation.php ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class scbQueryManipulation {
4
+
5
+ private $bits = array();
6
+ private $wp_query;
7
+
8
+ private static $filters = array(
9
+ 'posts_where',
10
+ 'posts_join',
11
+ 'posts_groupby',
12
+ 'posts_orderby',
13
+ 'posts_distinct',
14
+ 'post_limits',
15
+ 'posts_fields'
16
+ );
17
+
18
+ public function __construct( $callback, $once = true ) {
19
+ $this->callback = $callback;
20
+
21
+ $this->enable();
22
+
23
+ if ( !$once )
24
+ return;
25
+
26
+ add_filter( 'posts_request', array( $this, '_disable' ) );
27
+ }
28
+
29
+ function _disable( $request ) {
30
+ remove_filter( 'posts_request', array( $this, '_disable' ) );
31
+
32
+ $this->disable();
33
+
34
+ return $request;
35
+ }
36
+
37
+ public function enable() {
38
+ foreach ( self::$filters as $filter ) {
39
+ add_filter( $filter, array( $this, 'collect' ), 999, 2 );
40
+ add_filter( $filter . '_request' , array( $this, 'update' ), 9 );
41
+ }
42
+
43
+ add_action( 'posts_selection' , array( $this, 'alter' ) );
44
+ }
45
+
46
+ public function disable() {
47
+ foreach ( self::$filters as $filter ) {
48
+ remove_filter( $filter, array( $this, 'collect' ), 999, 2 );
49
+ remove_filter( $filter . '_request' , array( $this, 'update' ), 9 );
50
+ }
51
+
52
+ remove_action( 'posts_selection' , array( $this, 'alter' ) );
53
+ }
54
+
55
+ function collect( $value, $wp_query ) {
56
+ // remove 'posts_'
57
+ $key = explode( '_', current_filter() );
58
+ $key = array_slice( $key, 1 );
59
+ $key = implode( '_', $key );
60
+
61
+ $this->bits[ $key ] = $value;
62
+
63
+ $this->wp_query = $wp_query;
64
+
65
+ return $value;
66
+ }
67
+
68
+ function alter( $query ) {
69
+ $this->bits = call_user_func( $this->callback, $this->bits, $this->wp_query );
70
+ }
71
+
72
+ function update( $value ) {
73
+ // remove 'posts_' and '_request'
74
+ $key = explode( '_', current_filter() );
75
+ $key = array_slice( $key, 1, -1 );
76
+ $key = implode( '_', $key );
77
+
78
+ return $this->bits[ $key ];
79
+ }
80
+ }
81
+
scb/Util.php CHANGED
@@ -117,8 +117,16 @@ class scbUtil {
117
 
118
 
119
  if ( ! function_exists( 'html' ) ):
120
- function html( $tag, $content = '' ) {
121
- list( $closing ) = explode( ' ', $tag, 2 );
 
 
 
 
 
 
 
 
122
 
123
  return "<{$tag}>{$content}</{$closing}>";
124
  }
117
 
118
 
119
  if ( ! function_exists( 'html' ) ):
120
+ function html($tag, $attributes = array(), $content = '') {
121
+ if ( is_array( $attributes ) ) {
122
+ $closing = $tag;
123
+ foreach ( $attributes as $key => $value ) {
124
+ $tag .= ' ' . $key . '="' . esc_attr( $value ) . '"';
125
+ }
126
+ } else {
127
+ $content = $attributes;
128
+ list($closing) = explode(' ', $tag, 2);
129
+ }
130
 
131
  return "<{$tag}>{$content}</{$closing}>";
132
  }
scb/load.php CHANGED
@@ -1,9 +1,10 @@
1
  <?php
2
 
3
- $GLOBALS['_scb_data'] = array( 22, __FILE__, array(
4
  'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
5
  'scbWidget', 'scbAdminPage', 'scbBoxesPage',
6
- 'scbQuery', 'scbRewrite', 'scbCron', ) );
 
7
 
8
  if ( !class_exists( 'scbLoad4' ) ) :
9
  class scbLoad4 {
1
  <?php
2
 
3
+ $GLOBALS['_scb_data'] = array( 23, __FILE__, array(
4
  'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
5
  'scbWidget', 'scbAdminPage', 'scbBoxesPage',
6
+ 'scbQueryManipulation', 'scbRewrite', 'scbCron',
7
+ ) );
8
 
9
  if ( !class_exists( 'scbLoad4' ) ) :
10
  class scbLoad4 {