Posts 2 Posts - Version 1.4.2

Version Description

  • fixed each_connected() returning wrapped objects
  • fixed issue with user queries and get_current_screen()
  • fixed "Delete all connections" button
  • fixed bugs with reciprocal and non-reciprocal indeterminate connection types
  • added Dutch translation
Download this release

Release Info

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

Code changes from version 1.4.1 to 1.4.2

admin/box-factory.php CHANGED
@@ -63,7 +63,7 @@ class P2P_Box_Factory extends P2P_Factory {
63
  }
64
 
65
  private static function show_box( $directed, $post ) {
66
- $show = $directed->get_opposite( 'side' )->can_edit_connections();
67
 
68
  return apply_filters( 'p2p_admin_box_show', $show, $directed, $post );
69
  }
@@ -71,11 +71,11 @@ class P2P_Box_Factory extends P2P_Factory {
71
  private function create_box( $directed ) {
72
  $box_args = $this->queue[ $directed->name ];
73
 
74
- $title_class = 'P2P_Field_Title_' . ucfirst( $directed->get_opposite( 'object' ) );
75
 
76
  $columns = array(
77
  'delete' => new P2P_Field_Delete,
78
- 'title' => new $title_class( $directed->get_opposite( 'labels' )->singular_name ),
79
  );
80
 
81
  foreach ( $directed->fields as $key => $data ) {
63
  }
64
 
65
  private static function show_box( $directed, $post ) {
66
+ $show = $directed->get( 'opposite', 'side' )->can_edit_connections();
67
 
68
  return apply_filters( 'p2p_admin_box_show', $show, $directed, $post );
69
  }
71
  private function create_box( $directed ) {
72
  $box_args = $this->queue[ $directed->name ];
73
 
74
+ $title_class = 'P2P_Field_Title_' . ucfirst( $directed->get( 'opposite', 'object' ) );
75
 
76
  $columns = array(
77
  'delete' => new P2P_Field_Delete,
78
+ 'title' => new $title_class( $directed->get( 'opposite', 'labels' )->singular_name ),
79
  );
80
 
81
  foreach ( $directed->fields as $key => $data ) {
admin/box.php CHANGED
@@ -25,7 +25,7 @@ class P2P_Box {
25
 
26
  $this->ctype = $ctype;
27
 
28
- $this->labels = $this->ctype->get_opposite( 'labels' );
29
  }
30
 
31
  public function init_scripts() {
@@ -60,7 +60,7 @@ class P2P_Box {
60
  $data_attr = array(
61
  'p2p_type' => $this->ctype->name,
62
  'duplicate_connections' => $this->ctype->duplicate_connections,
63
- 'cardinality' => $this->ctype->get_opposite( 'cardinality' ),
64
  'direction' => $this->ctype->get_direction()
65
  );
66
 
@@ -98,7 +98,7 @@ class P2P_Box {
98
  'label' => $this->labels->create,
99
  );
100
 
101
- if ( 'one' == $this->ctype->get_opposite( 'cardinality' ) ) {
102
  if ( !empty( $this->connected_items ) )
103
  $data['hide'] = 'style="display:none"';
104
  }
@@ -161,7 +161,7 @@ class P2P_Box {
161
  'p2p:per_page' => 5
162
  ) );
163
 
164
- $candidate = $this->ctype->get_connectable( $current_post_id, $extra_qv );
165
 
166
  if ( empty( $candidate->items ) ) {
167
  return html( 'div class="p2p-notice"', $this->labels->not_found );
@@ -207,7 +207,7 @@ class P2P_Box {
207
  $args = array(
208
  'post_title' => $_POST['post_title'],
209
  'post_author' => get_current_user_id(),
210
- 'post_type' => $this->ctype->get_opposite( 'side' )->first_post_type()
211
  );
212
 
213
  $from = absint( $_POST['from'] );
@@ -230,22 +230,15 @@ class P2P_Box {
230
 
231
  $p2p_id = $this->ctype->connect( $from, $to );
232
 
233
- if ( is_wp_error( $p2p_id ) ) {
234
- $r = array(
235
- 'error' => sprintf(
236
- __( "Can't create connection: %s", P2P_TEXTDOMAIN ),
237
- $p2p_id->get_error_message()
238
- )
239
- );
240
- } else {
241
- $item = $this->ctype->get_opposite('side')->item_recognize( $to );
242
 
243
- $r = array(
244
- 'row' => $this->connection_row( $p2p_id, $item, true )
245
- );
246
- }
247
 
248
- die( json_encode( $r ) );
 
 
 
 
249
  }
250
 
251
  public function ajax_disconnect() {
@@ -255,11 +248,24 @@ class P2P_Box {
255
  }
256
 
257
  public function ajax_clear_connections() {
258
- $this->ctype->disconnect( $_POST['from'], 'any' );
 
 
259
 
260
  $this->refresh_candidates();
261
  }
262
 
 
 
 
 
 
 
 
 
 
 
 
263
  public function ajax_search() {
264
  $this->refresh_candidates();
265
  }
@@ -276,7 +282,7 @@ class P2P_Box {
276
  if ( !$this->args->can_create_post )
277
  return false;
278
 
279
- $side = $this->ctype->get_opposite( 'side' );
280
 
281
  return $side->can_create_item();
282
  }
25
 
26
  $this->ctype = $ctype;
27
 
28
+ $this->labels = $this->ctype->get( 'opposite', 'labels' );
29
  }
30
 
31
  public function init_scripts() {
60
  $data_attr = array(
61
  'p2p_type' => $this->ctype->name,
62
  'duplicate_connections' => $this->ctype->duplicate_connections,
63
+ 'cardinality' => $this->ctype->get( 'opposite', 'cardinality' ),
64
  'direction' => $this->ctype->get_direction()
65
  );
66
 
98
  'label' => $this->labels->create,
99
  );
100
 
101
+ if ( 'one' == $this->ctype->get( 'opposite', 'cardinality' ) ) {
102
  if ( !empty( $this->connected_items ) )
103
  $data['hide'] = 'style="display:none"';
104
  }
161
  'p2p:per_page' => 5
162
  ) );
163
 
164
+ $candidate = $this->ctype->get_connectable( $current_post_id, $extra_qv, 'abstract' );
165
 
166
  if ( empty( $candidate->items ) ) {
167
  return html( 'div class="p2p-notice"', $this->labels->not_found );
207
  $args = array(
208
  'post_title' => $_POST['post_title'],
209
  'post_author' => get_current_user_id(),
210
+ 'post_type' => $this->ctype->get( 'opposite', 'side' )->first_post_type()
211
  );
212
 
213
  $from = absint( $_POST['from'] );
230
 
231
  $p2p_id = $this->ctype->connect( $from, $to );
232
 
233
+ self::maybe_send_error( $p2p_id );
 
 
 
 
 
 
 
 
234
 
235
+ $item = $this->ctype->get( 'opposite','side')->item_recognize( $to );
 
 
 
236
 
237
+ $out = array(
238
+ 'row' => $this->connection_row( $p2p_id, $item, true )
239
+ );
240
+
241
+ die( json_encode( $out ) );
242
  }
243
 
244
  public function ajax_disconnect() {
248
  }
249
 
250
  public function ajax_clear_connections() {
251
+ $r = $this->ctype->disconnect( $_POST['from'], 'any' );
252
+
253
+ self::maybe_send_error( $r );
254
 
255
  $this->refresh_candidates();
256
  }
257
 
258
+ protected static function maybe_send_error( $r ) {
259
+ if ( !is_wp_error( $r ) )
260
+ return;
261
+
262
+ $out = array(
263
+ 'error' => $r->get_error_message()
264
+ );
265
+
266
+ die( json_encode( $out ) );
267
+ }
268
+
269
  public function ajax_search() {
270
  $this->refresh_candidates();
271
  }
282
  if ( !$this->args->can_create_post )
283
  return false;
284
 
285
+ $side = $this->ctype->get( 'opposite', 'side' );
286
 
287
  return $side->can_create_item();
288
  }
admin/column.php CHANGED
@@ -29,7 +29,7 @@ abstract class P2P_Column {
29
  $this->ctype->name
30
  );
31
 
32
- $columns[ $this->column_id ] = $this->ctype->get_current( 'title' );
33
 
34
  return $columns;
35
  }
29
  $this->ctype->name
30
  );
31
 
32
+ $columns[ $this->column_id ] = $this->ctype->get( 'current', 'title' );
33
 
34
  return $columns;
35
  }
admin/fields.php CHANGED
@@ -58,15 +58,10 @@ class P2P_Field_Generic implements P2P_Field {
58
  }
59
 
60
  function render( $p2p_id, $_ ) {
61
- $args = array(
62
- 'name' => array( 'p2p_meta', $p2p_id, $this->key ),
63
- 'type' => $this->data['type']
64
- );
65
-
66
- if ( isset( $this->data['values'] ) )
67
- $args['values'] = $this->data['values'];
68
 
69
- if ( 'select' == $args['type'] )
70
  $args['text'] = '';
71
 
72
  return scbForms::input_from_meta( $args, $p2p_id, 'p2p' );
58
  }
59
 
60
  function render( $p2p_id, $_ ) {
61
+ $args = $this->data;
62
+ $args['name'] = array( 'p2p_meta', $p2p_id, $this->key );
 
 
 
 
 
63
 
64
+ if ( 'select' == $args['type'] && !isset( $args['text'] ) )
65
  $args['text'] = '';
66
 
67
  return scbForms::input_from_meta( $args, $p2p_id, 'p2p' );
core/api.php CHANGED
@@ -321,7 +321,7 @@ function p2p_list_posts( $posts, $args = array() ) {
321
  if ( is_a( $posts, 'P2P_List' ) ) {
322
  $list = $posts;
323
  } else {
324
- $list = new P2P_List_Post( $posts );
325
  }
326
 
327
  return $list->render( $args );
321
  if ( is_a( $posts, 'P2P_List' ) ) {
322
  $list = $posts;
323
  } else {
324
+ $list = new P2P_List( $posts, 'P2P_Item_Post' );
325
  }
326
 
327
  return $list->render( $args );
core/directed-type.php CHANGED
@@ -34,33 +34,49 @@ class P2P_Directed_Connection_Type {
34
  return $this->set_direction( _p2p_flip_direction( $this->direction ) );
35
  }
36
 
37
- public function get_opposite( $key ) {
38
- $direction = ( 'to' == $this->direction ) ? 'from' : 'to';
39
-
40
- return $this->get_arg( $key, $direction );
41
- }
42
-
43
- public function get_current( $key ) {
44
- $direction = ( 'to' == $this->direction ) ? 'to' : 'from';
45
-
46
- return $this->get_arg( $key, $direction );
47
- }
 
 
 
 
 
 
48
 
49
- private function get_arg( $key, $direction ) {
50
  $arg = $this->ctype->$key;
51
 
52
- return $arg[$direction];
53
  }
54
 
55
- private function abstract_query( $qv, $side, $output = 'abstract' ) {
 
 
 
56
  $query = $side->do_query( $qv );
57
 
58
  if ( 'raw' == $output )
59
  return $query;
60
 
61
- $class = str_replace( 'P2P_Side_', 'P2P_List_', get_class( $side ) );
 
 
 
 
 
 
 
 
62
 
63
- return new $class( $query );
64
  }
65
 
66
  /**
@@ -90,15 +106,13 @@ class P2P_Directed_Connection_Type {
90
  * @return object
91
  */
92
  public function get_connected( $item, $extra_qv = array(), $output = 'raw' ) {
93
- $side = $this->get_opposite( 'side' );
94
-
95
- $args = array_merge( $side->translate_qv( $extra_qv ), array(
96
  'connected_type' => $this->name,
97
  'connected_direction' => $this->direction,
98
  'connected_items' => $item
99
  ) );
100
 
101
- return $this->abstract_query( $args, $side, $output );
102
  }
103
 
104
  public function get_orderby_key() {
@@ -120,27 +134,22 @@ class P2P_Directed_Connection_Type {
120
  *
121
  * @param mixed $arg The item to find connection candidates for.
122
  */
123
- public function get_connectable( $arg, $extra_qv = array() ) {
124
- $side = $this->get_opposite( 'side' );
125
 
126
- $item = $this->get_current( 'side' )->item_recognize( $arg );
127
 
128
  $extra_qv['p2p:exclude'] = $this->get_non_connectable( $item, $extra_qv );
129
 
130
- $extra_qv = $side->get_base_qv( $side->translate_qv( $extra_qv ) );
131
-
132
  $qv = apply_filters( 'p2p_connectable_args', $extra_qv, $this, $item->get_object() );
133
 
134
- return $this->abstract_query( $qv, $side );
135
  }
136
 
137
- private function get_non_connectable( $item, $extra_qv ) {
138
  $to_exclude = array();
139
 
140
- if ( $this->indeterminate && !$this->self_connections )
141
- $to_exclude[] = $item->get_id();
142
-
143
- if ( 'one' == $this->get_current( 'cardinality' ) ) {
144
  $to_check = 'any';
145
  } elseif ( !$this->duplicate_connections ) {
146
  $to_check = $item;
@@ -156,6 +165,22 @@ class P2P_Directed_Connection_Type {
156
  return $to_exclude;
157
  }
158
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  /**
160
  * Connect two items.
161
  *
@@ -166,13 +191,11 @@ class P2P_Directed_Connection_Type {
166
  * @return int|object p2p_id or WP_Error on failure
167
  */
168
  public function connect( $from, $to, $meta = array() ) {
169
- $from = $this->get_current( 'side' )->item_recognize( $from );
170
- if ( !$from )
171
- return new WP_Error( 'first_parameter', 'Invalid first parameter.' );
172
 
173
- $to = $this->get_opposite( 'side' )->item_recognize( $to );
174
- if ( !$to )
175
- return new WP_Error( 'second_parameter', 'Invalid second parameter.' );
176
 
177
  if ( !$this->self_connections && $from->get_id() == $to->get_id() )
178
  return new WP_Error( 'self_connection', 'Connection between an element and itself is not allowed.' );
@@ -180,13 +203,13 @@ class P2P_Directed_Connection_Type {
180
  if ( !$this->duplicate_connections && $this->get_p2p_id( $from, $to ) )
181
  return new WP_Error( 'duplicate_connection', 'Duplicate connections are not allowed.' );
182
 
183
- if ( 'one' == $this->get_opposite( 'cardinality' ) ) {
184
  if ( $this->has_connections( $from ) )
185
  return new WP_Error( 'cardinality_opposite', 'Cardinality problem (opposite).' );
186
  }
187
 
188
- if ( 'one' == $this->get_current( 'cardinality' ) ) {
189
- if ( $this->has_connections( $to ) )
190
  return new WP_Error( 'cardinality_current', 'Cardinality problem (current).' );
191
  }
192
 
@@ -210,7 +233,7 @@ class P2P_Directed_Connection_Type {
210
  protected function has_connections( $item ) {
211
  $extra_qv = array( 'p2p:per_page' => 1 );
212
 
213
- $connections = $this->lose_direction()->get_connected( $item, $extra_qv, 'abstract' );
214
 
215
  return !empty( $connections->items );
216
  }
@@ -234,17 +257,11 @@ class P2P_Directed_Connection_Type {
234
  * @return int|object count or WP_Error on failure
235
  */
236
  public function disconnect( $from, $to ) {
237
- $from = $this->get_current( 'side' )->item_recognize( $from );
238
- if ( !$from )
239
- return new WP_Error( 'first_parameter', 'Invalid first parameter.' );
240
-
241
- if ( 'any' != $to ) {
242
- $to = $this->get_opposite( 'side' )->item_recognize( $to );
243
- if ( !$to )
244
- return new WP_Error( 'second_parameter', 'Invalid second parameter.' );
245
- }
246
 
247
- return $this->delete_connections( compact( 'from', 'to' ) );
248
  }
249
 
250
  public function get_p2p_id( $from, $to ) {
34
  return $this->set_direction( _p2p_flip_direction( $this->direction ) );
35
  }
36
 
37
+ public function get( $side, $key ) {
38
+ switch ( $side ) {
39
+ case 'current':
40
+ $map = array(
41
+ 'to' => 'to',
42
+ 'from' => 'from',
43
+ 'any' => 'from'
44
+ );
45
+ break;
46
+ case 'opposite':
47
+ $map = array(
48
+ 'to' => 'from',
49
+ 'from' => 'to',
50
+ 'any' => 'to'
51
+ );
52
+ break;
53
+ }
54
 
 
55
  $arg = $this->ctype->$key;
56
 
57
+ return $arg[ $map[ $this->direction ] ];
58
  }
59
 
60
+ private function abstract_query( $qv, $which, $output = 'abstract' ) {
61
+ $side = $this->get( $which, 'side' );
62
+
63
+ $qv = $this->get_final_qv( $qv, $which );
64
  $query = $side->do_query( $qv );
65
 
66
  if ( 'raw' == $output )
67
  return $query;
68
 
69
+ return $side->get_list( $query );
70
+ }
71
+
72
+ protected function recognize( $item, $which = 'current' ) {
73
+ return $this->get( $which, 'side' )->item_recognize( $item );
74
+ }
75
+
76
+ public function get_final_qv( $q, $which = 'current' ) {
77
+ $side = $this->get( $which, 'side' );
78
 
79
+ return $side->get_base_qv( $side->translate_qv( $q ) );
80
  }
81
 
82
  /**
106
  * @return object
107
  */
108
  public function get_connected( $item, $extra_qv = array(), $output = 'raw' ) {
109
+ $args = array_merge( $extra_qv, array(
 
 
110
  'connected_type' => $this->name,
111
  'connected_direction' => $this->direction,
112
  'connected_items' => $item
113
  ) );
114
 
115
+ return $this->abstract_query( $args, 'opposite', $output );
116
  }
117
 
118
  public function get_orderby_key() {
134
  *
135
  * @param mixed $arg The item to find connection candidates for.
136
  */
137
+ public function get_connectable( $arg, $extra_qv = array(), $output = 'raw' ) {
138
+ $side = $this->get( 'opposite', 'side' );
139
 
140
+ $item = $this->recognize( $arg );
141
 
142
  $extra_qv['p2p:exclude'] = $this->get_non_connectable( $item, $extra_qv );
143
 
 
 
144
  $qv = apply_filters( 'p2p_connectable_args', $extra_qv, $this, $item->get_object() );
145
 
146
+ return $this->abstract_query( $qv, 'opposite', $output );
147
  }
148
 
149
+ protected function get_non_connectable( $item, $extra_qv ) {
150
  $to_exclude = array();
151
 
152
+ if ( 'one' == $this->get( 'current', 'cardinality' ) ) {
 
 
 
153
  $to_check = 'any';
154
  } elseif ( !$this->duplicate_connections ) {
155
  $to_check = $item;
165
  return $to_exclude;
166
  }
167
 
168
+ private function _check_params( $from_arg, $to_arg ) {
169
+ $from = $this->recognize( $from_arg, 'current' );
170
+ if ( !$from )
171
+ return new WP_Error( 'first_parameter', 'Invalid first parameter.' );
172
+
173
+ if ( 'any' == $to_arg ) {
174
+ $to = 'any';
175
+ } else {
176
+ $to = $this->recognize( $to_arg, 'opposite' );
177
+ if ( !$to )
178
+ return new WP_Error( 'second_parameter', 'Invalid second parameter.' );
179
+ }
180
+
181
+ return compact( 'from', 'to' );
182
+ }
183
+
184
  /**
185
  * Connect two items.
186
  *
191
  * @return int|object p2p_id or WP_Error on failure
192
  */
193
  public function connect( $from, $to, $meta = array() ) {
194
+ $r = $this->_check_params( $from, $to );
195
+ if ( is_wp_error( $r ) )
196
+ return $r;
197
 
198
+ extract( $r );
 
 
199
 
200
  if ( !$this->self_connections && $from->get_id() == $to->get_id() )
201
  return new WP_Error( 'self_connection', 'Connection between an element and itself is not allowed.' );
203
  if ( !$this->duplicate_connections && $this->get_p2p_id( $from, $to ) )
204
  return new WP_Error( 'duplicate_connection', 'Duplicate connections are not allowed.' );
205
 
206
+ if ( 'one' == $this->get( 'opposite', 'cardinality' ) ) {
207
  if ( $this->has_connections( $from ) )
208
  return new WP_Error( 'cardinality_opposite', 'Cardinality problem (opposite).' );
209
  }
210
 
211
+ if ( 'one' == $this->get( 'current', 'cardinality' ) ) {
212
+ if ( $this->flip_direction()->has_connections( $to ) )
213
  return new WP_Error( 'cardinality_current', 'Cardinality problem (current).' );
214
  }
215
 
233
  protected function has_connections( $item ) {
234
  $extra_qv = array( 'p2p:per_page' => 1 );
235
 
236
+ $connections = $this->get_connected( $item, $extra_qv, 'abstract' );
237
 
238
  return !empty( $connections->items );
239
  }
257
  * @return int|object count or WP_Error on failure
258
  */
259
  public function disconnect( $from, $to ) {
260
+ $r = $this->_check_params( $from, $to );
261
+ if ( is_wp_error( $r ) )
262
+ return $r;
 
 
 
 
 
 
263
 
264
+ return $this->delete_connections( $r );
265
  }
266
 
267
  public function get_p2p_id( $from, $to ) {
core/indeterminate-type.php ADDED
@@ -0,0 +1,40 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class P2P_Indeterminate_Connection_Type extends P2P_Directed_Connection_Type {
4
+
5
+ protected function recognize( $arg ) {
6
+ foreach ( array( 'current', 'opposite' ) as $side ) {
7
+ $item = $this->get( $side, 'side' )->item_recognize( $arg );
8
+ if ( $item )
9
+ return $item;
10
+ }
11
+
12
+ return false;
13
+ }
14
+
15
+ public function get_final_qv( $q ) {
16
+ $side = $this->get( 'current', 'side' );
17
+
18
+ // the sides are of the same type, so just use one for translating
19
+ $q = $side->translate_qv( $q );
20
+
21
+ $args = $side->get_base_qv( $q );
22
+
23
+ $other_qv = $this->get( 'opposite', 'side' )->get_base_qv( $q );
24
+
25
+ // need to be inclusive
26
+ if ( isset( $other_qv['post_type'] ) )
27
+ _p2p_append( $args['post_type'], $other_qv['post_type'] );
28
+
29
+ return $args;
30
+ }
31
+
32
+ protected function get_non_connectable( $item, $extra_qv ) {
33
+ $to_exclude = parent::get_non_connectable( $item, $extra_qv );
34
+
35
+ if ( !$this->self_connections )
36
+ $to_exclude[] = $item->get_id();
37
+
38
+ return $to_exclude;
39
+ }
40
+ }
core/item.php CHANGED
@@ -8,10 +8,18 @@ abstract class P2P_Item {
8
  $this->item = $item;
9
  }
10
 
 
 
 
 
11
  function __get( $key ) {
12
  return $this->item->$key;
13
  }
14
 
 
 
 
 
15
  function get_object() {
16
  return $this->item;
17
  }
8
  $this->item = $item;
9
  }
10
 
11
+ function __isset( $key ) {
12
+ return isset( $this->item->$key );
13
+ }
14
+
15
  function __get( $key ) {
16
  return $this->item->$key;
17
  }
18
 
19
+ function __set( $key, $value ) {
20
+ $this->item->$key = $value;
21
+ }
22
+
23
  function get_object() {
24
  return $this->item;
25
  }
core/list.php CHANGED
@@ -1,18 +1,17 @@
1
  <?php
2
 
3
- abstract class P2P_List {
4
 
5
  public $items;
6
  public $current_page = 1;
7
  public $total_pages = 0;
8
 
9
- function __construct( $items ) {
10
  if ( is_numeric( reset( $items ) ) ) {
11
  // Don't wrap when we just have a list of ids
12
  $this->items = $items;
13
  } else {
14
- $class = str_replace( 'P2P_List', 'P2P_Item', get_class( $this ) );
15
- $this->items = _p2p_wrap( $items, $class );
16
  }
17
  }
18
 
@@ -65,37 +64,3 @@ abstract class P2P_List {
65
  }
66
  }
67
 
68
-
69
- class P2P_List_Post extends P2P_List {
70
-
71
- function __construct( $wp_query ) {
72
- if ( is_array( $wp_query ) ) {
73
- $items = $wp_query;
74
- } else {
75
- $items = $wp_query->posts;
76
- $this->current_page = max( 1, $wp_query->get('paged') );
77
- $this->total_pages = $wp_query->max_num_pages;
78
- }
79
-
80
- parent::__construct( $items );
81
- }
82
- }
83
-
84
-
85
- class P2P_List_Attachment extends P2P_List_Post {}
86
-
87
-
88
- class P2P_List_User extends P2P_List {
89
-
90
- function __construct( $query ) {
91
- $qv = $query->query_vars;
92
-
93
- if ( isset( $qv['p2p:page'] ) ) {
94
- $this->current_page = $qv['p2p:page'];
95
- $this->total_pages = ceil( $query->get_total() / $qv['p2p:per_page'] );
96
- }
97
-
98
- parent::__construct( $query->get_results() );
99
- }
100
- }
101
-
1
  <?php
2
 
3
+ class P2P_List {
4
 
5
  public $items;
6
  public $current_page = 1;
7
  public $total_pages = 0;
8
 
9
+ function __construct( $items, $item_type ) {
10
  if ( is_numeric( reset( $items ) ) ) {
11
  // Don't wrap when we just have a list of ids
12
  $this->items = $items;
13
  } else {
14
+ $this->items = _p2p_wrap( $items, $item_type );
 
15
  }
16
  }
17
 
64
  }
65
  }
66
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
core/query.php CHANGED
@@ -83,7 +83,7 @@ class P2P_Query {
83
  'connected_meta' => $directed->data
84
  ) );
85
 
86
- $q = $directed->get_opposite( 'side' )->get_base_qv( $q );
87
 
88
  $q = apply_filters( 'p2p_connected_args', $q, $directed, $item );
89
  }
@@ -108,7 +108,9 @@ class P2P_Query {
108
  return $this->$key;
109
  }
110
 
111
- private function do_other_query( $side ) {
 
 
112
  $qv = array_merge( $this->query, array(
113
  'fields' => 'ids',
114
  'p2p:per_page' => -1
@@ -117,7 +119,9 @@ class P2P_Query {
117
  if ( 'any' != $this->items )
118
  $qv['p2p:include'] = _p2p_normalize( $this->items );
119
 
120
- return $side->capture_query( $side->get_base_qv( $side->translate_qv( $qv ) ) );
 
 
121
  }
122
 
123
  /**
@@ -148,7 +152,7 @@ class P2P_Query {
148
  case 'to':
149
  list( $from, $to ) = $fields;
150
 
151
- $search = $this->do_other_query( $directed->get_current( 'side' ) );
152
 
153
  $part .= " AND $main_id_column = $wpdb->p2p.$from";
154
  $part .= " AND $wpdb->p2p.$to IN ($search)";
@@ -159,8 +163,8 @@ class P2P_Query {
159
  ($main_id_column = $wpdb->p2p.p2p_to AND $wpdb->p2p.p2p_from IN (%s)) OR
160
  ($main_id_column = $wpdb->p2p.p2p_from AND $wpdb->p2p.p2p_to IN (%s))
161
  )",
162
- $this->do_other_query( $directed->get_current( 'side' ) ),
163
- $this->do_other_query( $directed->get_opposite( 'side' ) )
164
  );
165
  }
166
 
83
  'connected_meta' => $directed->data
84
  ) );
85
 
86
+ $q = $directed->get_final_qv( $q, 'opposite' );
87
 
88
  $q = apply_filters( 'p2p_connected_args', $q, $directed, $item );
89
  }
108
  return $this->$key;
109
  }
110
 
111
+ private function do_other_query( $directed, $which ) {
112
+ $side = $directed->get( $which, 'side' );
113
+
114
  $qv = array_merge( $this->query, array(
115
  'fields' => 'ids',
116
  'p2p:per_page' => -1
119
  if ( 'any' != $this->items )
120
  $qv['p2p:include'] = _p2p_normalize( $this->items );
121
 
122
+ $qv = $directed->get_final_qv( $qv, $which );
123
+
124
+ return $side->capture_query( $qv );
125
  }
126
 
127
  /**
152
  case 'to':
153
  list( $from, $to ) = $fields;
154
 
155
+ $search = $this->do_other_query( $directed, 'current' );
156
 
157
  $part .= " AND $main_id_column = $wpdb->p2p.$from";
158
  $part .= " AND $wpdb->p2p.$to IN ($search)";
163
  ($main_id_column = $wpdb->p2p.p2p_to AND $wpdb->p2p.p2p_from IN (%s)) OR
164
  ($main_id_column = $wpdb->p2p.p2p_from AND $wpdb->p2p.p2p_to IN (%s))
165
  )",
166
+ $this->do_other_query( $directed, 'current' ),
167
+ $this->do_other_query( $directed, 'opposite' )
168
  );
169
  }
170
 
core/side.php CHANGED
@@ -12,6 +12,7 @@ abstract class P2P_Side {
12
  abstract function get_base_qv( $q );
13
  abstract function translate_qv( $qv );
14
  abstract function do_query( $args );
 
15
  abstract function capture_query( $args );
16
 
17
  abstract function is_indeterminate( $side );
@@ -101,6 +102,15 @@ class P2P_Side_Post extends P2P_Side {
101
  return new WP_Query( $args );
102
  }
103
 
 
 
 
 
 
 
 
 
 
104
  function capture_query( $args ) {
105
  $q = new WP_Query;
106
  $q->_p2p_capture = true;
@@ -234,6 +244,18 @@ class P2P_Side_User extends P2P_Side {
234
  return new WP_User_Query( $args );
235
  }
236
 
 
 
 
 
 
 
 
 
 
 
 
 
237
  function capture_query( $args ) {
238
  $args['count_total'] = false;
239
 
12
  abstract function get_base_qv( $q );
13
  abstract function translate_qv( $qv );
14
  abstract function do_query( $args );
15
+ abstract function get_list( $query );
16
  abstract function capture_query( $args );
17
 
18
  abstract function is_indeterminate( $side );
102
  return new WP_Query( $args );
103
  }
104
 
105
+ function get_list( $wp_query ) {
106
+ $list = new P2P_List( $wp_query->posts, $this->item_type );
107
+
108
+ $list->current_page = max( 1, $wp_query->get('paged') );
109
+ $list->total_pages = $wp_query->max_num_pages;
110
+
111
+ return $list;
112
+ }
113
+
114
  function capture_query( $args ) {
115
  $q = new WP_Query;
116
  $q->_p2p_capture = true;
244
  return new WP_User_Query( $args );
245
  }
246
 
247
+ function get_list( $query ) {
248
+ $list = new P2P_List( $query->get_results(), $this->item_type );
249
+
250
+ $qv = $query->query_vars;
251
+
252
+ if ( isset( $qv['p2p:page'] ) ) {
253
+ $list->current_page = $qv['p2p:page'];
254
+ $list->total_pages = ceil( $query->get_total() / $qv['p2p:per_page'] );
255
+ }
256
+
257
+ return $list;
258
+ }
259
  function capture_query( $args ) {
260
  $args['count_total'] = false;
261
 
core/type.php CHANGED
@@ -134,8 +134,11 @@ class P2P_Connection_Type {
134
  if ( !in_array( $direction, array( 'from', 'to', 'any' ) ) )
135
  return false;
136
 
137
- if ( $instantiate )
138
- return new P2P_Directed_Connection_Type( $this, $direction );
 
 
 
139
 
140
  return $direction;
141
  }
@@ -353,7 +356,11 @@ class P2P_Connection_Type {
353
 
354
  $q = $directed->get_connected( $items, $extra_qv, 'abstract' );
355
 
356
- p2p_distribute_connected( $items, $q->items, $prop_name );
 
 
 
 
357
  }
358
 
359
  public function get_desc() {
134
  if ( !in_array( $direction, array( 'from', 'to', 'any' ) ) )
135
  return false;
136
 
137
+ if ( $instantiate ) {
138
+ $class = $this->indeterminate ? 'P2P_Indeterminate_Connection_Type' : 'P2P_Directed_Connection_Type';
139
+
140
+ return new $class( $this, $direction );
141
+ }
142
 
143
  return $direction;
144
  }
356
 
357
  $q = $directed->get_connected( $items, $extra_qv, 'abstract' );
358
 
359
+ $raw_connected = array();
360
+ foreach ( $q->items as $item )
361
+ $raw_connected[] = $item->get_object();
362
+
363
+ p2p_distribute_connected( $items, $raw_connected, $prop_name );
364
  }
365
 
366
  public function get_desc() {
core/url-query.php CHANGED
@@ -20,14 +20,14 @@ class P2P_URL_Query {
20
 
21
  // Add the query vars to the global user query (on the user admin screen)
22
  static function user_query( $query ) {
23
- if ( defined( 'DOING_AJAX' ) )
24
  return;
25
 
26
- // Restrict to users screen
27
- if ( 'users' != get_current_screen()->id )
 
28
  return;
29
 
30
- // Don't overwrite capturing query
31
  if ( isset( $query->_p2p_capture ) )
32
  return;
33
 
20
 
21
  // Add the query vars to the global user query (on the user admin screen)
22
  static function user_query( $query ) {
23
+ if ( !function_exists( 'get_current_screen' ) )
24
  return;
25
 
26
+ $current_screen = get_current_screen();
27
+
28
+ if ( $current_screen && 'users' != $current_screen->id )
29
  return;
30
 
 
31
  if ( isset( $query->_p2p_capture ) )
32
  return;
33
 
lang/posts-to-posts-nl_NL.mo ADDED
Binary file
lang/posts-to-posts-nl_NL.po ADDED
@@ -0,0 +1,159 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Translation of 1.4.1 in Dutch
2
+ # This file is distributed under the same license as the 1.4.1 package.
3
+ msgid ""
4
+ msgstr ""
5
+ "PO-Revision-Date: 2012-09-07 15:36+0100\n"
6
+ "MIME-Version: 1.0\n"
7
+ "Content-Type: text/plain; charset=UTF-8\n"
8
+ "Content-Transfer-Encoding: 8bit\n"
9
+ "Plural-Forms: nplurals=2; plural=n != 1;\n"
10
+ "X-Generator: GlotPress/0.1\n"
11
+ "Project-Id-Version: 1.4.1\n"
12
+ "POT-Creation-Date: \n"
13
+ "Last-Translator: Remco Tolsma <remco@pronamic.nl>\n"
14
+ "Language-Team: \n"
15
+
16
+ #: admin/box.php:38
17
+ msgid "Are you sure you want to delete all connections?"
18
+ msgstr "Weet je zeker dat je alle verbindingen wilt verwijderen?"
19
+
20
+ #: admin/box.php:114
21
+ msgid "Search"
22
+ msgstr "Zoeken"
23
+
24
+ #: admin/box.php:191
25
+ msgid "previous"
26
+ msgstr "vorige"
27
+
28
+ #: admin/box.php:192
29
+ msgid "next"
30
+ msgstr "volgende"
31
+
32
+ #: admin/box.php:193
33
+ msgid "of"
34
+ msgstr "of"
35
+
36
+ #: admin/box.php:236
37
+ msgid "Can't create connection: %s"
38
+ msgstr "Kan verbinding niet maken: %s"
39
+
40
+ #: admin/factory.php:30
41
+ msgid " (from)"
42
+ msgstr "(van)"
43
+
44
+ #: admin/factory.php:31
45
+ msgid " (to)"
46
+ msgstr "(naar)"
47
+
48
+ #: admin/fields.php:7
49
+ msgid "Delete all connections"
50
+ msgstr "Verwijder alle verbindingen"
51
+
52
+ #: admin/fields.php:16
53
+ msgid "Delete connection"
54
+ msgstr "Verwijder verbinding"
55
+
56
+ #: admin/tools.php:7
57
+ msgid "Connection Types"
58
+ msgstr "Verbindingstypen"
59
+
60
+ #: admin/tools.php:41
61
+ msgid "<em>%s</em> is not a registered connection type."
62
+ msgstr "<em>%s</em> is niet een geregistreerde verbindingstype."
63
+
64
+ #: admin/tools.php:50
65
+ msgid "Converted %1$s connections from <em>%2$s</em> to <em>%3$s</em>."
66
+ msgstr "%1$s verbindingen omgezet van <em>%2$s</em> naar <em>%3$s</em>."
67
+
68
+ #: admin/tools.php:64
69
+ msgid "Name"
70
+ msgstr "Naam"
71
+
72
+ #: admin/tools.php:65
73
+ msgid "Information"
74
+ msgstr "Informatie"
75
+
76
+ #: admin/tools.php:66
77
+ msgid "Connections"
78
+ msgstr "Verbindingen"
79
+
80
+ #: admin/tools.php:74
81
+ msgid "No connection types registered."
82
+ msgstr "Geen verbindingstypen geregistreerd."
83
+
84
+ #: admin/tools.php:76
85
+ msgid "To register a connection type, see <a href=\"%s\">the wiki</a>."
86
+ msgstr ""
87
+ "Bekijk <a href=\"%s\">de wiki</a> om een verbindingstype te registeren."
88
+
89
+ #: admin/tools.php:93
90
+ msgid "Convert to registered connection type:"
91
+ msgstr "Omzetten naar geregistreerde verbindingstype:"
92
+
93
+ #: admin/tools.php:129
94
+ msgid "Go"
95
+ msgstr "Go"
96
+
97
+ #: core/extra.php:16
98
+ msgid "Posts 2 Posts"
99
+ msgstr "Posts 2 Posts"
100
+
101
+ #: core/extra.php:17
102
+ msgid "A list of posts connected to the current post"
103
+ msgstr "Een lijst van berichten verbonden aan het huidige bericht."
104
+
105
+ #: core/extra.php:34
106
+ msgid "Title:"
107
+ msgstr "Titel:"
108
+
109
+ #: core/extra.php:41
110
+ msgid "Connection type:"
111
+ msgstr "Verbindingstype:"
112
+
113
+ #: core/extra.php:46
114
+ msgid "Connection listing:"
115
+ msgstr "Verbinding lijst:"
116
+
117
+ #: core/extra.php:52
118
+ msgid "connected"
119
+ msgstr "verbonden"
120
+
121
+ #: core/extra.php:53
122
+ msgid "related"
123
+ msgstr "gerelateerd"
124
+
125
+ #: core/side.php:220
126
+ msgid "Users"
127
+ msgstr "Gebruikers"
128
+
129
+ #: core/side.php:229
130
+ msgid "User"
131
+ msgstr "Gebruiker"
132
+
133
+ #: core/side.php:230
134
+ msgid "Search Users"
135
+ msgstr "Gebruikers zoeken"
136
+
137
+ #: core/side.php:231
138
+ msgid "No users found."
139
+ msgstr "Geen gebruikers gevonden."
140
+
141
+ #: core/type.php:79
142
+ msgid "Create connections"
143
+ msgstr "Verbindingen maken"
144
+
145
+ #: core/type.php:102
146
+ msgid "Connected %s"
147
+ msgstr "Verbonden %s"
148
+
149
+ #: scb/AdminPage.php:172
150
+ msgid "Settings <strong>saved</strong>."
151
+ msgstr "Instellingen <strong>opgeslagen</strong>."
152
+
153
+ #: scb/AdminPage.php:185 scb/AdminPage.php:196
154
+ msgid "Save Changes"
155
+ msgstr "Wijzigingen opslaan"
156
+
157
+ #: scb/AdminPage.php:346
158
+ msgid "Settings"
159
+ msgstr "Instellingen"
posts-to-posts.php CHANGED
@@ -2,7 +2,7 @@
2
  /*
3
  Plugin Name: Posts 2 Posts
4
  Description: Create many-to-many relationships between all types of posts.
5
- Version: 1.4.1
6
  Author: scribu
7
  Author URI: http://scribu.net/
8
  Plugin URI: http://scribu.net/wordpress/posts-to-posts
@@ -23,7 +23,8 @@ function _p2p_load() {
23
 
24
  _p2p_load_files( "$base/core", array(
25
  'storage', 'query', 'query-post', 'query-user', 'url-query',
26
- 'util', 'item', 'list', 'side', 'type-factory', 'type', 'directed-type',
 
27
  'api', 'extra'
28
  ) );
29
 
2
  /*
3
  Plugin Name: Posts 2 Posts
4
  Description: Create many-to-many relationships between all types of posts.
5
+ Version: 1.4.2
6
  Author: scribu
7
  Author URI: http://scribu.net/
8
  Plugin URI: http://scribu.net/wordpress/posts-to-posts
23
 
24
  _p2p_load_files( "$base/core", array(
25
  'storage', 'query', 'query-post', 'query-user', 'url-query',
26
+ 'util', 'item', 'list', 'side',
27
+ 'type-factory', 'type', 'directed-type', 'indeterminate-type',
28
  'api', 'extra'
29
  ) );
30
 
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: scribu, ciobi
3
  Tags: connections, custom post types, relationships, many-to-many, users
4
  Requires at least: 3.4
5
  Tested up to: 3.4
6
- Stable tag: 1.4.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -53,6 +53,13 @@ Make sure your host is running PHP 5. The only foolproof way to do this is to ad
53
 
54
  == Changelog ==
55
 
 
 
 
 
 
 
 
56
  = 1.4.1 =
57
  * fixed errors in admin box
58
  * fixed each_connected()
@@ -63,6 +70,7 @@ Make sure your host is running PHP 5. The only foolproof way to do this is to ad
63
  * improved usability of connection candidate UI
64
  * fixed issues related to auto-drafts
65
  * show columns on the admin user list screen
 
66
 
67
  = 1.3.1 =
68
  * sanitize connection fields values on save, preventing security exploits
3
  Tags: connections, custom post types, relationships, many-to-many, users
4
  Requires at least: 3.4
5
  Tested up to: 3.4
6
+ Stable tag: 1.4.2
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
53
 
54
  == Changelog ==
55
 
56
+ = 1.4.2 =
57
+ * fixed each_connected() returning wrapped objects
58
+ * fixed issue with user queries and get_current_screen()
59
+ * fixed "Delete all connections" button
60
+ * fixed bugs with reciprocal and non-reciprocal indeterminate connection types
61
+ * added Dutch translation
62
+
63
  = 1.4.1 =
64
  * fixed errors in admin box
65
  * fixed each_connected()
70
  * improved usability of connection candidate UI
71
  * fixed issues related to auto-drafts
72
  * show columns on the admin user list screen
73
+ * [more info](http://scribu.net/wordpress/posts-to-posts/p2p-1-4.html)
74
 
75
  = 1.3.1 =
76
  * sanitize connection fields values on save, preventing security exploits
scb/Util.php CHANGED
@@ -187,6 +187,18 @@ function html_link( $url, $title = '' ) {
187
  }
188
  endif;
189
 
 
 
 
 
 
 
 
 
 
 
 
 
190
 
191
  //_____Compatibility layer_____
192
 
187
  }
188
  endif;
189
 
190
+ function scb_get_query_flags( $wp_query = null ) {
191
+ if ( !$wp_query )
192
+ $wp_query = $GLOBALS['wp_query'];
193
+
194
+ $flags = array();
195
+ foreach ( get_object_vars( $wp_query ) as $key => $val ) {
196
+ if ( 'is_' == substr( $key, 0, 3 ) && $val )
197
+ $flags[] = substr( $key, 3 );
198
+ }
199
+
200
+ return $flags;
201
+ }
202
 
203
  //_____Compatibility layer_____
204
 
scb/load.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
 
3
- $GLOBALS['_scb_data'] = array( 56, __FILE__, array(
4
  'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
5
  'scbWidget', 'scbAdminPage', 'scbBoxesPage',
6
  'scbCron', 'scbHooks',
1
  <?php
2
 
3
+ $GLOBALS['_scb_data'] = array( 57, __FILE__, array(
4
  'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
5
  'scbWidget', 'scbAdminPage', 'scbBoxesPage',
6
  'scbCron', 'scbHooks',