Version Description
- added 'p2p_init' hook
- replaced 'View All' button with '+ Create connections' toggle
- improved usability of connection candidate UI
- fixed issues related to auto-drafts
- show columns on the admin user list screen
Download this release
Release Info
Developer | scribu |
Plugin | Posts 2 Posts |
Version | 1.4 |
Comparing to | |
See all releases |
Code changes from version 1.3.1 to 1.4
- admin/box-factory.php +64 -72
- admin/box.css +29 -34
- admin/box.js +47 -47
- admin/box.php +47 -93
- admin/column-factory.php +28 -40
- admin/column.php +85 -26
- admin/factory.php +69 -0
- admin/fields.php +56 -57
- admin/templates/box.html +14 -11
- admin/templates/column-create.html +4 -1
- admin/templates/column-delete-all.html +1 -1
- admin/templates/column-delete.html +1 -1
- admin/templates/connection-types.html +6 -0
- admin/templates/tab-search.html +2 -2
- admin/tools.php +26 -26
- core/api.php +20 -4
- core/directed-type.php +42 -55
- core/extra.php +2 -4
- core/item.php +90 -0
- core/list.php +23 -18
- core/query-post.php +28 -29
- core/query-user.php +6 -18
- core/query.php +99 -99
- core/side.php +155 -46
- core/storage.php +0 -30
- core/type.php +93 -35
- core/url-query.php +32 -7
- core/util.php +37 -2
- lang/posts-to-posts-it_IT.mo +0 -0
- lang/posts-to-posts-it_IT.po +133 -0
- lang/posts-to-posts-ro_RO.mo +0 -0
- lang/posts-to-posts-ro_RO.po +62 -54
- lang/posts-to-posts.pot +44 -54
- posts-to-posts.php +11 -6
- readme.txt +9 -2
- scb/AdminPage.php +3 -17
- scb/Forms.php +90 -56
- scb/Options.php +10 -24
- scb/Util.php +4 -2
- scb/load.php +5 -3
- screenshot-1.png +0 -0
- screenshot-2.png +0 -0
- screenshot-4.png +0 -0
admin/box-factory.php
CHANGED
@@ -2,19 +2,17 @@
|
|
2 |
|
3 |
define( 'P2P_BOX_NONCE', 'p2p-box' );
|
4 |
|
5 |
-
class P2P_Box_Factory {
|
6 |
|
7 |
-
|
|
|
8 |
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_boxes' ) );
|
13 |
-
add_action( 'save_post', array( __CLASS__, 'save_post' ), 10, 2 );
|
14 |
-
add_action( 'wp_ajax_p2p_box', array( __CLASS__, 'wp_ajax_p2p_box' ) );
|
15 |
}
|
16 |
|
17 |
-
|
18 |
if ( isset( $args['admin_box'] ) ) {
|
19 |
$box_args = _p2p_pluck( $args, 'admin_box' );
|
20 |
if ( !is_array( $box_args ) )
|
@@ -29,92 +27,79 @@ class P2P_Box_Factory {
|
|
29 |
}
|
30 |
}
|
31 |
|
32 |
-
|
33 |
-
|
34 |
-
return $args;
|
35 |
-
}
|
36 |
-
|
37 |
-
static function register( $p2p_type, $box_args ) {
|
38 |
-
if ( isset( self::$box_args[$p2p_type] ) )
|
39 |
-
return false;
|
40 |
-
|
41 |
-
$box_args = (object) wp_parse_args( $box_args, array(
|
42 |
'show' => 'any',
|
43 |
'context' => 'side',
|
|
|
44 |
'can_create_post' => true
|
45 |
) );
|
46 |
|
47 |
-
|
48 |
-
return false;
|
49 |
|
50 |
-
|
|
|
51 |
|
52 |
-
|
|
|
53 |
}
|
54 |
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
|
59 |
-
|
|
|
60 |
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
|
63 |
-
|
64 |
-
|
65 |
-
$title['to'] .= __( ' (to)', P2P_TEXTDOMAIN );
|
66 |
-
}
|
67 |
|
68 |
-
|
69 |
-
|
70 |
|
71 |
-
|
|
|
72 |
|
73 |
-
|
|
|
74 |
|
75 |
-
|
76 |
-
continue;
|
77 |
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
$post_type,
|
83 |
-
$box_args->context,
|
84 |
-
'default'
|
85 |
-
);
|
86 |
|
87 |
-
|
88 |
-
|
89 |
}
|
90 |
-
}
|
91 |
-
|
92 |
-
private static function get_visible_directions( $post_type, $ctype, $show_ui ) {
|
93 |
-
$direction = $ctype->find_direction( $post_type, false );
|
94 |
-
if ( !$direction )
|
95 |
-
return array();
|
96 |
|
97 |
-
if ( $
|
98 |
-
|
99 |
}
|
100 |
|
101 |
-
|
102 |
-
return array( $direction );
|
103 |
-
|
104 |
-
return array();
|
105 |
}
|
106 |
|
107 |
/**
|
108 |
* Collect metadata from all boxes.
|
109 |
*/
|
110 |
-
|
111 |
if ( 'revision' == $post->post_type || defined( 'DOING_AJAX' ) )
|
112 |
return;
|
113 |
|
114 |
if ( isset( $_POST['p2p_connections'] ) ) {
|
115 |
// Loop through the hidden fields instead of through $_POST['p2p_meta'] because empty checkboxes send no data.
|
116 |
foreach ( $_POST['p2p_connections'] as $p2p_id ) {
|
117 |
-
$data = scbForms::get_value( array( 'p2p_meta', $p2p_id ), $_POST, array() );
|
118 |
|
119 |
$connection = p2p_get_connection( $p2p_id );
|
120 |
|
@@ -126,7 +111,7 @@ class P2P_Box_Factory {
|
|
126 |
|
127 |
$data = scbForms::validate_post_data( $fields, $data );
|
128 |
|
129 |
-
scbForms::update_meta( $fields, $data, $p2p_id, 'p2p' );
|
130 |
}
|
131 |
}
|
132 |
|
@@ -140,34 +125,41 @@ class P2P_Box_Factory {
|
|
140 |
}
|
141 |
}
|
142 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
/**
|
144 |
* Controller for all box ajax requests.
|
145 |
*/
|
146 |
-
|
147 |
check_ajax_referer( P2P_BOX_NONCE, 'nonce' );
|
148 |
|
149 |
$ctype = p2p_type( $_REQUEST['p2p_type'] );
|
150 |
-
if ( !$ctype || !isset(
|
151 |
-
die(0);
|
152 |
-
|
153 |
-
$post_type = get_post_type( $_REQUEST['from'] );
|
154 |
-
if ( !$post_type )
|
155 |
die(0);
|
156 |
|
157 |
$directed = $ctype->set_direction( $_REQUEST['direction'] );
|
158 |
if ( !$directed )
|
159 |
die(0);
|
160 |
|
161 |
-
$
|
|
|
|
|
162 |
|
163 |
-
if (
|
164 |
die(-1);
|
165 |
|
|
|
|
|
166 |
$method = 'ajax_' . $_REQUEST['subaction'];
|
167 |
|
168 |
$box->$method();
|
169 |
}
|
170 |
}
|
171 |
|
172 |
-
P2P_Box_Factory
|
173 |
|
2 |
|
3 |
define( 'P2P_BOX_NONCE', 'p2p-box' );
|
4 |
|
5 |
+
class P2P_Box_Factory extends P2P_Factory {
|
6 |
|
7 |
+
function __construct() {
|
8 |
+
add_filter( 'p2p_connection_type_args', array( $this, 'filter_ctypes' ) );
|
9 |
|
10 |
+
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
|
11 |
+
add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
|
12 |
+
add_action( 'wp_ajax_p2p_box', array( $this, 'wp_ajax_p2p_box' ) );
|
|
|
|
|
|
|
13 |
}
|
14 |
|
15 |
+
function filter_ctypes( $args ) {
|
16 |
if ( isset( $args['admin_box'] ) ) {
|
17 |
$box_args = _p2p_pluck( $args, 'admin_box' );
|
18 |
if ( !is_array( $box_args ) )
|
27 |
}
|
28 |
}
|
29 |
|
30 |
+
$box_args = wp_parse_args( $box_args, array(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
'show' => 'any',
|
32 |
'context' => 'side',
|
33 |
+
'priority' => 'default',
|
34 |
'can_create_post' => true
|
35 |
) );
|
36 |
|
37 |
+
$this->register( $args['name'], $box_args );
|
|
|
38 |
|
39 |
+
return $args;
|
40 |
+
}
|
41 |
|
42 |
+
function add_meta_boxes( $post_type ) {
|
43 |
+
$this->filter( 'post', $post_type );
|
44 |
}
|
45 |
|
46 |
+
function add_item( $directed, $object_type, $post_type, $title ) {
|
47 |
+
if ( !self::show_box( $directed, $GLOBALS['post'] ) )
|
48 |
+
return;
|
49 |
|
50 |
+
$box = $this->create_box( $directed );
|
51 |
+
$box_args = $this->queue[ $directed->name ];
|
52 |
|
53 |
+
add_meta_box(
|
54 |
+
sprintf( 'p2p-%s-%s', $directed->get_direction(), $directed->name ),
|
55 |
+
$title,
|
56 |
+
array( $box, 'render' ),
|
57 |
+
$post_type,
|
58 |
+
$box_args->context,
|
59 |
+
$box_args->priority
|
60 |
+
);
|
61 |
|
62 |
+
$box->init_scripts();
|
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 |
+
}
|
70 |
|
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 ) {
|
82 |
+
$columns[ 'meta-' . $key ] = new P2P_Field_Generic( $key, $data );
|
83 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
+
if ( $orderby_key = $directed->get_orderby_key() ) {
|
86 |
+
$columns['order'] = new P2P_Field_Order( $orderby_key );
|
87 |
}
|
88 |
|
89 |
+
return new P2P_Box( $box_args, $columns, $directed );
|
|
|
|
|
|
|
90 |
}
|
91 |
|
92 |
/**
|
93 |
* Collect metadata from all boxes.
|
94 |
*/
|
95 |
+
function save_post( $post_id, $post ) {
|
96 |
if ( 'revision' == $post->post_type || defined( 'DOING_AJAX' ) )
|
97 |
return;
|
98 |
|
99 |
if ( isset( $_POST['p2p_connections'] ) ) {
|
100 |
// Loop through the hidden fields instead of through $_POST['p2p_meta'] because empty checkboxes send no data.
|
101 |
foreach ( $_POST['p2p_connections'] as $p2p_id ) {
|
102 |
+
$data = stripslashes_deep( scbForms::get_value( array( 'p2p_meta', $p2p_id ), $_POST, array() ) );
|
103 |
|
104 |
$connection = p2p_get_connection( $p2p_id );
|
105 |
|
111 |
|
112 |
$data = scbForms::validate_post_data( $fields, $data );
|
113 |
|
114 |
+
scbForms::update_meta( $fields, self::addslashes_deep( $data ), $p2p_id, 'p2p' );
|
115 |
}
|
116 |
}
|
117 |
|
125 |
}
|
126 |
}
|
127 |
|
128 |
+
private function addslashes_deep( $value ) {
|
129 |
+
if ( is_array( $value ) )
|
130 |
+
return array_map( array( __CLASS__, __METHOD__ ), $value );
|
131 |
+
|
132 |
+
return addslashes( $value );
|
133 |
+
}
|
134 |
+
|
135 |
/**
|
136 |
* Controller for all box ajax requests.
|
137 |
*/
|
138 |
+
function wp_ajax_p2p_box() {
|
139 |
check_ajax_referer( P2P_BOX_NONCE, 'nonce' );
|
140 |
|
141 |
$ctype = p2p_type( $_REQUEST['p2p_type'] );
|
142 |
+
if ( !$ctype || !isset( $this->queue[$ctype->name] ) )
|
|
|
|
|
|
|
|
|
143 |
die(0);
|
144 |
|
145 |
$directed = $ctype->set_direction( $_REQUEST['direction'] );
|
146 |
if ( !$directed )
|
147 |
die(0);
|
148 |
|
149 |
+
$post = get_post( $_REQUEST['from'] );
|
150 |
+
if ( !$post )
|
151 |
+
die(0);
|
152 |
|
153 |
+
if ( !self::show_box( $directed, $post ) )
|
154 |
die(-1);
|
155 |
|
156 |
+
$box = $this->create_box( $directed );
|
157 |
+
|
158 |
$method = 'ajax_' . $_REQUEST['subaction'];
|
159 |
|
160 |
$box->$method();
|
161 |
}
|
162 |
}
|
163 |
|
164 |
+
new P2P_Box_Factory;
|
165 |
|
admin/box.css
CHANGED
@@ -2,12 +2,12 @@
|
|
2 |
color: #AAA;
|
3 |
}
|
4 |
|
5 |
-
.p2p-box a {
|
6 |
text-decoration: none;
|
7 |
}
|
8 |
|
9 |
-
.p2p-
|
10 |
-
|
11 |
}
|
12 |
|
13 |
/* Tabs */
|
@@ -47,6 +47,7 @@
|
|
47 |
}
|
48 |
|
49 |
.p2p-search + .p2p-results,
|
|
|
50 |
.p2p-results + .p2p-navigation {
|
51 |
margin-top: 8px;
|
52 |
}
|
@@ -68,14 +69,6 @@ td.p2p-col-create {
|
|
68 |
padding: 0;
|
69 |
}
|
70 |
|
71 |
-
.p2p-col-delete a,
|
72 |
-
.p2p-col-create a,
|
73 |
-
.p2p-col-delete img,
|
74 |
-
.p2p-col-create img {
|
75 |
-
padding: 5px 6px;
|
76 |
-
vertical-align: middle;
|
77 |
-
}
|
78 |
-
|
79 |
.p2p-results tr:first-child td {
|
80 |
border-top: 0;
|
81 |
}
|
@@ -89,52 +82,59 @@ td.p2p-col-create {
|
|
89 |
width: 100%;
|
90 |
}
|
91 |
|
92 |
-
.p2p-col-create,
|
93 |
.p2p-col-delete {
|
94 |
width: 16px;
|
|
|
95 |
}
|
96 |
|
97 |
-
.p2p-
|
98 |
-
.p2p-col-delete a {
|
99 |
display: block;
|
100 |
height: 16px;
|
101 |
width: 16px;
|
|
|
102 |
}
|
103 |
|
104 |
-
.p2p-col-create,
|
105 |
-
.p2p-
|
106 |
-
|
|
|
|
|
|
|
|
|
|
|
107 |
}
|
108 |
|
109 |
.p2p-col-create:hover,
|
110 |
.p2p-col-delete:hover {
|
111 |
background-color: #f5f5f5;
|
112 |
border-right-color: #ddd;
|
|
|
113 |
}
|
114 |
|
115 |
-
.p2p-col-create
|
116 |
-
.p2p-col-delete
|
117 |
-
opacity:
|
118 |
}
|
119 |
|
120 |
-
.p2p-col-
|
121 |
-
.
|
122 |
-
opacity: 1;
|
123 |
}
|
124 |
|
125 |
-
.p2p-col-create
|
126 |
background: url("images/add.png") no-repeat scroll 50% 50% transparent;
|
|
|
|
|
127 |
}
|
128 |
|
129 |
-
.p2p-
|
130 |
-
|
131 |
}
|
132 |
|
133 |
-
.p2p-
|
134 |
display: block;
|
135 |
margin: 2px 0;
|
136 |
-
max-height:
|
137 |
-
max-width:
|
138 |
}
|
139 |
|
140 |
td.p2p-col-order {
|
@@ -163,11 +163,6 @@ tr:hover td.p2p-col-order {
|
|
163 |
display: block;
|
164 |
}
|
165 |
|
166 |
-
#side-sortables .p2p-notice {
|
167 |
-
display: block;
|
168 |
-
margin-top: 8px;
|
169 |
-
}
|
170 |
-
|
171 |
/* Pagination */
|
172 |
|
173 |
.p2p-navigation {
|
2 |
color: #AAA;
|
3 |
}
|
4 |
|
5 |
+
.p2p-box td a {
|
6 |
text-decoration: none;
|
7 |
}
|
8 |
|
9 |
+
.p2p-toggle-tabs {
|
10 |
+
font-weight: bold;
|
11 |
}
|
12 |
|
13 |
/* Tabs */
|
47 |
}
|
48 |
|
49 |
.p2p-search + .p2p-results,
|
50 |
+
.p2p-search + .p2p-notice,
|
51 |
.p2p-results + .p2p-navigation {
|
52 |
margin-top: 8px;
|
53 |
}
|
69 |
padding: 0;
|
70 |
}
|
71 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
72 |
.p2p-results tr:first-child td {
|
73 |
border-top: 0;
|
74 |
}
|
82 |
width: 100%;
|
83 |
}
|
84 |
|
|
|
85 |
.p2p-col-delete {
|
86 |
width: 16px;
|
87 |
+
border-right: 1px solid transparent;
|
88 |
}
|
89 |
|
90 |
+
.p2p-icon {
|
|
|
91 |
display: block;
|
92 |
height: 16px;
|
93 |
width: 16px;
|
94 |
+
opacity: 0.5;
|
95 |
}
|
96 |
|
97 |
+
.p2p-col-create div,
|
98 |
+
.p2p-icon {
|
99 |
+
padding: 5px 6px;
|
100 |
+
vertical-align: middle;
|
101 |
+
}
|
102 |
+
|
103 |
+
td.p2p-col-create .p2p-icon {
|
104 |
+
padding: 0;
|
105 |
}
|
106 |
|
107 |
.p2p-col-create:hover,
|
108 |
.p2p-col-delete:hover {
|
109 |
background-color: #f5f5f5;
|
110 |
border-right-color: #ddd;
|
111 |
+
cursor: pointer;
|
112 |
}
|
113 |
|
114 |
+
.p2p-col-create:hover .p2p-icon,
|
115 |
+
.p2p-col-delete:hover .p2p-icon {
|
116 |
+
opacity: 1;
|
117 |
}
|
118 |
|
119 |
+
.p2p-col-delete .p2p-icon {
|
120 |
+
background: url("images/delete.png") no-repeat scroll 50% 50% transparent;
|
|
|
121 |
}
|
122 |
|
123 |
+
.p2p-col-create .p2p-icon {
|
124 |
background: url("images/add.png") no-repeat scroll 50% 50% transparent;
|
125 |
+
float: left;
|
126 |
+
margin-right: 6px;
|
127 |
}
|
128 |
|
129 |
+
.p2p-box .post-state {
|
130 |
+
font-style: italic;
|
131 |
}
|
132 |
|
133 |
+
.p2p-box td img {
|
134 |
display: block;
|
135 |
margin: 2px 0;
|
136 |
+
max-height: 60px;
|
137 |
+
max-width: 80px;
|
138 |
}
|
139 |
|
140 |
td.p2p-col-order {
|
163 |
display: block;
|
164 |
}
|
165 |
|
|
|
|
|
|
|
|
|
|
|
166 |
/* Pagination */
|
167 |
|
168 |
.p2p-navigation {
|
admin/box.js
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
// Generated by CoffeeScript 1.3.1
|
2 |
(function() {
|
3 |
|
4 |
jQuery(function() {
|
@@ -11,7 +10,7 @@
|
|
11 |
$this.val($this.attr('placeholder'));
|
12 |
$this.addClass('p2p-placeholder');
|
13 |
}
|
14 |
-
return;
|
15 |
};
|
16 |
clearVal = function() {
|
17 |
var $this;
|
@@ -20,12 +19,12 @@
|
|
20 |
$this.val('');
|
21 |
$this.removeClass('p2p-placeholder');
|
22 |
}
|
23 |
-
return;
|
24 |
};
|
25 |
jQuery('.p2p-search input[placeholder]').each(setVal).focus(clearVal).blur(setVal);
|
26 |
}
|
27 |
return jQuery('.p2p-box').each(function() {
|
28 |
-
var $connections, $createButton, $createInput, $metabox, $searchInput, $spinner,
|
29 |
$metabox = jQuery(this);
|
30 |
$connections = $metabox.find('.p2p-connections');
|
31 |
$spinner = jQuery('<img>', {
|
@@ -49,7 +48,11 @@
|
|
49 |
handler = function(response) {
|
50 |
try {
|
51 |
response = jQuery.parseJSON(response);
|
52 |
-
|
|
|
|
|
|
|
|
|
53 |
} catch (e) {
|
54 |
return typeof console !== "undefined" && console !== null ? console.error('Malformed response', response) : void 0;
|
55 |
}
|
@@ -63,8 +66,6 @@
|
|
63 |
};
|
64 |
PostsTab = (function() {
|
65 |
|
66 |
-
PostsTab.name = 'PostsTab';
|
67 |
-
|
68 |
function PostsTab(selector) {
|
69 |
var _this = this;
|
70 |
this.tab = $metabox.find(selector);
|
@@ -112,12 +113,8 @@
|
|
112 |
PostsTab.prototype.update_rows = function(response) {
|
113 |
$spinner.remove();
|
114 |
this.tab.find('button, .p2p-results, .p2p-navigation, .p2p-notice').remove();
|
115 |
-
|
116 |
-
|
117 |
-
} else {
|
118 |
-
this.tab.append(response.rows);
|
119 |
-
return this.init_pagination_data();
|
120 |
-
}
|
121 |
};
|
122 |
|
123 |
return PostsTab;
|
@@ -125,7 +122,7 @@
|
|
125 |
})();
|
126 |
searchTab = new PostsTab('.p2p-tab-search');
|
127 |
row_ajax_request = function($td, data, callback) {
|
128 |
-
$td.
|
129 |
return ajax_request(data, callback);
|
130 |
};
|
131 |
remove_row = function($td) {
|
@@ -147,66 +144,70 @@
|
|
147 |
return searchTab.update_rows(results);
|
148 |
};
|
149 |
clear_connections = function(ev) {
|
150 |
-
var $
|
151 |
_this = this;
|
|
|
152 |
if (!confirm(P2PAdmin.deleteConfirmMessage)) {
|
153 |
-
return
|
154 |
}
|
155 |
-
$
|
156 |
-
$td = $self.closest('td');
|
157 |
data = {
|
158 |
subaction: 'clear_connections'
|
159 |
};
|
160 |
row_ajax_request($td, data, function(response) {
|
161 |
$connections.hide().find('tbody').html('');
|
162 |
-
$td.html($self);
|
163 |
return refresh_candidates(response);
|
164 |
});
|
165 |
-
return
|
166 |
};
|
167 |
delete_connection = function(ev) {
|
168 |
-
var $
|
169 |
_this = this;
|
170 |
-
|
171 |
-
$td =
|
172 |
data = {
|
173 |
subaction: 'disconnect',
|
174 |
-
p2p_id: $
|
175 |
};
|
176 |
row_ajax_request($td, data, function(response) {
|
177 |
remove_row($td);
|
178 |
return refresh_candidates(response);
|
179 |
});
|
180 |
-
return
|
181 |
};
|
182 |
create_connection = function(ev) {
|
183 |
-
var $
|
184 |
_this = this;
|
185 |
-
|
186 |
-
$td =
|
187 |
data = {
|
188 |
subaction: 'connect',
|
189 |
-
to: $
|
190 |
};
|
191 |
row_ajax_request($td, data, function(response) {
|
192 |
append_connection(response);
|
193 |
if ($metabox.data('duplicate_connections')) {
|
194 |
-
return $td.
|
195 |
} else {
|
196 |
return remove_row($td);
|
197 |
}
|
198 |
});
|
199 |
-
return
|
200 |
};
|
201 |
-
|
|
|
|
|
|
|
|
|
|
|
202 |
var $tab;
|
|
|
203 |
$tab = jQuery(this);
|
204 |
$metabox.find('.wp-tab-bar li').removeClass('wp-tab-active');
|
205 |
$tab.addClass('wp-tab-active');
|
206 |
-
$metabox.find('.tabs-panel').hide().end().find($tab.data('ref')).show().find(':text').focus();
|
207 |
-
return false;
|
208 |
};
|
209 |
-
$metabox.delegate('th.p2p-col-delete
|
210 |
if ($connections.find('th.p2p-col-order').length) {
|
211 |
$connections.find('tbody').sortable({
|
212 |
handle: 'td.p2p-col-order',
|
@@ -220,22 +221,18 @@
|
|
220 |
}
|
221 |
});
|
222 |
}
|
223 |
-
$viewAll = $metabox.find('.p2p-tab-search button');
|
224 |
-
$viewAll.click(function() {
|
225 |
-
searchTab.find_posts(1);
|
226 |
-
return false;
|
227 |
-
});
|
228 |
$searchInput = $metabox.find('.p2p-tab-search :text');
|
229 |
$searchInput.keypress(function(ev) {
|
230 |
if (ev.keyCode === 13) {
|
231 |
-
|
232 |
}
|
|
|
233 |
}).keyup(function(ev) {
|
234 |
var delayed;
|
235 |
if (delayed !== void 0) {
|
236 |
clearTimeout(delayed);
|
237 |
}
|
238 |
-
|
239 |
var searchStr;
|
240 |
searchStr = $searchInput.val();
|
241 |
if (searchStr === searchTab.params.s) {
|
@@ -245,19 +242,21 @@
|
|
245 |
$spinner.insertAfter($searchInput).show();
|
246 |
return searchTab.find_posts(1);
|
247 |
}, 400);
|
|
|
248 |
});
|
249 |
$createButton = $metabox.find('.p2p-tab-create-post button');
|
250 |
$createInput = $metabox.find('.p2p-tab-create-post :text');
|
251 |
-
$createButton.click(function() {
|
252 |
var $button, data, title;
|
|
|
253 |
$button = jQuery(this);
|
254 |
if ($button.hasClass('inactive')) {
|
255 |
-
return
|
256 |
}
|
257 |
title = $createInput.val();
|
258 |
if (title === '') {
|
259 |
$createInput.focus();
|
260 |
-
return
|
261 |
}
|
262 |
$button.addClass('inactive');
|
263 |
data = {
|
@@ -269,13 +268,14 @@
|
|
269 |
$createInput.val('');
|
270 |
return $button.removeClass('inactive');
|
271 |
});
|
272 |
-
return
|
273 |
});
|
274 |
return $createInput.keypress(function(ev) {
|
275 |
if (13 === ev.keyCode) {
|
276 |
$createButton.click();
|
277 |
-
|
278 |
}
|
|
|
279 |
});
|
280 |
});
|
281 |
});
|
|
|
1 |
(function() {
|
2 |
|
3 |
jQuery(function() {
|
10 |
$this.val($this.attr('placeholder'));
|
11 |
$this.addClass('p2p-placeholder');
|
12 |
}
|
13 |
+
return void 0;
|
14 |
};
|
15 |
clearVal = function() {
|
16 |
var $this;
|
19 |
$this.val('');
|
20 |
$this.removeClass('p2p-placeholder');
|
21 |
}
|
22 |
+
return void 0;
|
23 |
};
|
24 |
jQuery('.p2p-search input[placeholder]').each(setVal).focus(clearVal).blur(setVal);
|
25 |
}
|
26 |
return jQuery('.p2p-box').each(function() {
|
27 |
+
var $connections, $createButton, $createInput, $metabox, $searchInput, $spinner, PostsTab, ajax_request, append_connection, clear_connections, create_connection, delete_connection, refresh_candidates, remove_row, row_ajax_request, searchTab, switch_to_tab, toggle_tabs;
|
28 |
$metabox = jQuery(this);
|
29 |
$connections = $metabox.find('.p2p-connections');
|
30 |
$spinner = jQuery('<img>', {
|
48 |
handler = function(response) {
|
49 |
try {
|
50 |
response = jQuery.parseJSON(response);
|
51 |
+
if (response.error) {
|
52 |
+
return alert(response.error);
|
53 |
+
} else {
|
54 |
+
return callback(response);
|
55 |
+
}
|
56 |
} catch (e) {
|
57 |
return typeof console !== "undefined" && console !== null ? console.error('Malformed response', response) : void 0;
|
58 |
}
|
66 |
};
|
67 |
PostsTab = (function() {
|
68 |
|
|
|
|
|
69 |
function PostsTab(selector) {
|
70 |
var _this = this;
|
71 |
this.tab = $metabox.find(selector);
|
113 |
PostsTab.prototype.update_rows = function(response) {
|
114 |
$spinner.remove();
|
115 |
this.tab.find('button, .p2p-results, .p2p-navigation, .p2p-notice').remove();
|
116 |
+
this.tab.append(response.rows);
|
117 |
+
return this.init_pagination_data();
|
|
|
|
|
|
|
|
|
118 |
};
|
119 |
|
120 |
return PostsTab;
|
122 |
})();
|
123 |
searchTab = new PostsTab('.p2p-tab-search');
|
124 |
row_ajax_request = function($td, data, callback) {
|
125 |
+
$td.find('.p2p-icon').css('background-image', 'url(' + P2PAdmin.spinner + ')');
|
126 |
return ajax_request(data, callback);
|
127 |
};
|
128 |
remove_row = function($td) {
|
144 |
return searchTab.update_rows(results);
|
145 |
};
|
146 |
clear_connections = function(ev) {
|
147 |
+
var $td, data,
|
148 |
_this = this;
|
149 |
+
ev.preventDefault();
|
150 |
if (!confirm(P2PAdmin.deleteConfirmMessage)) {
|
151 |
+
return;
|
152 |
}
|
153 |
+
$td = jQuery(ev.target).closest('td');
|
|
|
154 |
data = {
|
155 |
subaction: 'clear_connections'
|
156 |
};
|
157 |
row_ajax_request($td, data, function(response) {
|
158 |
$connections.hide().find('tbody').html('');
|
|
|
159 |
return refresh_candidates(response);
|
160 |
});
|
161 |
+
return null;
|
162 |
};
|
163 |
delete_connection = function(ev) {
|
164 |
+
var $td, data,
|
165 |
_this = this;
|
166 |
+
ev.preventDefault();
|
167 |
+
$td = jQuery(ev.target).closest('td');
|
168 |
data = {
|
169 |
subaction: 'disconnect',
|
170 |
+
p2p_id: $td.find('input').val()
|
171 |
};
|
172 |
row_ajax_request($td, data, function(response) {
|
173 |
remove_row($td);
|
174 |
return refresh_candidates(response);
|
175 |
});
|
176 |
+
return null;
|
177 |
};
|
178 |
create_connection = function(ev) {
|
179 |
+
var $td, data,
|
180 |
_this = this;
|
181 |
+
ev.preventDefault();
|
182 |
+
$td = jQuery(ev.target).closest('td');
|
183 |
data = {
|
184 |
subaction: 'connect',
|
185 |
+
to: $td.find('div').data('item-id')
|
186 |
};
|
187 |
row_ajax_request($td, data, function(response) {
|
188 |
append_connection(response);
|
189 |
if ($metabox.data('duplicate_connections')) {
|
190 |
+
return $td.find('.p2p-icon').css('background-image', '');
|
191 |
} else {
|
192 |
return remove_row($td);
|
193 |
}
|
194 |
});
|
195 |
+
return null;
|
196 |
};
|
197 |
+
toggle_tabs = function(ev) {
|
198 |
+
ev.preventDefault();
|
199 |
+
$metabox.find('.p2p-create-connections-tabs').toggle();
|
200 |
+
return null;
|
201 |
+
};
|
202 |
+
switch_to_tab = function(ev) {
|
203 |
var $tab;
|
204 |
+
ev.preventDefault();
|
205 |
$tab = jQuery(this);
|
206 |
$metabox.find('.wp-tab-bar li').removeClass('wp-tab-active');
|
207 |
$tab.addClass('wp-tab-active');
|
208 |
+
return $metabox.find('.tabs-panel').hide().end().find($tab.data('ref')).show().find(':text').focus();
|
|
|
209 |
};
|
210 |
+
$metabox.delegate('th.p2p-col-delete .p2p-icon', 'click', clear_connections).delegate('td.p2p-col-delete .p2p-icon', 'click', delete_connection).delegate('td.p2p-col-create div', 'click', create_connection).delegate('.p2p-toggle-tabs', 'click', toggle_tabs).delegate('.wp-tab-bar li', 'click', switch_to_tab);
|
211 |
if ($connections.find('th.p2p-col-order').length) {
|
212 |
$connections.find('tbody').sortable({
|
213 |
handle: 'td.p2p-col-order',
|
221 |
}
|
222 |
});
|
223 |
}
|
|
|
|
|
|
|
|
|
|
|
224 |
$searchInput = $metabox.find('.p2p-tab-search :text');
|
225 |
$searchInput.keypress(function(ev) {
|
226 |
if (ev.keyCode === 13) {
|
227 |
+
ev.preventDefault();
|
228 |
}
|
229 |
+
return null;
|
230 |
}).keyup(function(ev) {
|
231 |
var delayed;
|
232 |
if (delayed !== void 0) {
|
233 |
clearTimeout(delayed);
|
234 |
}
|
235 |
+
delayed = setTimeout(function() {
|
236 |
var searchStr;
|
237 |
searchStr = $searchInput.val();
|
238 |
if (searchStr === searchTab.params.s) {
|
242 |
$spinner.insertAfter($searchInput).show();
|
243 |
return searchTab.find_posts(1);
|
244 |
}, 400);
|
245 |
+
return null;
|
246 |
});
|
247 |
$createButton = $metabox.find('.p2p-tab-create-post button');
|
248 |
$createInput = $metabox.find('.p2p-tab-create-post :text');
|
249 |
+
$createButton.click(function(ev) {
|
250 |
var $button, data, title;
|
251 |
+
ev.preventDefault();
|
252 |
$button = jQuery(this);
|
253 |
if ($button.hasClass('inactive')) {
|
254 |
+
return;
|
255 |
}
|
256 |
title = $createInput.val();
|
257 |
if (title === '') {
|
258 |
$createInput.focus();
|
259 |
+
return;
|
260 |
}
|
261 |
$button.addClass('inactive');
|
262 |
data = {
|
268 |
$createInput.val('');
|
269 |
return $button.removeClass('inactive');
|
270 |
});
|
271 |
+
return null;
|
272 |
});
|
273 |
return $createInput.keypress(function(ev) {
|
274 |
if (13 === ev.keyCode) {
|
275 |
$createButton.click();
|
276 |
+
ev.preventDefault();
|
277 |
}
|
278 |
+
return null;
|
279 |
});
|
280 |
});
|
281 |
});
|
admin/box.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
interface P2P_Field {
|
4 |
function get_title();
|
5 |
-
function render( $p2p_id, $
|
6 |
}
|
7 |
|
8 |
class P2P_Box {
|
@@ -10,8 +10,6 @@ class P2P_Box {
|
|
10 |
|
11 |
private $args;
|
12 |
|
13 |
-
private $ptype;
|
14 |
-
|
15 |
private $columns;
|
16 |
|
17 |
private static $admin_box_qv = array(
|
@@ -20,14 +18,14 @@ class P2P_Box {
|
|
20 |
'post_status' => 'any',
|
21 |
);
|
22 |
|
23 |
-
function __construct( $args, $ctype ) {
|
24 |
$this->args = $args;
|
25 |
|
|
|
|
|
26 |
$this->ctype = $ctype;
|
27 |
|
28 |
$this->labels = $this->ctype->get_opposite( 'labels' );
|
29 |
-
|
30 |
-
$this->init_columns();
|
31 |
}
|
32 |
|
33 |
public function init_scripts() {
|
@@ -41,31 +39,13 @@ class P2P_Box {
|
|
41 |
) );
|
42 |
}
|
43 |
|
44 |
-
protected function init_columns() {
|
45 |
-
$title_class = $this->get_column_title_class();
|
46 |
-
|
47 |
-
$this->columns = array(
|
48 |
-
'delete' => new P2P_Field_Delete,
|
49 |
-
'title' => new $title_class( $this->labels->singular_name ),
|
50 |
-
);
|
51 |
-
|
52 |
-
foreach ( $this->ctype->fields as $key => $data ) {
|
53 |
-
$this->columns[ 'meta-' . $key ] = new P2P_Field_Generic( $key, $data );
|
54 |
-
}
|
55 |
-
|
56 |
-
if ( $orderby_key = $this->ctype->get_orderby_key() ) {
|
57 |
-
$this->columns['order'] = new P2P_Field_Order( $orderby_key );
|
58 |
-
}
|
59 |
-
}
|
60 |
-
|
61 |
-
protected function get_column_title_class() {
|
62 |
-
$object_type = $this->ctype->get_opposite( 'object' );
|
63 |
-
|
64 |
-
return 'P2P_Field_Title_' . ucfirst( $object_type );
|
65 |
-
}
|
66 |
-
|
67 |
function render( $post ) {
|
68 |
-
$
|
|
|
|
|
|
|
|
|
|
|
69 |
|
70 |
$data = array(
|
71 |
'attributes' => $this->render_data_attributes(),
|
@@ -76,17 +56,6 @@ class P2P_Box {
|
|
76 |
echo P2P_Mustache::render( 'box', $data );
|
77 |
}
|
78 |
|
79 |
-
protected function get_folded_connections( $post ) {
|
80 |
-
$extra_qv = array_merge( self::$admin_box_qv, array(
|
81 |
-
'p2p:context' => 'admin_box',
|
82 |
-
'p2p:per_page' => -1
|
83 |
-
) );
|
84 |
-
|
85 |
-
$query = $this->ctype->get_connected( $post, $extra_qv, 'abstract' );
|
86 |
-
|
87 |
-
return scb_list_fold( $query->items, 'p2p_id', 'ID' );
|
88 |
-
}
|
89 |
-
|
90 |
protected function render_data_attributes() {
|
91 |
$data_attr = array(
|
92 |
'p2p_type' => $this->ctype->name,
|
@@ -109,8 +78,8 @@ class P2P_Box {
|
|
109 |
$data['hide'] = 'style="display:none"';
|
110 |
|
111 |
$tbody = array();
|
112 |
-
foreach ( $this->connected_items as $
|
113 |
-
$tbody[] = $this->connection_row( $p2p_id, $
|
114 |
}
|
115 |
$data['tbody'] = $tbody;
|
116 |
|
@@ -126,16 +95,18 @@ class P2P_Box {
|
|
126 |
|
127 |
protected function render_create_connections( $post ) {
|
128 |
$data = array(
|
129 |
-
'label' =>
|
130 |
);
|
131 |
|
132 |
-
if ( 'one' == $this->ctype->get_opposite( 'cardinality' )
|
133 |
-
$
|
|
|
|
|
134 |
|
135 |
// Search tab
|
136 |
$tab_content = P2P_Mustache::render( 'tab-search', array(
|
137 |
'placeholder' => $this->labels->search_items,
|
138 |
-
'
|
139 |
) );
|
140 |
|
141 |
$data['tabs'][] = array(
|
@@ -163,17 +134,17 @@ class P2P_Box {
|
|
163 |
return $data;
|
164 |
}
|
165 |
|
166 |
-
protected function connection_row( $p2p_id, $
|
167 |
-
return $this->table_row( $this->columns, $p2p_id, $
|
168 |
}
|
169 |
|
170 |
-
protected function table_row( $columns, $p2p_id, $
|
171 |
$data = array();
|
172 |
|
173 |
foreach ( $columns as $key => $field ) {
|
174 |
$data['columns'][] = array(
|
175 |
'column' => $key,
|
176 |
-
'content' => $field->render( $p2p_id, $
|
177 |
);
|
178 |
}
|
179 |
|
@@ -192,18 +163,18 @@ class P2P_Box {
|
|
192 |
|
193 |
$candidate = $this->ctype->get_connectable( $current_post_id, $extra_qv );
|
194 |
|
195 |
-
if ( empty( $candidate->items ) )
|
196 |
-
return
|
|
|
197 |
|
198 |
$data = array();
|
199 |
|
200 |
$columns = array(
|
201 |
-
'create' => new P2P_Field_Create,
|
202 |
-
'title' => $this->columns['title']
|
203 |
);
|
204 |
|
205 |
foreach ( $candidate->items as $item ) {
|
206 |
-
$data['rows'][] = $this->table_row( $columns, 0, $item
|
207 |
}
|
208 |
|
209 |
if ( $candidate->total_pages > 1 ) {
|
@@ -236,7 +207,7 @@ class P2P_Box {
|
|
236 |
$args = array(
|
237 |
'post_title' => $_POST['post_title'],
|
238 |
'post_author' => get_current_user_id(),
|
239 |
-
'post_type' => $this->ctype->get_opposite( 'side' )->
|
240 |
);
|
241 |
|
242 |
$from = absint( $_POST['from'] );
|
@@ -259,10 +230,20 @@ class P2P_Box {
|
|
259 |
|
260 |
$p2p_id = $this->ctype->connect( $from, $to );
|
261 |
|
262 |
-
if ( is_wp_error( $p2p_id ) )
|
263 |
-
$r = array(
|
264 |
-
|
265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
266 |
|
267 |
die( json_encode( $r ) );
|
268 |
}
|
@@ -280,51 +261,24 @@ class P2P_Box {
|
|
280 |
}
|
281 |
|
282 |
public function ajax_search() {
|
283 |
-
|
284 |
}
|
285 |
|
286 |
private function refresh_candidates() {
|
287 |
-
$
|
288 |
|
289 |
-
|
290 |
-
}
|
291 |
-
|
292 |
-
private function _ajax_search( $args ) {
|
293 |
-
$rows = $this->post_rows( $args['from'], $args['paged'], $args['s'] );
|
294 |
|
295 |
-
|
296 |
-
$results = compact( 'rows' );
|
297 |
-
} else {
|
298 |
-
$results = array(
|
299 |
-
'msg' => $this->labels->not_found,
|
300 |
-
);
|
301 |
-
}
|
302 |
-
|
303 |
-
return $results;
|
304 |
}
|
305 |
|
306 |
protected function can_create_post() {
|
307 |
if ( !$this->args->can_create_post )
|
308 |
return false;
|
309 |
|
310 |
-
if ( 'post' != $this->ctype->get_opposite( 'object' ) )
|
311 |
-
return false;
|
312 |
-
|
313 |
$side = $this->ctype->get_opposite( 'side' );
|
314 |
|
315 |
-
|
316 |
-
return false;
|
317 |
-
|
318 |
-
if ( count( $side->query_vars ) > 1 )
|
319 |
-
return false;
|
320 |
-
|
321 |
-
return true;
|
322 |
-
}
|
323 |
-
|
324 |
-
public function check_capability() {
|
325 |
-
$show = $this->ctype->get_opposite( 'side' )->check_capability();
|
326 |
-
|
327 |
-
return apply_filters( 'p2p_admin_box_show', $show, $this->ctype, $GLOBALS['post'] );
|
328 |
}
|
329 |
}
|
330 |
|
2 |
|
3 |
interface P2P_Field {
|
4 |
function get_title();
|
5 |
+
function render( $p2p_id, $item );
|
6 |
}
|
7 |
|
8 |
class P2P_Box {
|
10 |
|
11 |
private $args;
|
12 |
|
|
|
|
|
13 |
private $columns;
|
14 |
|
15 |
private static $admin_box_qv = array(
|
18 |
'post_status' => 'any',
|
19 |
);
|
20 |
|
21 |
+
function __construct( $args, $columns, $ctype ) {
|
22 |
$this->args = $args;
|
23 |
|
24 |
+
$this->columns = $columns;
|
25 |
+
|
26 |
$this->ctype = $ctype;
|
27 |
|
28 |
$this->labels = $this->ctype->get_opposite( 'labels' );
|
|
|
|
|
29 |
}
|
30 |
|
31 |
public function init_scripts() {
|
39 |
) );
|
40 |
}
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
function render( $post ) {
|
43 |
+
$extra_qv = array_merge( self::$admin_box_qv, array(
|
44 |
+
'p2p:context' => 'admin_box',
|
45 |
+
'p2p:per_page' => -1
|
46 |
+
) );
|
47 |
+
|
48 |
+
$this->connected_items = $this->ctype->get_connected( $post, $extra_qv, 'abstract' )->items;
|
49 |
|
50 |
$data = array(
|
51 |
'attributes' => $this->render_data_attributes(),
|
56 |
echo P2P_Mustache::render( 'box', $data );
|
57 |
}
|
58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
protected function render_data_attributes() {
|
60 |
$data_attr = array(
|
61 |
'p2p_type' => $this->ctype->name,
|
78 |
$data['hide'] = 'style="display:none"';
|
79 |
|
80 |
$tbody = array();
|
81 |
+
foreach ( $this->connected_items as $item ) {
|
82 |
+
$tbody[] = $this->connection_row( $item->p2p_id, $item );
|
83 |
}
|
84 |
$data['tbody'] = $tbody;
|
85 |
|
95 |
|
96 |
protected function render_create_connections( $post ) {
|
97 |
$data = array(
|
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 |
+
}
|
105 |
|
106 |
// Search tab
|
107 |
$tab_content = P2P_Mustache::render( 'tab-search', array(
|
108 |
'placeholder' => $this->labels->search_items,
|
109 |
+
'candidates' => $this->post_rows( $post->ID )
|
110 |
) );
|
111 |
|
112 |
$data['tabs'][] = array(
|
134 |
return $data;
|
135 |
}
|
136 |
|
137 |
+
protected function connection_row( $p2p_id, $item, $render = false ) {
|
138 |
+
return $this->table_row( $this->columns, $p2p_id, $item, $render );
|
139 |
}
|
140 |
|
141 |
+
protected function table_row( $columns, $p2p_id, $item, $render = false ) {
|
142 |
$data = array();
|
143 |
|
144 |
foreach ( $columns as $key => $field ) {
|
145 |
$data['columns'][] = array(
|
146 |
'column' => $key,
|
147 |
+
'content' => $field->render( $p2p_id, $item )
|
148 |
);
|
149 |
}
|
150 |
|
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 );
|
168 |
+
}
|
169 |
|
170 |
$data = array();
|
171 |
|
172 |
$columns = array(
|
173 |
+
'create' => new P2P_Field_Create( $this->columns['title'] ),
|
|
|
174 |
);
|
175 |
|
176 |
foreach ( $candidate->items as $item ) {
|
177 |
+
$data['rows'][] = $this->table_row( $columns, 0, $item );
|
178 |
}
|
179 |
|
180 |
if ( $candidate->total_pages > 1 ) {
|
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 |
+
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 |
}
|
261 |
}
|
262 |
|
263 |
public function ajax_search() {
|
264 |
+
$this->refresh_candidates();
|
265 |
}
|
266 |
|
267 |
private function refresh_candidates() {
|
268 |
+
$rows = $this->post_rows( $_REQUEST['from'], $_REQUEST['paged'], $_REQUEST['s'] );
|
269 |
|
270 |
+
$results = compact( 'rows' );
|
|
|
|
|
|
|
|
|
271 |
|
272 |
+
die( json_encode( $results ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
273 |
}
|
274 |
|
275 |
protected function can_create_post() {
|
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 |
}
|
283 |
}
|
284 |
|
admin/column-factory.php
CHANGED
@@ -1,66 +1,54 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
class P2P_Column_Factory {
|
4 |
|
5 |
-
|
|
|
6 |
|
7 |
-
|
8 |
-
add_filter( 'p2p_connection_type_args', array( __CLASS__, 'filter_args' ) );
|
9 |
-
|
10 |
-
add_action( 'admin_print_styles', array( __CLASS__, 'add_columns' ) );
|
11 |
}
|
12 |
|
13 |
-
|
14 |
if ( isset( $args['admin_column'] ) ) {
|
15 |
$column_args = _p2p_pluck( $args, 'admin_column' );
|
|
|
|
|
16 |
} else {
|
17 |
-
$column_args =
|
18 |
}
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
}
|
24 |
|
25 |
-
|
26 |
-
if ( isset( self::$column_args[$p2p_type] ) )
|
27 |
-
return false;
|
28 |
|
29 |
-
|
30 |
-
return false;
|
31 |
-
|
32 |
-
self::$column_args[$p2p_type] = $column_args;
|
33 |
-
|
34 |
-
return true;
|
35 |
}
|
36 |
|
37 |
-
|
38 |
$screen = get_current_screen();
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
foreach ( self::$column_args as $p2p_type => $column_args ) {
|
46 |
-
$ctype = p2p_type( $p2p_type );
|
47 |
|
48 |
-
|
49 |
-
|
50 |
-
continue;
|
51 |
|
52 |
-
|
53 |
-
continue;
|
54 |
|
55 |
-
|
|
|
56 |
|
57 |
-
|
|
|
|
|
58 |
|
59 |
-
|
60 |
-
add_action( "manage_{$post_type}_posts_custom_column", array( $column, 'display_column' ), 10, 2 );
|
61 |
-
}
|
62 |
}
|
63 |
}
|
64 |
|
65 |
-
P2P_Column_Factory
|
66 |
|
1 |
<?php
|
2 |
|
3 |
+
class P2P_Column_Factory extends P2P_Factory {
|
4 |
|
5 |
+
function __construct() {
|
6 |
+
add_filter( 'p2p_connection_type_args', array( $this, 'filter_ctypes' ) );
|
7 |
|
8 |
+
add_action( 'admin_print_styles', array( $this, 'add_columns' ) );
|
|
|
|
|
|
|
9 |
}
|
10 |
|
11 |
+
function filter_ctypes( $args ) {
|
12 |
if ( isset( $args['admin_column'] ) ) {
|
13 |
$column_args = _p2p_pluck( $args, 'admin_column' );
|
14 |
+
if ( !is_array( $column_args ) )
|
15 |
+
$column_args = array( 'show' => $column_args );
|
16 |
} else {
|
17 |
+
$column_args = array();
|
18 |
}
|
19 |
|
20 |
+
$column_args = wp_parse_args( $column_args, array(
|
21 |
+
'show' => false,
|
22 |
+
) );
|
|
|
23 |
|
24 |
+
$this->register( $args['name'], $column_args );
|
|
|
|
|
25 |
|
26 |
+
return $args;
|
|
|
|
|
|
|
|
|
|
|
27 |
}
|
28 |
|
29 |
+
function add_columns() {
|
30 |
$screen = get_current_screen();
|
31 |
|
32 |
+
$screen_map = array(
|
33 |
+
'edit' => 'post',
|
34 |
+
'users' => 'user'
|
35 |
+
);
|
|
|
|
|
|
|
36 |
|
37 |
+
if ( !isset( $screen_map[ $screen->base ] ) )
|
38 |
+
return;
|
|
|
39 |
|
40 |
+
$object_type = $screen_map[ $screen->base ];
|
|
|
41 |
|
42 |
+
$this->filter( $object_type, $screen->post_type );
|
43 |
+
}
|
44 |
|
45 |
+
function add_item( $directed, $object_type, $post_type, $title ) {
|
46 |
+
$class = 'P2P_Column_' . ucfirst( $object_type );
|
47 |
+
$column = new $class( $directed );
|
48 |
|
49 |
+
$column->styles();
|
|
|
|
|
50 |
}
|
51 |
}
|
52 |
|
53 |
+
new P2P_Column_Factory;
|
54 |
|
admin/column.php
CHANGED
@@ -1,23 +1,35 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
class P2P_Column {
|
4 |
|
5 |
protected $ctype;
|
6 |
|
7 |
protected $connected = array();
|
8 |
|
9 |
-
function __construct( $directed ) {
|
10 |
$this->ctype = $directed;
|
11 |
|
12 |
-
$extra_qv = array(
|
|
|
|
|
|
|
13 |
|
14 |
-
$this->ctype->
|
15 |
|
16 |
-
$this->connected =
|
|
|
|
|
|
|
|
|
17 |
}
|
18 |
|
19 |
function add_column( $columns ) {
|
20 |
-
$
|
|
|
|
|
|
|
|
|
|
|
21 |
|
22 |
return $columns;
|
23 |
}
|
@@ -33,34 +45,81 @@ class P2P_Column {
|
|
33 |
<?php
|
34 |
}
|
35 |
|
36 |
-
function
|
37 |
-
|
|
|
|
|
|
|
|
|
|
|
38 |
return;
|
39 |
|
40 |
-
$
|
41 |
-
|
42 |
-
|
43 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
);
|
45 |
|
46 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
-
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
$args = array(
|
53 |
-
'connected_type' => $this->ctype->name,
|
54 |
-
'connected_direction' => $direction,
|
55 |
-
'connected_items' => $item->ID,
|
56 |
-
'post_type' => get_current_screen()->post_type
|
57 |
-
);
|
58 |
|
59 |
-
|
60 |
|
61 |
-
|
62 |
-
|
63 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
}
|
65 |
}
|
66 |
|
1 |
<?php
|
2 |
|
3 |
+
abstract class P2P_Column {
|
4 |
|
5 |
protected $ctype;
|
6 |
|
7 |
protected $connected = array();
|
8 |
|
9 |
+
function __construct( $directed, $items ) {
|
10 |
$this->ctype = $directed;
|
11 |
|
12 |
+
$extra_qv = array(
|
13 |
+
'p2p:per_page' => -1,
|
14 |
+
'p2p:context' => 'admin_column'
|
15 |
+
);
|
16 |
|
17 |
+
$connected = $this->ctype->get_connected( $items, $extra_qv, 'abstract' );
|
18 |
|
19 |
+
$this->connected = p2p_triage_connected( $connected->items );
|
20 |
+
|
21 |
+
$screen = get_current_screen();
|
22 |
+
|
23 |
+
add_filter( "manage_{$screen->id}_columns", array( $this, 'add_column' ) );
|
24 |
}
|
25 |
|
26 |
function add_column( $columns ) {
|
27 |
+
$this->column_id = sprintf( 'p2p-%s-%s',
|
28 |
+
$this->ctype->get_direction(),
|
29 |
+
$this->ctype->name
|
30 |
+
);
|
31 |
+
|
32 |
+
$columns[ $this->column_id ] = $this->ctype->get_current( 'title' );
|
33 |
|
34 |
return $columns;
|
35 |
}
|
45 |
<?php
|
46 |
}
|
47 |
|
48 |
+
abstract function get_admin_link( $item );
|
49 |
+
|
50 |
+
protected function render_column( $column, $item_id ) {
|
51 |
+
if ( $this->column_id != $column )
|
52 |
+
return;
|
53 |
+
|
54 |
+
if ( !isset( $this->connected[ $item_id ] ) )
|
55 |
return;
|
56 |
|
57 |
+
$out = '<ul>';
|
58 |
+
foreach ( $this->connected[ $item_id ] as $item ) {
|
59 |
+
$out .= html( 'li', html_link( $this->get_admin_link( $item ), $item->get_title() ) );
|
60 |
+
}
|
61 |
+
$out .= '</ul>';
|
62 |
+
|
63 |
+
return $out;
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
|
68 |
+
class P2P_Column_Post extends P2P_Column {
|
69 |
+
|
70 |
+
function __construct( $directed ) {
|
71 |
+
global $wp_query;
|
72 |
+
|
73 |
+
$this->ctype = $directed;
|
74 |
+
|
75 |
+
$extra_qv = array( 'p2p:context' => 'admin_column' );
|
76 |
+
|
77 |
+
parent::__construct( $directed, $wp_query->posts );
|
78 |
+
|
79 |
+
$screen = get_current_screen();
|
80 |
+
|
81 |
+
add_action( "manage_{$screen->post_type}_posts_custom_column", array( $this, 'display_column' ), 10, 2 );
|
82 |
+
}
|
83 |
+
|
84 |
+
function get_admin_link( $item ) {
|
85 |
+
$args = array(
|
86 |
+
'connected_type' => $this->ctype->name,
|
87 |
+
'connected_direction' => $this->ctype->flip_direction()->get_direction(),
|
88 |
+
'connected_items' => $item->get_id(),
|
89 |
+
'post_type' => get_current_screen()->post_type
|
90 |
);
|
91 |
|
92 |
+
return add_query_arg( $args, admin_url( 'edit.php' ) );
|
93 |
+
}
|
94 |
+
|
95 |
+
function display_column( $column, $item_id ) {
|
96 |
+
echo parent::render_column( $column, $item_id );
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
|
101 |
+
class P2P_Column_User extends P2P_Column {
|
102 |
|
103 |
+
function __construct( $directed ) {
|
104 |
+
global $wp_list_table;
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
+
parent::__construct( $directed, $wp_list_table->items );
|
107 |
|
108 |
+
add_filter( 'manage_users_custom_column', array( $this, 'display_column' ), 10, 3 );
|
109 |
+
}
|
110 |
+
|
111 |
+
function get_admin_link( $item ) {
|
112 |
+
$args = array(
|
113 |
+
'connected_type' => $this->ctype->name,
|
114 |
+
'connected_direction' => $this->ctype->flip_direction()->get_direction(),
|
115 |
+
'connected_items' => $item->get_id(),
|
116 |
+
);
|
117 |
+
|
118 |
+
return add_query_arg( $args, admin_url( 'users.php' ) );
|
119 |
+
}
|
120 |
+
|
121 |
+
function display_column( $content, $column, $item_id ) {
|
122 |
+
return parent::render_column( $column, $item_id );
|
123 |
}
|
124 |
}
|
125 |
|
admin/factory.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
abstract class P2P_Factory {
|
4 |
+
|
5 |
+
protected $queue = array();
|
6 |
+
|
7 |
+
function register( $p2p_type, $args ) {
|
8 |
+
if ( isset( $this->queue[$p2p_type] ) )
|
9 |
+
return false;
|
10 |
+
|
11 |
+
$args = (object) $args;
|
12 |
+
|
13 |
+
if ( !$args->show )
|
14 |
+
return false;
|
15 |
+
|
16 |
+
$this->queue[$p2p_type] = $args;
|
17 |
+
|
18 |
+
return true;
|
19 |
+
}
|
20 |
+
|
21 |
+
function filter( $object_type, $post_type ) {
|
22 |
+
foreach ( $this->queue as $p2p_type => $args ) {
|
23 |
+
$ctype = p2p_type( $p2p_type );
|
24 |
+
|
25 |
+
$directions = self::determine_directions( $ctype, $object_type, $post_type, $args->show );
|
26 |
+
|
27 |
+
$title = $ctype->title;
|
28 |
+
|
29 |
+
if ( count( $directions ) > 1 && $title['from'] == $title['to'] ) {
|
30 |
+
$title['from'] .= __( ' (from)', P2P_TEXTDOMAIN );
|
31 |
+
$title['to'] .= __( ' (to)', P2P_TEXTDOMAIN );
|
32 |
+
}
|
33 |
+
|
34 |
+
foreach ( $directions as $direction ) {
|
35 |
+
$key = ( 'to' == $direction ) ? 'to' : 'from';
|
36 |
+
|
37 |
+
$directed = $ctype->set_direction( $direction );
|
38 |
+
|
39 |
+
$this->add_item( $directed, $object_type, $post_type, $title[$key] );
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
43 |
+
|
44 |
+
protected static function determine_directions( $ctype, $object_type, $post_type, $show_ui ) {
|
45 |
+
$direction = $ctype->direction_from_types( $object_type, $post_type );
|
46 |
+
if ( !$direction )
|
47 |
+
return array();
|
48 |
+
|
49 |
+
if ( $ctype->indeterminate )
|
50 |
+
$direction = 'any';
|
51 |
+
|
52 |
+
if ( $ctype->reciprocal ) {
|
53 |
+
if ( $show_ui )
|
54 |
+
$directions = array( 'any' );
|
55 |
+
else
|
56 |
+
$directions = array();
|
57 |
+
} else {
|
58 |
+
$directions = array_intersect(
|
59 |
+
_p2p_expand_direction( $show_ui ),
|
60 |
+
_p2p_expand_direction( $direction )
|
61 |
+
);
|
62 |
+
}
|
63 |
+
|
64 |
+
return $directions;
|
65 |
+
}
|
66 |
+
|
67 |
+
abstract function add_item( $directed, $object_type, $post_type, $title );
|
68 |
+
}
|
69 |
+
|
admin/fields.php
CHANGED
@@ -1,23 +1,5 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
class P2P_Field_Create implements P2P_Field {
|
4 |
-
|
5 |
-
function get_title() {
|
6 |
-
// Not needed
|
7 |
-
return '';
|
8 |
-
}
|
9 |
-
|
10 |
-
function render( $p2p_id, $post_id ) {
|
11 |
-
$data = array(
|
12 |
-
'post_id' => $post_id,
|
13 |
-
'title' => __( 'Create connection', P2P_TEXTDOMAIN )
|
14 |
-
);
|
15 |
-
|
16 |
-
return P2P_Mustache::render( 'column-create', $data );
|
17 |
-
}
|
18 |
-
}
|
19 |
-
|
20 |
-
|
21 |
class P2P_Field_Delete implements P2P_Field {
|
22 |
|
23 |
function get_title() {
|
@@ -28,7 +10,7 @@ class P2P_Field_Delete implements P2P_Field {
|
|
28 |
return P2P_Mustache::render( 'column-delete-all', $data );
|
29 |
}
|
30 |
|
31 |
-
function render( $p2p_id, $
|
32 |
$data = array(
|
33 |
'p2p_id' => $p2p_id,
|
34 |
'title' => __( 'Delete connection', P2P_TEXTDOMAIN )
|
@@ -51,7 +33,7 @@ class P2P_Field_Order implements P2P_Field {
|
|
51 |
return '';
|
52 |
}
|
53 |
|
54 |
-
function render( $p2p_id, $
|
55 |
return html( 'input', array(
|
56 |
'type' => 'hidden',
|
57 |
'name' => "p2p_order[$this->sort_key][]",
|
@@ -60,6 +42,7 @@ class P2P_Field_Order implements P2P_Field {
|
|
60 |
}
|
61 |
}
|
62 |
|
|
|
63 |
class P2P_Field_Generic implements P2P_Field {
|
64 |
|
65 |
protected $key;
|
@@ -74,7 +57,7 @@ class P2P_Field_Generic implements P2P_Field {
|
|
74 |
return $this->data['title'];
|
75 |
}
|
76 |
|
77 |
-
function render( $p2p_id, $
|
78 |
$args = array(
|
79 |
'name' => array( 'p2p_meta', $p2p_id, $this->key ),
|
80 |
'type' => $this->data['type']
|
@@ -91,7 +74,31 @@ class P2P_Field_Generic implements P2P_Field {
|
|
91 |
}
|
92 |
|
93 |
|
94 |
-
class
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
|
96 |
protected $title;
|
97 |
|
@@ -103,63 +110,55 @@ class P2P_Field_Title_Post implements P2P_Field {
|
|
103 |
return $this->title;
|
104 |
}
|
105 |
|
106 |
-
function render( $p2p_id, $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
$data = array(
|
108 |
-
'title-attr' => get_permalink(
|
109 |
-
'title' => get_post_field( 'post_title', $post_id ),
|
110 |
-
'url' => get_edit_post_link( $post_id ),
|
111 |
);
|
112 |
|
113 |
-
$
|
114 |
|
115 |
-
if ( 'publish' != $post_status ) {
|
116 |
-
$status_obj = get_post_status_object( $post_status );
|
117 |
if ( $status_obj ) {
|
118 |
$data['status']['text'] = $status_obj->label;
|
119 |
}
|
120 |
}
|
121 |
|
122 |
-
return
|
123 |
}
|
124 |
}
|
125 |
|
|
|
126 |
|
127 |
-
|
128 |
-
|
129 |
-
function render( $p2p_id, $attachment_id ) {
|
130 |
-
list( $src ) = wp_get_attachment_image_src( $attachment_id, 'thumbnail', true );
|
131 |
-
|
132 |
$data = array(
|
133 |
-
'title-attr' =>
|
134 |
-
'title' => html( 'img', compact( 'src' ) ),
|
135 |
-
'url' => get_edit_post_link( $attachment_id ),
|
136 |
);
|
137 |
|
138 |
-
return
|
139 |
}
|
140 |
}
|
141 |
|
|
|
142 |
|
143 |
-
|
144 |
-
|
145 |
-
function render( $p2p_id, $user_id ) {
|
146 |
-
$data = array(
|
147 |
'title-attr' => '',
|
148 |
-
'title' => get_user_by( 'id', $user_id )->display_name,
|
149 |
-
'url' => $this->get_edit_url( $user_id ),
|
150 |
);
|
151 |
-
|
152 |
-
return P2P_Mustache::render( 'column-title', $data );
|
153 |
-
}
|
154 |
-
|
155 |
-
private function get_edit_url( $user_id ) {
|
156 |
-
if ( get_current_user_id() == $user_id ) {
|
157 |
-
$edit_link = 'profile.php';
|
158 |
-
} else {
|
159 |
-
$edit_link = "user-edit.php?user_id=$user_id";
|
160 |
-
}
|
161 |
-
|
162 |
-
return admin_url( $edit_link );
|
163 |
}
|
164 |
}
|
165 |
|
1 |
<?php
|
2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
class P2P_Field_Delete implements P2P_Field {
|
4 |
|
5 |
function get_title() {
|
10 |
return P2P_Mustache::render( 'column-delete-all', $data );
|
11 |
}
|
12 |
|
13 |
+
function render( $p2p_id, $_ ) {
|
14 |
$data = array(
|
15 |
'p2p_id' => $p2p_id,
|
16 |
'title' => __( 'Delete connection', P2P_TEXTDOMAIN )
|
33 |
return '';
|
34 |
}
|
35 |
|
36 |
+
function render( $p2p_id, $_ ) {
|
37 |
return html( 'input', array(
|
38 |
'type' => 'hidden',
|
39 |
'name' => "p2p_order[$this->sort_key][]",
|
42 |
}
|
43 |
}
|
44 |
|
45 |
+
|
46 |
class P2P_Field_Generic implements P2P_Field {
|
47 |
|
48 |
protected $key;
|
57 |
return $this->data['title'];
|
58 |
}
|
59 |
|
60 |
+
function render( $p2p_id, $_ ) {
|
61 |
$args = array(
|
62 |
'name' => array( 'p2p_meta', $p2p_id, $this->key ),
|
63 |
'type' => $this->data['type']
|
74 |
}
|
75 |
|
76 |
|
77 |
+
class P2P_Field_Create implements P2P_Field {
|
78 |
+
|
79 |
+
protected $title_field;
|
80 |
+
|
81 |
+
function __construct( $title_field ) {
|
82 |
+
$this->title_field = $title_field;
|
83 |
+
}
|
84 |
+
|
85 |
+
function get_title() {
|
86 |
+
// Not needed
|
87 |
+
return '';
|
88 |
+
}
|
89 |
+
|
90 |
+
function render( $p2p_id, $item ) {
|
91 |
+
$data = array_merge( $this->title_field->get_data( $item ), array(
|
92 |
+
'title' => $item->get_title(),
|
93 |
+
'item-id' => $item->get_id(),
|
94 |
+
) );
|
95 |
+
|
96 |
+
return P2P_Mustache::render( 'column-create', $data );
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
|
101 |
+
abstract class P2P_Field_Title implements P2P_Field {
|
102 |
|
103 |
protected $title;
|
104 |
|
110 |
return $this->title;
|
111 |
}
|
112 |
|
113 |
+
function render( $p2p_id, $item ) {
|
114 |
+
$data = array_merge( $this->get_data( $item ), array(
|
115 |
+
'title' => $item->get_title(),
|
116 |
+
'url' => $item->get_editlink(),
|
117 |
+
) );
|
118 |
+
|
119 |
+
return P2P_Mustache::render( 'column-title', $data );
|
120 |
+
}
|
121 |
+
|
122 |
+
abstract function get_data( $item );
|
123 |
+
}
|
124 |
+
|
125 |
+
class P2P_Field_Title_Post extends P2P_Field_Title {
|
126 |
+
|
127 |
+
function get_data( $item ) {
|
128 |
$data = array(
|
129 |
+
'title-attr' => $item->get_permalink()
|
|
|
|
|
130 |
);
|
131 |
|
132 |
+
$post = $item->get_object();
|
133 |
|
134 |
+
if ( 'publish' != $post->post_status ) {
|
135 |
+
$status_obj = get_post_status_object( $post->post_status );
|
136 |
if ( $status_obj ) {
|
137 |
$data['status']['text'] = $status_obj->label;
|
138 |
}
|
139 |
}
|
140 |
|
141 |
+
return $data;
|
142 |
}
|
143 |
}
|
144 |
|
145 |
+
class P2P_Field_Title_Attachment extends P2P_Field_Title {
|
146 |
|
147 |
+
function get_data( $item ) {
|
|
|
|
|
|
|
|
|
148 |
$data = array(
|
149 |
+
'title-attr' => $item->get_object()->post_title,
|
|
|
|
|
150 |
);
|
151 |
|
152 |
+
return $data;
|
153 |
}
|
154 |
}
|
155 |
|
156 |
+
class P2P_Field_Title_User extends P2P_Field_Title {
|
157 |
|
158 |
+
function get_data( $user ) {
|
159 |
+
return array(
|
|
|
|
|
160 |
'title-attr' => '',
|
|
|
|
|
161 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
162 |
}
|
163 |
}
|
164 |
|
admin/templates/box.html
CHANGED
@@ -19,20 +19,23 @@
|
|
19 |
|
20 |
{{#create-connections}}
|
21 |
<div class="p2p-create-connections" {{{hide}}}>
|
22 |
-
<p><
|
23 |
-
|
24 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
{{#tabs}}
|
26 |
-
<
|
|
|
|
|
27 |
{{/tabs}}
|
28 |
-
</ul>
|
29 |
-
{{/show-tab-headers}}
|
30 |
-
|
31 |
-
{{#tabs}}
|
32 |
-
<div class="p2p-tab-{{tab-id}} tabs-panel">
|
33 |
-
{{{tab-content}}}
|
34 |
</div>
|
35 |
-
{{/tabs}}
|
36 |
</div>
|
37 |
{{/create-connections}}
|
38 |
</div>
|
19 |
|
20 |
{{#create-connections}}
|
21 |
<div class="p2p-create-connections" {{{hide}}}>
|
22 |
+
<p class="p2p-toggle-tabs"><a href="#">+ {{{label}}}</a></p>
|
23 |
+
|
24 |
+
<div class="p2p-create-connections-tabs" style="display: none">
|
25 |
+
{{#show-tab-headers}}
|
26 |
+
<ul class="wp-tab-bar clearfix">
|
27 |
+
{{#tabs}}
|
28 |
+
<li {{#is-active}}class="wp-tab-active"{{/is-active}} data-ref=".p2p-tab-{{tab-id}}"><a href="#">{{{tab-title}}}</a></li>
|
29 |
+
{{/tabs}}
|
30 |
+
</ul>
|
31 |
+
{{/show-tab-headers}}
|
32 |
+
|
33 |
{{#tabs}}
|
34 |
+
<div class="p2p-tab-{{tab-id}} tabs-panel">
|
35 |
+
{{{tab-content}}}
|
36 |
+
</div>
|
37 |
{{/tabs}}
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
</div>
|
|
|
39 |
</div>
|
40 |
{{/create-connections}}
|
41 |
</div>
|
admin/templates/column-create.html
CHANGED
@@ -1 +1,4 @@
|
|
1 |
-
<
|
|
|
|
|
|
1 |
+
<div data-item-id="{{item-id}}" title="{{{title-attr}}}">
|
2 |
+
<span class="p2p-icon"></span>
|
3 |
+
{{{title}}}{{#status}} - <span class="post-state">{{text}}</span>{{/status}}
|
4 |
+
</div>
|
admin/templates/column-delete-all.html
CHANGED
@@ -1 +1 @@
|
|
1 |
-
<
|
1 |
+
<span class="p2p-icon" title="{{{title}}}"></span>
|
admin/templates/column-delete.html
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
-
<
|
2 |
<input type="hidden" name="p2p_connections[]" value="{{p2p_id}}" />
|
1 |
+
<span class="p2p-icon" title="{{{title}}}"></span>
|
2 |
<input type="hidden" name="p2p_connections[]" value="{{p2p_id}}" />
|
admin/templates/connection-types.html
CHANGED
@@ -1,3 +1,4 @@
|
|
|
|
1 |
<table class="widefat">
|
2 |
<thead>
|
3 |
<tr>
|
@@ -16,3 +17,8 @@
|
|
16 |
{{/rows}}
|
17 |
</tbody>
|
18 |
</table>
|
|
|
|
|
|
|
|
|
|
1 |
+
{{#has-rows}}
|
2 |
<table class="widefat">
|
3 |
<thead>
|
4 |
<tr>
|
17 |
{{/rows}}
|
18 |
</tbody>
|
19 |
</table>
|
20 |
+
{{/has-rows}}
|
21 |
+
{{^has-rows}}
|
22 |
+
<p>{{{no-rows}}}</p>
|
23 |
+
<p>{{{no-rows2}}}</p>
|
24 |
+
{{/has-rows}}
|
admin/templates/tab-search.html
CHANGED
@@ -1,5 +1,5 @@
|
|
1 |
<div class="p2p-search">
|
2 |
<input type="text" name="p2p_search" autocomplete="off" placeholder="{{{placeholder}}}" />
|
3 |
-
|
4 |
-
<button class="button">{{{view-all}}}</button>
|
5 |
</div>
|
|
|
|
1 |
<div class="p2p-search">
|
2 |
<input type="text" name="p2p_search" autocomplete="off" placeholder="{{{placeholder}}}" />
|
|
|
|
|
3 |
</div>
|
4 |
+
|
5 |
+
{{{candidates}}}
|
admin/tools.php
CHANGED
@@ -23,20 +23,7 @@ class P2P_Tools_Page extends scbAdminPage {
|
|
23 |
|
24 |
P2P_Storage::install();
|
25 |
|
26 |
-
|
27 |
-
$n = P2P_Storage::upgrade();
|
28 |
-
|
29 |
-
update_option( 'p2p_storage', P2P_Storage::$version );
|
30 |
-
|
31 |
-
echo scb_admin_notice( sprintf( __( 'Upgraded %d connections.', P2P_TEXTDOMAIN ), $n ) );
|
32 |
-
} elseif ( $current_ver ) {
|
33 |
-
echo scb_admin_notice( sprintf(
|
34 |
-
__( 'The Posts 2 Posts connections need to be upgraded. <a href="%s">Proceed.</a>', P2P_TEXTDOMAIN ),
|
35 |
-
admin_url( 'tools.php?page=connection-types&p2p-upgrade=1' )
|
36 |
-
) );
|
37 |
-
} else {
|
38 |
-
update_option( 'p2p_storage', P2P_Storage::$version );
|
39 |
-
}
|
40 |
}
|
41 |
|
42 |
function form_handler() {
|
@@ -80,22 +67,35 @@ class P2P_Tools_Page extends scbAdminPage {
|
|
80 |
)
|
81 |
);
|
82 |
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
|
|
|
|
|
|
|
|
87 |
);
|
|
|
|
|
88 |
|
89 |
-
$
|
|
|
|
|
|
|
|
|
90 |
|
91 |
-
|
92 |
-
$row['desc'] = $ctype->get_desc();
|
93 |
-
} else {
|
94 |
-
$row['desc'] = __( 'Convert to registered connection type:', P2P_TEXTDOMAIN ) . scbForms::form_wrap( $this->get_dropdown( $p2p_type ), $this->nonce );
|
95 |
-
$row['class'] = 'error';
|
96 |
-
}
|
97 |
|
98 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
}
|
100 |
|
101 |
echo P2P_Mustache::render( 'connection-types', $data );
|
23 |
|
24 |
P2P_Storage::install();
|
25 |
|
26 |
+
update_option( 'p2p_storage', P2P_Storage::$version );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
}
|
28 |
|
29 |
function form_handler() {
|
67 |
)
|
68 |
);
|
69 |
|
70 |
+
$connection_counts = $this->get_connection_counts();
|
71 |
+
|
72 |
+
if ( empty( $connection_counts ) ) {
|
73 |
+
$data['has-rows'] = false;
|
74 |
+
$data['no-rows'] = __( 'No connection types registered.', P2P_TEXTDOMAIN );
|
75 |
+
$data['no-rows2'] = sprintf(
|
76 |
+
__( 'To register a connection type, see <a href="%s">the wiki</a>.', P2P_TEXTDOMAIN ),
|
77 |
+
'https://github.com/scribu/wp-posts-to-posts/wiki/'
|
78 |
);
|
79 |
+
} else {
|
80 |
+
$data['has-rows'] = array(true);
|
81 |
|
82 |
+
foreach ( $connection_counts as $p2p_type => $count ) {
|
83 |
+
$row = array(
|
84 |
+
'p2p_type' => $p2p_type,
|
85 |
+
'count' => number_format_i18n( $count )
|
86 |
+
);
|
87 |
|
88 |
+
$ctype = p2p_type( $p2p_type );
|
|
|
|
|
|
|
|
|
|
|
89 |
|
90 |
+
if ( $ctype ) {
|
91 |
+
$row['desc'] = $ctype->get_desc();
|
92 |
+
} else {
|
93 |
+
$row['desc'] = __( 'Convert to registered connection type:', P2P_TEXTDOMAIN ) . scbForms::form_wrap( $this->get_dropdown( $p2p_type ), $this->nonce );
|
94 |
+
$row['class'] = 'error';
|
95 |
+
}
|
96 |
+
|
97 |
+
$data['rows'][] = $row;
|
98 |
+
}
|
99 |
}
|
100 |
|
101 |
echo P2P_Mustache::render( 'connection-types', $data );
|
core/api.php
CHANGED
@@ -171,7 +171,7 @@ function _p2p_get_connections( $p2p_type, $args = array() ) {
|
|
171 |
if ( empty( $$key ) )
|
172 |
return array();
|
173 |
|
174 |
-
$value = scbUtil::array_to_sql( (
|
175 |
|
176 |
$where .= " AND p2p_$key IN ($value)";
|
177 |
}
|
@@ -228,8 +228,8 @@ function p2p_create_connection( $p2p_type, $args ) {
|
|
228 |
'meta' => array()
|
229 |
) ), EXTR_SKIP );
|
230 |
|
231 |
-
$from =
|
232 |
-
$to =
|
233 |
|
234 |
if ( !$from || !$to )
|
235 |
return false;
|
@@ -251,6 +251,8 @@ function p2p_create_connection( $p2p_type, $args ) {
|
|
251 |
foreach ( $meta as $key => $value )
|
252 |
p2p_add_meta( $p2p_id, $key, $value );
|
253 |
|
|
|
|
|
254 |
return $p2p_id;
|
255 |
}
|
256 |
|
@@ -283,6 +285,8 @@ function p2p_delete_connection( $p2p_id ) {
|
|
283 |
|
284 |
$p2p_ids = array_map( 'absint', (array) $p2p_id );
|
285 |
|
|
|
|
|
286 |
$where = "WHERE p2p_id IN (" . implode( ',', $p2p_ids ) . ")";
|
287 |
|
288 |
$count = $wpdb->query( "DELETE FROM $wpdb->p2p $where" );
|
@@ -339,6 +343,16 @@ function p2p_distribute_connected( $items, $connected, $prop_name ) {
|
|
339 |
$indexed_list[ $item->ID ] = $item;
|
340 |
}
|
341 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
342 |
foreach ( $connected as $inner_item ) {
|
343 |
if ( $inner_item->ID == $inner_item->p2p_from ) {
|
344 |
$outer_item_id = $inner_item->p2p_to;
|
@@ -349,7 +363,9 @@ function p2p_distribute_connected( $items, $connected, $prop_name ) {
|
|
349 |
continue;
|
350 |
}
|
351 |
|
352 |
-
|
353 |
}
|
|
|
|
|
354 |
}
|
355 |
|
171 |
if ( empty( $$key ) )
|
172 |
return array();
|
173 |
|
174 |
+
$value = scbUtil::array_to_sql( _p2p_normalize( $$key ) );
|
175 |
|
176 |
$where .= " AND p2p_$key IN ($value)";
|
177 |
}
|
228 |
'meta' => array()
|
229 |
) ), EXTR_SKIP );
|
230 |
|
231 |
+
list( $from ) = _p2p_normalize( $from );
|
232 |
+
list( $to ) = _p2p_normalize( $to );
|
233 |
|
234 |
if ( !$from || !$to )
|
235 |
return false;
|
251 |
foreach ( $meta as $key => $value )
|
252 |
p2p_add_meta( $p2p_id, $key, $value );
|
253 |
|
254 |
+
do_action( 'p2p_created_connection', $p2p_id );
|
255 |
+
|
256 |
return $p2p_id;
|
257 |
}
|
258 |
|
285 |
|
286 |
$p2p_ids = array_map( 'absint', (array) $p2p_id );
|
287 |
|
288 |
+
do_action( 'p2p_delete_connections', $p2p_ids );
|
289 |
+
|
290 |
$where = "WHERE p2p_id IN (" . implode( ',', $p2p_ids ) . ")";
|
291 |
|
292 |
$count = $wpdb->query( "DELETE FROM $wpdb->p2p $where" );
|
343 |
$indexed_list[ $item->ID ] = $item;
|
344 |
}
|
345 |
|
346 |
+
$groups = p2p_triage_connected( $connected );
|
347 |
+
|
348 |
+
foreach ( $groups as $outer_item_id => $connected_items ) {
|
349 |
+
$indexed_list[ $outer_item_id ]->$prop_name = $connected_items;
|
350 |
+
}
|
351 |
+
}
|
352 |
+
|
353 |
+
function p2p_triage_connected( $connected ) {
|
354 |
+
$groups = array();
|
355 |
+
|
356 |
foreach ( $connected as $inner_item ) {
|
357 |
if ( $inner_item->ID == $inner_item->p2p_from ) {
|
358 |
$outer_item_id = $inner_item->p2p_to;
|
363 |
continue;
|
364 |
}
|
365 |
|
366 |
+
$groups[ $outer_item_id ][] = $inner_item;
|
367 |
}
|
368 |
+
|
369 |
+
return $groups;
|
370 |
}
|
371 |
|
core/directed-type.php
CHANGED
@@ -31,12 +31,7 @@ class P2P_Directed_Connection_Type {
|
|
31 |
}
|
32 |
|
33 |
public function flip_direction() {
|
34 |
-
|
35 |
-
return $this;
|
36 |
-
|
37 |
-
$direction = ( 'to' == $this->direction ) ? 'from' : 'to';
|
38 |
-
|
39 |
-
return $this->set_direction( $direction );
|
40 |
}
|
41 |
|
42 |
public function get_opposite( $key ) {
|
@@ -98,34 +93,12 @@ class P2P_Directed_Connection_Type {
|
|
98 |
$side = $this->get_opposite( 'side' );
|
99 |
|
100 |
$args = array_merge( $side->translate_qv( $extra_qv ), array(
|
|
|
|
|
101 |
'connected_items' => $item
|
102 |
) );
|
103 |
|
104 |
-
return $this->abstract_query( $
|
105 |
-
}
|
106 |
-
|
107 |
-
public function get_connected_args( $q ) {
|
108 |
-
$q = wp_parse_args( $q, array(
|
109 |
-
'p2p:context' => false
|
110 |
-
) );
|
111 |
-
|
112 |
-
if ( $orderby_key = $this->get_orderby_key() ) {
|
113 |
-
$q = wp_parse_args( $q, array(
|
114 |
-
'connected_orderby' => $orderby_key,
|
115 |
-
'connected_order' => 'ASC',
|
116 |
-
'connected_order_num' => true,
|
117 |
-
) );
|
118 |
-
}
|
119 |
-
|
120 |
-
$q = array_merge( $this->get_opposite( 'side' )->get_base_qv( $q ), array(
|
121 |
-
'p2p_type' => array( $this->name => $this->get_direction() ),
|
122 |
-
) );
|
123 |
-
|
124 |
-
$q = array_merge_recursive( $q, array(
|
125 |
-
'connected_meta' => $this->data
|
126 |
-
) );
|
127 |
-
|
128 |
-
return apply_filters( 'p2p_connected_args', $q, $this, $q['connected_items'] );
|
129 |
}
|
130 |
|
131 |
public function get_orderby_key() {
|
@@ -145,38 +118,40 @@ class P2P_Directed_Connection_Type {
|
|
145 |
/**
|
146 |
* Get a list of items that could be connected to a given item.
|
147 |
*
|
148 |
-
* @param
|
149 |
*/
|
150 |
-
public function get_connectable( $
|
151 |
$side = $this->get_opposite( 'side' );
|
152 |
|
153 |
-
$
|
|
|
|
|
154 |
|
155 |
$extra_qv = $side->get_base_qv( $side->translate_qv( $extra_qv ) );
|
156 |
|
157 |
-
$qv = apply_filters( 'p2p_connectable_args', $extra_qv, $this, $
|
158 |
|
159 |
return $this->abstract_query( $qv, $side );
|
160 |
}
|
161 |
|
162 |
-
private function get_non_connectable( $
|
163 |
$to_exclude = array();
|
164 |
|
165 |
if ( $this->indeterminate && !$this->self_connections )
|
166 |
-
$to_exclude[] = $
|
167 |
|
168 |
if ( 'one' == $this->get_current( 'cardinality' ) ) {
|
169 |
-
|
170 |
-
|
171 |
-
|
|
|
|
|
172 |
}
|
173 |
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
) ) );
|
179 |
-
}
|
180 |
|
181 |
return $to_exclude;
|
182 |
}
|
@@ -191,25 +166,29 @@ class P2P_Directed_Connection_Type {
|
|
191 |
* @return int|object p2p_id or WP_Error on failure
|
192 |
*/
|
193 |
public function connect( $from, $to, $meta = array() ) {
|
194 |
-
$from = $this->get_current( 'side' )->
|
195 |
if ( !$from )
|
196 |
return new WP_Error( 'first_parameter', 'Invalid first parameter.' );
|
197 |
|
198 |
-
$to = $this->get_opposite( 'side' )->
|
199 |
if ( !$to )
|
200 |
return new WP_Error( 'second_parameter', 'Invalid second parameter.' );
|
201 |
|
202 |
-
if ( !$this->self_connections && $from == $to )
|
203 |
return new WP_Error( 'self_connection', 'Connection between an element and itself is not allowed.' );
|
204 |
|
205 |
if ( !$this->duplicate_connections && $this->get_p2p_id( $from, $to ) )
|
206 |
return new WP_Error( 'duplicate_connection', 'Duplicate connections are not allowed.' );
|
207 |
|
208 |
-
if ( 'one' == $this->get_opposite( 'cardinality' )
|
209 |
-
|
|
|
|
|
210 |
|
211 |
-
if ( 'one' == $this->get_current( 'cardinality' )
|
212 |
-
|
|
|
|
|
213 |
|
214 |
$p2p_id = $this->create_connection( array(
|
215 |
'from' => $from,
|
@@ -228,6 +207,14 @@ class P2P_Directed_Connection_Type {
|
|
228 |
return $p2p_id;
|
229 |
}
|
230 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
231 |
protected function get_default( $args, $p2p_id ) {
|
232 |
if ( isset( $args['default_cb'] ) )
|
233 |
return call_user_func( $args['default_cb'], p2p_get_connection( $p2p_id ) );
|
@@ -247,12 +234,12 @@ class P2P_Directed_Connection_Type {
|
|
247 |
* @return int|object count or WP_Error on failure
|
248 |
*/
|
249 |
public function disconnect( $from, $to ) {
|
250 |
-
$from = $this->get_current( 'side' )->
|
251 |
if ( !$from )
|
252 |
return new WP_Error( 'first_parameter', 'Invalid first parameter.' );
|
253 |
|
254 |
if ( 'any' != $to ) {
|
255 |
-
$to = $this->get_opposite( 'side' )->
|
256 |
if ( !$to )
|
257 |
return new WP_Error( 'second_parameter', 'Invalid second parameter.' );
|
258 |
}
|
31 |
}
|
32 |
|
33 |
public function flip_direction() {
|
34 |
+
return $this->set_direction( _p2p_flip_direction( $this->direction ) );
|
|
|
|
|
|
|
|
|
|
|
35 |
}
|
36 |
|
37 |
public function get_opposite( $key ) {
|
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() {
|
118 |
/**
|
119 |
* Get a list of items that could be connected to a given item.
|
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;
|
147 |
+
} else {
|
148 |
+
return $to_exclude;
|
149 |
}
|
150 |
|
151 |
+
$extra_qv['fields'] = 'ids';
|
152 |
+
$already_connected = $this->get_connected( $to_check, $extra_qv, 'abstract' )->items;
|
153 |
+
|
154 |
+
_p2p_append( $to_exclude, $already_connected );
|
|
|
|
|
155 |
|
156 |
return $to_exclude;
|
157 |
}
|
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.' );
|
179 |
|
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 |
|
193 |
$p2p_id = $this->create_connection( array(
|
194 |
'from' => $from,
|
207 |
return $p2p_id;
|
208 |
}
|
209 |
|
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 |
+
}
|
217 |
+
|
218 |
protected function get_default( $args, $p2p_id ) {
|
219 |
if ( isset( $args['default_cb'] ) )
|
220 |
return call_user_func( $args['default_cb'], p2p_get_connection( $p2p_id ) );
|
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 |
}
|
core/extra.php
CHANGED
@@ -25,9 +25,6 @@ class P2P_Widget extends scbWidget {
|
|
25 |
$ctypes = array();
|
26 |
|
27 |
foreach ( P2P_Connection_Type_Factory::get_all_instances() as $p2p_type => $ctype ) {
|
28 |
-
if ( ! $ctype instanceof P2P_Connection_Type )
|
29 |
-
continue;
|
30 |
-
|
31 |
$ctypes[ $p2p_type ] = $ctype->get_desc();
|
32 |
}
|
33 |
|
@@ -41,7 +38,8 @@ class P2P_Widget extends scbWidget {
|
|
41 |
'type' => 'select',
|
42 |
'name' => 'ctype',
|
43 |
'values' => $ctypes,
|
44 |
-
'desc' => __( 'Connection type:', P2P_TEXTDOMAIN )
|
|
|
45 |
), $instance ) );
|
46 |
|
47 |
echo html( 'p',
|
25 |
$ctypes = array();
|
26 |
|
27 |
foreach ( P2P_Connection_Type_Factory::get_all_instances() as $p2p_type => $ctype ) {
|
|
|
|
|
|
|
28 |
$ctypes[ $p2p_type ] = $ctype->get_desc();
|
29 |
}
|
30 |
|
38 |
'type' => 'select',
|
39 |
'name' => 'ctype',
|
40 |
'values' => $ctypes,
|
41 |
+
'desc' => __( 'Connection type:', P2P_TEXTDOMAIN ),
|
42 |
+
'extra' => "style='width: 100%'"
|
43 |
), $instance ) );
|
44 |
|
45 |
echo html( 'p',
|
core/item.php
ADDED
@@ -0,0 +1,90 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
abstract class P2P_Item {
|
4 |
+
|
5 |
+
protected $item;
|
6 |
+
|
7 |
+
function __construct( $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 |
+
}
|
18 |
+
|
19 |
+
function get_id() {
|
20 |
+
return $this->item->ID;
|
21 |
+
}
|
22 |
+
|
23 |
+
abstract function get_permalink();
|
24 |
+
abstract function get_title();
|
25 |
+
}
|
26 |
+
|
27 |
+
|
28 |
+
class P2P_Item_Post extends P2P_Item {
|
29 |
+
|
30 |
+
function get_title() {
|
31 |
+
return get_the_title( $this->item );
|
32 |
+
}
|
33 |
+
|
34 |
+
function get_permalink() {
|
35 |
+
return get_permalink( $this->item );
|
36 |
+
}
|
37 |
+
|
38 |
+
function get_editlink() {
|
39 |
+
return get_edit_post_link( $this->item );
|
40 |
+
}
|
41 |
+
}
|
42 |
+
|
43 |
+
|
44 |
+
class P2P_Item_Attachment extends P2P_Item_Post {
|
45 |
+
|
46 |
+
function get_title() {
|
47 |
+
return wp_get_attachment_image( $this->item->ID, 'thumbnail', false );
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
|
52 |
+
class P2P_Item_User extends P2P_Item {
|
53 |
+
|
54 |
+
function get_title() {
|
55 |
+
return $this->item->display_name;
|
56 |
+
}
|
57 |
+
|
58 |
+
function get_permalink() {
|
59 |
+
return get_author_posts_url( $this->item->ID );
|
60 |
+
}
|
61 |
+
|
62 |
+
function get_editlink() {
|
63 |
+
return get_edit_user_link( $this->item->ID );
|
64 |
+
}
|
65 |
+
}
|
66 |
+
|
67 |
+
|
68 |
+
// WP < 3.5
|
69 |
+
if ( !function_exists( 'get_edit_user_link' ) ) :
|
70 |
+
function get_edit_user_link( $user_id = null ) {
|
71 |
+
if ( ! $user_id )
|
72 |
+
$user_id = get_current_user_id();
|
73 |
+
|
74 |
+
if ( empty( $user_id ) || ! current_user_can( 'edit_user', $user_id ) )
|
75 |
+
return '';
|
76 |
+
|
77 |
+
$user = new WP_User( $user_id );
|
78 |
+
|
79 |
+
if ( ! $user->exists() )
|
80 |
+
return '';
|
81 |
+
|
82 |
+
if ( get_current_user_id() == $user->ID )
|
83 |
+
$link = get_edit_profile_url( $user->ID );
|
84 |
+
else
|
85 |
+
$link = add_query_arg( 'user_id', $user->ID, self_admin_url( 'user-edit.php' ) );
|
86 |
+
|
87 |
+
return apply_filters( 'get_edit_user_link', $link, $user->ID );
|
88 |
+
}
|
89 |
+
endif;
|
90 |
+
|
core/list.php
CHANGED
@@ -6,6 +6,16 @@ abstract class P2P_List {
|
|
6 |
public $current_page = 1;
|
7 |
public $total_pages = 0;
|
8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
function render( $args = array() ) {
|
10 |
if ( empty( $this->items ) )
|
11 |
return '';
|
@@ -33,7 +43,11 @@ abstract class P2P_List {
|
|
33 |
echo $before_list;
|
34 |
|
35 |
if ( $separator ) {
|
36 |
-
|
|
|
|
|
|
|
|
|
37 |
} else {
|
38 |
foreach ( $this->items as $item ) {
|
39 |
echo $before_item . $this->render_item( $item ) . $after_item;
|
@@ -46,7 +60,9 @@ abstract class P2P_List {
|
|
46 |
return ob_get_clean();
|
47 |
}
|
48 |
|
49 |
-
|
|
|
|
|
50 |
}
|
51 |
|
52 |
|
@@ -54,26 +70,19 @@ class P2P_List_Post extends P2P_List {
|
|
54 |
|
55 |
function __construct( $wp_query ) {
|
56 |
if ( is_array( $wp_query ) ) {
|
57 |
-
$
|
58 |
} else {
|
59 |
-
$
|
60 |
$this->current_page = max( 1, $wp_query->get('paged') );
|
61 |
$this->total_pages = $wp_query->max_num_pages;
|
62 |
}
|
63 |
-
}
|
64 |
|
65 |
-
|
66 |
-
return html( 'a', array( 'href' => get_permalink( $post ) ), get_the_title( $post ) );
|
67 |
}
|
68 |
}
|
69 |
|
70 |
|
71 |
-
class P2P_List_Attachment extends P2P_List_Post {
|
72 |
-
|
73 |
-
protected function render_item( $post ) {
|
74 |
-
return html( 'a', array( 'href' => get_permalink( $post ) ), wp_get_attachment_image( $post->ID, 'thumbnail', false ) );
|
75 |
-
}
|
76 |
-
}
|
77 |
|
78 |
|
79 |
class P2P_List_User extends P2P_List {
|
@@ -81,16 +90,12 @@ class P2P_List_User extends P2P_List {
|
|
81 |
function __construct( $query ) {
|
82 |
$qv = $query->query_vars;
|
83 |
|
84 |
-
$this->items = $query->get_results();
|
85 |
-
|
86 |
if ( isset( $qv['p2p:page'] ) ) {
|
87 |
$this->current_page = $qv['p2p:page'];
|
88 |
$this->total_pages = ceil( $query->get_total() / $qv['p2p:per_page'] );
|
89 |
}
|
90 |
-
}
|
91 |
|
92 |
-
|
93 |
-
return html( 'a', array( 'href' => get_author_posts_url( $user->ID ) ), $user->display_name );
|
94 |
}
|
95 |
}
|
96 |
|
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 |
+
|
19 |
function render( $args = array() ) {
|
20 |
if ( empty( $this->items ) )
|
21 |
return '';
|
43 |
echo $before_list;
|
44 |
|
45 |
if ( $separator ) {
|
46 |
+
$list = array();
|
47 |
+
foreach ( $this->items as $item ) {
|
48 |
+
$list[] = $this->render_item( $item->get_object() );
|
49 |
+
}
|
50 |
+
echo implode( $separator, $list );
|
51 |
} else {
|
52 |
foreach ( $this->items as $item ) {
|
53 |
echo $before_item . $this->render_item( $item ) . $after_item;
|
60 |
return ob_get_clean();
|
61 |
}
|
62 |
|
63 |
+
protected function render_item( $item ) {
|
64 |
+
return html_link( $item->get_permalink(), $item->get_title() );
|
65 |
+
}
|
66 |
}
|
67 |
|
68 |
|
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 {
|
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 |
|
core/query-post.php
CHANGED
@@ -1,64 +1,63 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
|
4 |
-
* Handles connected{_to|_from} query vars
|
5 |
-
*/
|
6 |
-
class P2P_WP_Query {
|
7 |
|
8 |
static function init() {
|
9 |
add_action( 'parse_query', array( __CLASS__, 'parse_query' ), 20 );
|
10 |
-
add_filter( 'posts_clauses', array( __CLASS__, 'posts_clauses' ),
|
|
|
11 |
add_filter( 'the_posts', array( __CLASS__, 'cache_p2p_meta' ), 20, 2 );
|
12 |
}
|
13 |
|
14 |
static function parse_query( $wp_query ) {
|
15 |
-
$
|
16 |
|
17 |
-
|
|
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
} else {
|
22 |
-
$item = isset( $q['post_type'] ) ? $q['post_type'] : 'post';
|
23 |
}
|
24 |
|
25 |
-
|
|
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
$wp_query->is_archive = true;
|
32 |
-
}
|
33 |
}
|
34 |
|
35 |
static function posts_clauses( $clauses, $wp_query ) {
|
36 |
global $wpdb;
|
37 |
|
38 |
-
|
39 |
-
|
40 |
-
if ( !$qv )
|
41 |
return $clauses;
|
42 |
|
43 |
-
$wp_query->
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
|
45 |
-
return
|
46 |
}
|
47 |
|
48 |
/**
|
49 |
* Pre-populates the p2p meta cache to decrease the number of queries.
|
50 |
*/
|
51 |
static function cache_p2p_meta( $the_posts, $wp_query ) {
|
52 |
-
if ( empty( $the_posts ) )
|
53 |
-
return $the_posts;
|
54 |
-
|
55 |
-
if ( isset( $wp_query->_p2p_cache ) ) {
|
56 |
update_meta_cache( 'p2p', wp_list_pluck( $the_posts, 'p2p_id' ) );
|
57 |
-
}
|
58 |
|
59 |
return $the_posts;
|
60 |
}
|
61 |
}
|
62 |
|
63 |
-
|
64 |
|
1 |
<?php
|
2 |
|
3 |
+
class P2P_Post_Query {
|
|
|
|
|
|
|
4 |
|
5 |
static function init() {
|
6 |
add_action( 'parse_query', array( __CLASS__, 'parse_query' ), 20 );
|
7 |
+
add_filter( 'posts_clauses', array( __CLASS__, 'posts_clauses' ), 20, 2 );
|
8 |
+
add_filter( 'posts_request', array( __CLASS__, 'capture' ), 999, 2 );
|
9 |
add_filter( 'the_posts', array( __CLASS__, 'cache_p2p_meta' ), 20, 2 );
|
10 |
}
|
11 |
|
12 |
static function parse_query( $wp_query ) {
|
13 |
+
$p2p_q = P2P_Query::create_from_qv( $wp_query->query_vars, 'post' );
|
14 |
|
15 |
+
if ( is_wp_error( $p2p_q ) ) {
|
16 |
+
trigger_error( $p2p_q->get_error_message(), E_USER_WARNING );
|
17 |
|
18 |
+
$wp_query->set( 'year', 2525 );
|
19 |
+
return;
|
|
|
|
|
20 |
}
|
21 |
|
22 |
+
if ( null === $p2p_q )
|
23 |
+
return;
|
24 |
|
25 |
+
$wp_query->_p2p_query = $p2p_q;
|
26 |
+
|
27 |
+
$wp_query->is_home = false;
|
28 |
+
$wp_query->is_archive = true;
|
|
|
|
|
29 |
}
|
30 |
|
31 |
static function posts_clauses( $clauses, $wp_query ) {
|
32 |
global $wpdb;
|
33 |
|
34 |
+
if ( !isset( $wp_query->_p2p_query ) )
|
|
|
|
|
35 |
return $clauses;
|
36 |
|
37 |
+
return $wp_query->_p2p_query->alter_clauses( $clauses, "$wpdb->posts.ID" );
|
38 |
+
}
|
39 |
+
|
40 |
+
static function capture( $request, $wp_query ) {
|
41 |
+
global $wpdb;
|
42 |
+
|
43 |
+
if ( !isset( $wp_query->_p2p_capture ) )
|
44 |
+
return $request;
|
45 |
+
|
46 |
+
$wp_query->_p2p_sql = $request;
|
47 |
|
48 |
+
return '';
|
49 |
}
|
50 |
|
51 |
/**
|
52 |
* Pre-populates the p2p meta cache to decrease the number of queries.
|
53 |
*/
|
54 |
static function cache_p2p_meta( $the_posts, $wp_query ) {
|
55 |
+
if ( isset( $wp_query->_p2p_query ) && !empty( $the_posts ) )
|
|
|
|
|
|
|
56 |
update_meta_cache( 'p2p', wp_list_pluck( $the_posts, 'p2p_id' ) );
|
|
|
57 |
|
58 |
return $the_posts;
|
59 |
}
|
60 |
}
|
61 |
|
62 |
+
P2P_Post_Query::init();
|
63 |
|
core/query-user.php
CHANGED
@@ -9,28 +9,16 @@ class P2P_User_Query {
|
|
9 |
static function pre_user_query( $query ) {
|
10 |
global $wpdb;
|
11 |
|
12 |
-
$
|
13 |
|
14 |
-
|
|
|
15 |
|
16 |
-
if ( isset( $q['connected_items'] ) ) {
|
17 |
-
$item = $q['connected_items'];
|
18 |
-
} else {
|
19 |
-
$item = 'any';
|
20 |
-
}
|
21 |
-
|
22 |
-
$r = P2P_Query::expand_connected_type( $q, $item, 'user' );
|
23 |
-
|
24 |
-
if ( false === $r ) {
|
25 |
$query->query_where = " AND 1=0";
|
26 |
return;
|
27 |
}
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
$qv = P2P_Query::get_qv( $q );
|
32 |
-
|
33 |
-
if ( !$qv )
|
34 |
return;
|
35 |
|
36 |
$map = array(
|
@@ -45,13 +33,13 @@ class P2P_User_Query {
|
|
45 |
foreach ( $map as $clause => $key )
|
46 |
$clauses[$clause] = $query->$key;
|
47 |
|
48 |
-
$clauses =
|
49 |
|
50 |
if ( 0 !== strpos( $clauses['orderby'], 'ORDER BY ' ) )
|
51 |
$clauses['orderby'] = 'ORDER BY ' . $clauses['orderby'];
|
52 |
|
53 |
foreach ( $map as $clause => $key )
|
54 |
-
$query->$key = $clauses[$clause];
|
55 |
}
|
56 |
}
|
57 |
|
9 |
static function pre_user_query( $query ) {
|
10 |
global $wpdb;
|
11 |
|
12 |
+
$p2p_q = P2P_Query::create_from_qv( $query->query_vars, 'user' );
|
13 |
|
14 |
+
if ( is_wp_error( $p2p_q ) ) {
|
15 |
+
trigger_error( $p2p_q->get_error_message(), E_USER_WARNING );
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
$query->query_where = " AND 1=0";
|
18 |
return;
|
19 |
}
|
20 |
|
21 |
+
if ( null === $p2p_q )
|
|
|
|
|
|
|
|
|
22 |
return;
|
23 |
|
24 |
$map = array(
|
33 |
foreach ( $map as $clause => $key )
|
34 |
$clauses[$clause] = $query->$key;
|
35 |
|
36 |
+
$clauses = $p2p_q->alter_clauses( $clauses, "$wpdb->users.ID" );
|
37 |
|
38 |
if ( 0 !== strpos( $clauses['orderby'], 'ORDER BY ' ) )
|
39 |
$clauses['orderby'] = 'ORDER BY ' . $clauses['orderby'];
|
40 |
|
41 |
foreach ( $map as $clause => $key )
|
42 |
+
$query->$key = $clauses[ $clause ];
|
43 |
}
|
44 |
}
|
45 |
|
core/query.php
CHANGED
@@ -2,54 +2,39 @@
|
|
2 |
|
3 |
class P2P_Query {
|
4 |
|
5 |
-
|
6 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
'connected' => 'any',
|
8 |
'connected_to' => 'to',
|
9 |
'connected_from' => 'from',
|
10 |
);
|
11 |
|
12 |
-
foreach ( $
|
13 |
if ( !empty( $q[ $key ] ) ) {
|
14 |
$q['connected_items'] = _p2p_pluck( $q, $key );
|
15 |
$q['connected_direction'] = $direction;
|
16 |
}
|
17 |
}
|
18 |
-
}
|
19 |
|
20 |
-
|
21 |
-
if ( !isset( $q['p2p_type'] ) ) {
|
22 |
if ( isset( $q['connected_items'] ) ) {
|
23 |
-
|
24 |
}
|
25 |
-
return false;
|
26 |
-
}
|
27 |
-
|
28 |
-
$qv['p2p_type'] = $q['p2p_type'];
|
29 |
|
30 |
-
$qv_list = array(
|
31 |
-
'items', 'direction', 'meta',
|
32 |
-
'orderby', 'order_num', 'order'
|
33 |
-
);
|
34 |
-
|
35 |
-
foreach ( $qv_list as $key ) {
|
36 |
-
$qv[$key] = isset( $q["connected_$key"] ) ? $q["connected_$key"] : false;
|
37 |
-
}
|
38 |
-
|
39 |
-
return $qv;
|
40 |
-
}
|
41 |
-
|
42 |
-
/**
|
43 |
-
* Sets 'p2p_type' => array( connection_type => direction )
|
44 |
-
*
|
45 |
-
* @return:
|
46 |
-
* null means ignore current query
|
47 |
-
* false means trigger 404
|
48 |
-
* true means proceed
|
49 |
-
*/
|
50 |
-
static function expand_connected_type( &$q, $item, $object_type ) {
|
51 |
-
if ( !isset( $q['connected_type'] ) )
|
52 |
return;
|
|
|
53 |
|
54 |
$ctypes = (array) _p2p_pluck( $q, 'connected_type' );
|
55 |
|
@@ -58,6 +43,8 @@ class P2P_Query {
|
|
58 |
else
|
59 |
$directions = array();
|
60 |
|
|
|
|
|
61 |
$p2p_types = array();
|
62 |
|
63 |
foreach ( $ctypes as $i => $p2p_type ) {
|
@@ -69,51 +56,91 @@ class P2P_Query {
|
|
69 |
if ( isset( $directions[$i] ) ) {
|
70 |
$directed = $ctype->set_direction( $directions[$i] );
|
71 |
} else {
|
72 |
-
$directed =
|
73 |
}
|
74 |
|
75 |
if ( !$directed )
|
76 |
continue;
|
77 |
|
78 |
-
$p2p_types[
|
79 |
}
|
80 |
|
81 |
if ( empty( $p2p_types ) )
|
82 |
-
return
|
83 |
|
84 |
-
if ( 1 == count( $p2p_types ) )
|
85 |
-
$
|
86 |
-
|
87 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
|
89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
}
|
91 |
|
92 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
global $wpdb;
|
94 |
|
95 |
$clauses['fields'] .= ", $wpdb->p2p.*";
|
96 |
|
97 |
$clauses['join'] .= " INNER JOIN $wpdb->p2p";
|
98 |
|
99 |
-
// Handle main query
|
100 |
-
if ( 'any' == $q['items'] ) {
|
101 |
-
$search = false;
|
102 |
-
} else {
|
103 |
-
$search = implode( ',', array_map( 'absint', _p2p_normalize( $q['items'] ) ) );
|
104 |
-
}
|
105 |
-
|
106 |
$where_parts = array();
|
107 |
|
108 |
-
foreach ( $
|
109 |
-
if (
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
|
114 |
$fields = array( 'p2p_from', 'p2p_to' );
|
115 |
|
116 |
-
switch ( $
|
117 |
|
118 |
case 'from':
|
119 |
$fields = array_reverse( $fields );
|
@@ -121,22 +148,20 @@ class P2P_Query {
|
|
121 |
case 'to':
|
122 |
list( $from, $to ) = $fields;
|
123 |
|
124 |
-
$
|
125 |
|
126 |
-
|
127 |
-
|
128 |
-
}
|
129 |
|
130 |
break;
|
131 |
default:
|
132 |
-
|
133 |
-
$
|
134 |
-
|
135 |
-
|
136 |
-
)
|
137 |
-
|
138 |
-
|
139 |
-
}
|
140 |
}
|
141 |
|
142 |
$where_parts[] = '(' . $part . ')';
|
@@ -144,30 +169,30 @@ class P2P_Query {
|
|
144 |
|
145 |
if ( 1 == count( $where_parts ) )
|
146 |
$clauses['where'] .= " AND " . $where_parts[0];
|
147 |
-
|
148 |
$clauses['where'] .= " AND (" . implode( ' OR ', $where_parts ) . ")";
|
149 |
|
150 |
// Handle custom fields
|
151 |
-
if ( !empty( $
|
152 |
-
$meta_clauses = _p2p_meta_sql_helper( $
|
153 |
foreach ( $meta_clauses as $key => $value ) {
|
154 |
$clauses[ $key ] .= $value;
|
155 |
}
|
156 |
}
|
157 |
|
158 |
// Handle ordering
|
159 |
-
if ( $
|
160 |
$clauses['join'] .= $wpdb->prepare( "
|
161 |
LEFT JOIN $wpdb->p2pmeta AS p2pm_order ON (
|
162 |
$wpdb->p2p.p2p_id = p2pm_order.p2p_id AND p2pm_order.meta_key = %s
|
163 |
)
|
164 |
-
", $
|
165 |
|
166 |
-
$order = ( 'DESC' == strtoupper( $
|
167 |
|
168 |
$field = 'meta_value';
|
169 |
|
170 |
-
if ( $
|
171 |
$field .= '+0';
|
172 |
|
173 |
$clauses['orderby'] = "p2pm_order.$field $order";
|
@@ -175,30 +200,5 @@ class P2P_Query {
|
|
175 |
|
176 |
return $clauses;
|
177 |
}
|
178 |
-
|
179 |
-
private function find_direction( $ctype, $arg, $object_type ) {
|
180 |
-
$opposite_side = self::choose_side( $object_type,
|
181 |
-
$ctype->object['from'],
|
182 |
-
$ctype->object['to']
|
183 |
-
);
|
184 |
-
|
185 |
-
if ( in_array( $opposite_side, array( 'from', 'to' ) ) )
|
186 |
-
return $ctype->set_direction( $opposite_side );
|
187 |
-
|
188 |
-
return $ctype->find_direction( $arg );
|
189 |
-
}
|
190 |
-
|
191 |
-
private static function choose_side( $current, $from, $to ) {
|
192 |
-
if ( $from == $to && $current == $from )
|
193 |
-
return 'any';
|
194 |
-
|
195 |
-
if ( $current == $from )
|
196 |
-
return 'to';
|
197 |
-
|
198 |
-
if ( $current == $to )
|
199 |
-
return 'from';
|
200 |
-
|
201 |
-
return false;
|
202 |
-
}
|
203 |
}
|
204 |
|
2 |
|
3 |
class P2P_Query {
|
4 |
|
5 |
+
protected $ctypes, $items, $query, $meta;
|
6 |
+
protected $orderby, $order, $order_num;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Create instance from mixed query vars
|
10 |
+
*
|
11 |
+
* @param array Query vars to collect parameters from
|
12 |
+
* @return:
|
13 |
+
* - null means ignore current query
|
14 |
+
* - WP_Error instance if the query is invalid
|
15 |
+
* - P2P_Query instance on success
|
16 |
+
*/
|
17 |
+
public static function create_from_qv( &$q, $object_type ) {
|
18 |
+
$shortcuts = array(
|
19 |
'connected' => 'any',
|
20 |
'connected_to' => 'to',
|
21 |
'connected_from' => 'from',
|
22 |
);
|
23 |
|
24 |
+
foreach ( $shortcuts as $key => $direction ) {
|
25 |
if ( !empty( $q[ $key ] ) ) {
|
26 |
$q['connected_items'] = _p2p_pluck( $q, $key );
|
27 |
$q['connected_direction'] = $direction;
|
28 |
}
|
29 |
}
|
|
|
30 |
|
31 |
+
if ( !isset( $q['connected_type'] ) ) {
|
|
|
32 |
if ( isset( $q['connected_items'] ) ) {
|
33 |
+
return new WP_Error( 'no_connection_type', "Queries without 'connected_type' are no longer supported." );
|
34 |
}
|
|
|
|
|
|
|
|
|
35 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
return;
|
37 |
+
}
|
38 |
|
39 |
$ctypes = (array) _p2p_pluck( $q, 'connected_type' );
|
40 |
|
43 |
else
|
44 |
$directions = array();
|
45 |
|
46 |
+
$item = isset( $q['connected_items'] ) ? $q['connected_items'] : 'any';
|
47 |
+
|
48 |
$p2p_types = array();
|
49 |
|
50 |
foreach ( $ctypes as $i => $p2p_type ) {
|
56 |
if ( isset( $directions[$i] ) ) {
|
57 |
$directed = $ctype->set_direction( $directions[$i] );
|
58 |
} else {
|
59 |
+
$directed = $ctype->find_direction( $item, true, $object_type );
|
60 |
}
|
61 |
|
62 |
if ( !$directed )
|
63 |
continue;
|
64 |
|
65 |
+
$p2p_types[] = $directed;
|
66 |
}
|
67 |
|
68 |
if ( empty( $p2p_types ) )
|
69 |
+
return new WP_Error( 'no_direction', "Could not find direction(s)." );
|
70 |
|
71 |
+
if ( 1 == count( $p2p_types ) ) {
|
72 |
+
$directed = $p2p_types[0];
|
73 |
+
|
74 |
+
if ( $orderby_key = $directed->get_orderby_key() ) {
|
75 |
+
$q = wp_parse_args( $q, array(
|
76 |
+
'connected_orderby' => $orderby_key,
|
77 |
+
'connected_order' => 'ASC',
|
78 |
+
'connected_order_num' => true,
|
79 |
+
) );
|
80 |
+
}
|
81 |
+
|
82 |
+
$q = array_merge_recursive( $q, array(
|
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 |
+
}
|
90 |
+
|
91 |
+
$p2p_q = new P2P_Query;
|
92 |
+
|
93 |
+
$p2p_q->ctypes = $p2p_types;
|
94 |
+
$p2p_q->items = $item;
|
95 |
|
96 |
+
foreach ( array( 'meta', 'orderby', 'order_num', 'order' ) as $key ) {
|
97 |
+
$p2p_q->$key = isset( $q["connected_$key"] ) ? $q["connected_$key"] : false;
|
98 |
+
}
|
99 |
+
|
100 |
+
$p2p_q->query = isset( $q['connected_query'] ) ? $q['connected_query'] : array();
|
101 |
+
|
102 |
+
return $p2p_q;
|
103 |
+
}
|
104 |
+
|
105 |
+
protected function __construct() {}
|
106 |
+
|
107 |
+
public function __get( $key ) {
|
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
|
115 |
+
) );
|
116 |
+
|
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 |
+
/**
|
124 |
+
* For low-level query modifications
|
125 |
+
*/
|
126 |
+
public function alter_clauses( &$clauses, $main_id_column ) {
|
127 |
global $wpdb;
|
128 |
|
129 |
$clauses['fields'] .= ", $wpdb->p2p.*";
|
130 |
|
131 |
$clauses['join'] .= " INNER JOIN $wpdb->p2p";
|
132 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
133 |
$where_parts = array();
|
134 |
|
135 |
+
foreach ( $this->ctypes as $directed ) {
|
136 |
+
if ( null === $directed ) // used by migration script
|
137 |
+
continue;
|
138 |
+
|
139 |
+
$part = $wpdb->prepare( "$wpdb->p2p.p2p_type = %s", $directed->name );
|
140 |
|
141 |
$fields = array( 'p2p_from', 'p2p_to' );
|
142 |
|
143 |
+
switch ( $directed->get_direction() ) {
|
144 |
|
145 |
case 'from':
|
146 |
$fields = array_reverse( $fields );
|
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)";
|
|
|
155 |
|
156 |
break;
|
157 |
default:
|
158 |
+
$part .= sprintf ( " AND (
|
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 |
|
167 |
$where_parts[] = '(' . $part . ')';
|
169 |
|
170 |
if ( 1 == count( $where_parts ) )
|
171 |
$clauses['where'] .= " AND " . $where_parts[0];
|
172 |
+
elseif ( !empty( $where_parts ) )
|
173 |
$clauses['where'] .= " AND (" . implode( ' OR ', $where_parts ) . ")";
|
174 |
|
175 |
// Handle custom fields
|
176 |
+
if ( !empty( $this->meta ) ) {
|
177 |
+
$meta_clauses = _p2p_meta_sql_helper( $this->meta );
|
178 |
foreach ( $meta_clauses as $key => $value ) {
|
179 |
$clauses[ $key ] .= $value;
|
180 |
}
|
181 |
}
|
182 |
|
183 |
// Handle ordering
|
184 |
+
if ( $this->orderby ) {
|
185 |
$clauses['join'] .= $wpdb->prepare( "
|
186 |
LEFT JOIN $wpdb->p2pmeta AS p2pm_order ON (
|
187 |
$wpdb->p2p.p2p_id = p2pm_order.p2p_id AND p2pm_order.meta_key = %s
|
188 |
)
|
189 |
+
", $this->orderby );
|
190 |
|
191 |
+
$order = ( 'DESC' == strtoupper( $this->order ) ) ? 'DESC' : 'ASC';
|
192 |
|
193 |
$field = 'meta_value';
|
194 |
|
195 |
+
if ( $this->order_num )
|
196 |
$field .= '+0';
|
197 |
|
198 |
$clauses['orderby'] = "p2pm_order.$field $order";
|
200 |
|
201 |
return $clauses;
|
202 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
203 |
}
|
204 |
|
core/side.php
CHANGED
@@ -2,35 +2,59 @@
|
|
2 |
|
3 |
abstract class P2P_Side {
|
4 |
|
5 |
-
|
|
|
|
|
6 |
|
7 |
-
function
|
8 |
-
|
9 |
-
}
|
10 |
|
11 |
-
function get_base_qv( $q )
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
}
|
14 |
}
|
15 |
|
16 |
|
17 |
class P2P_Side_Post extends P2P_Side {
|
18 |
|
19 |
-
|
20 |
|
21 |
function __construct( $query_vars ) {
|
22 |
-
|
|
|
23 |
|
24 |
-
|
|
|
25 |
}
|
26 |
|
27 |
private function get_ptype() {
|
28 |
-
return get_post_type_object( $this->
|
29 |
}
|
30 |
|
31 |
function get_base_qv( $q ) {
|
32 |
if ( isset( $q['post_type'] ) && 'any' != $q['post_type'] ) {
|
33 |
-
$common = array_intersect( $this->post_type, (array) $q['post_type'] );
|
34 |
|
35 |
if ( !$common )
|
36 |
unset( $q['post_type'] );
|
@@ -43,7 +67,7 @@ class P2P_Side_Post extends P2P_Side {
|
|
43 |
}
|
44 |
|
45 |
function get_desc() {
|
46 |
-
return implode( ', ', array_map( array( $this, 'post_type_label' ), $this->post_type ) );
|
47 |
}
|
48 |
|
49 |
private function post_type_label( $post_type ) {
|
@@ -56,19 +80,39 @@ class P2P_Side_Post extends P2P_Side {
|
|
56 |
}
|
57 |
|
58 |
function get_labels() {
|
59 |
-
return $this->get_ptype()->labels;
|
60 |
}
|
61 |
|
62 |
-
function
|
63 |
return current_user_can( $this->get_ptype()->cap->edit_posts );
|
64 |
}
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
function do_query( $args ) {
|
67 |
return new WP_Query( $args );
|
68 |
}
|
69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
function translate_qv( $qv ) {
|
71 |
$map = array(
|
|
|
72 |
'exclude' => 'post__not_in',
|
73 |
'search' => 's',
|
74 |
'page' => 'paged',
|
@@ -82,43 +126,68 @@ class P2P_Side_Post extends P2P_Side {
|
|
82 |
return $qv;
|
83 |
}
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
function item_recognize( $arg ) {
|
86 |
-
|
87 |
-
|
|
|
|
|
88 |
return false;
|
89 |
-
|
90 |
-
|
91 |
-
$post_type = get_post_type( $post_id );
|
92 |
-
} else {
|
93 |
-
$post_type = $arg;
|
94 |
}
|
95 |
|
96 |
-
if (
|
|
|
|
|
|
|
|
|
97 |
return false;
|
98 |
|
99 |
-
return
|
100 |
}
|
101 |
|
102 |
-
function
|
103 |
$post = get_post( $arg );
|
104 |
-
if ( $post )
|
105 |
-
return $post->ID;
|
106 |
|
107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
108 |
}
|
109 |
|
110 |
-
function
|
111 |
-
|
|
|
|
|
|
|
112 |
}
|
113 |
}
|
114 |
|
115 |
|
116 |
class P2P_Side_Attachment extends P2P_Side_Post {
|
117 |
|
|
|
|
|
118 |
function __construct( $query_vars ) {
|
119 |
-
|
120 |
|
121 |
-
$this->post_type = array( 'attachment' );
|
|
|
|
|
|
|
|
|
122 |
}
|
123 |
|
124 |
function get_base_qv( $q ) {
|
@@ -131,6 +200,12 @@ class P2P_Side_Attachment extends P2P_Side_Post {
|
|
131 |
|
132 |
class P2P_Side_User extends P2P_Side {
|
133 |
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
function get_desc() {
|
135 |
return __( 'Users', P2P_TEXTDOMAIN );
|
136 |
}
|
@@ -140,22 +215,60 @@ class P2P_Side_User extends P2P_Side {
|
|
140 |
}
|
141 |
|
142 |
function get_labels() {
|
143 |
-
return
|
144 |
'singular_name' => __( 'User', P2P_TEXTDOMAIN ),
|
145 |
'search_items' => __( 'Search Users', P2P_TEXTDOMAIN ),
|
146 |
'not_found' => __( 'No users found.', P2P_TEXTDOMAIN ),
|
147 |
);
|
148 |
}
|
149 |
|
150 |
-
function
|
151 |
return current_user_can( 'list_users' );
|
152 |
}
|
153 |
|
|
|
|
|
|
|
|
|
154 |
function do_query( $args ) {
|
155 |
return new WP_User_Query( $args );
|
156 |
}
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
function translate_qv( $qv ) {
|
|
|
|
|
|
|
159 |
if ( isset( $qv['p2p:exclude'] ) )
|
160 |
$qv['exclude'] = _p2p_pluck( $qv, 'p2p:exclude' );
|
161 |
|
@@ -170,23 +283,19 @@ class P2P_Side_User extends P2P_Side {
|
|
170 |
return $qv;
|
171 |
}
|
172 |
|
173 |
-
function
|
174 |
-
return
|
175 |
}
|
176 |
|
177 |
-
function
|
178 |
-
|
179 |
-
return $arg->ID;
|
180 |
-
|
181 |
-
$user = get_user_by( 'id', $arg );
|
182 |
-
if ( $user )
|
183 |
-
return $user->ID;
|
184 |
-
|
185 |
-
return false;
|
186 |
}
|
187 |
|
188 |
-
function
|
189 |
-
|
|
|
|
|
|
|
190 |
}
|
191 |
}
|
192 |
|
2 |
|
3 |
abstract class P2P_Side {
|
4 |
|
5 |
+
abstract function get_title();
|
6 |
+
abstract function get_desc();
|
7 |
+
abstract function get_labels();
|
8 |
|
9 |
+
abstract function can_edit_connections();
|
10 |
+
abstract function can_create_item();
|
|
|
11 |
|
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 );
|
18 |
+
|
19 |
+
protected $item_type;
|
20 |
+
|
21 |
+
function item_recognize( $arg ) {
|
22 |
+
$class = $this->item_type;
|
23 |
+
|
24 |
+
if ( is_a( $arg, $class ) )
|
25 |
+
return $arg;
|
26 |
+
|
27 |
+
if ( is_a( $arg, 'P2P_Item' ) )
|
28 |
+
return false;
|
29 |
+
|
30 |
+
$raw_item = $this->recognize( $arg );
|
31 |
+
if ( !$raw_item )
|
32 |
+
return false;
|
33 |
+
|
34 |
+
return new $class( $raw_item );
|
35 |
}
|
36 |
}
|
37 |
|
38 |
|
39 |
class P2P_Side_Post extends P2P_Side {
|
40 |
|
41 |
+
protected $item_type = 'P2P_Item_Post';
|
42 |
|
43 |
function __construct( $query_vars ) {
|
44 |
+
$this->query_vars = $query_vars;
|
45 |
+
}
|
46 |
|
47 |
+
public function first_post_type() {
|
48 |
+
return $this->query_vars['post_type'][0];
|
49 |
}
|
50 |
|
51 |
private function get_ptype() {
|
52 |
+
return get_post_type_object( $this->first_post_type() );
|
53 |
}
|
54 |
|
55 |
function get_base_qv( $q ) {
|
56 |
if ( isset( $q['post_type'] ) && 'any' != $q['post_type'] ) {
|
57 |
+
$common = array_intersect( $this->query_vars['post_type'], (array) $q['post_type'] );
|
58 |
|
59 |
if ( !$common )
|
60 |
unset( $q['post_type'] );
|
67 |
}
|
68 |
|
69 |
function get_desc() {
|
70 |
+
return implode( ', ', array_map( array( $this, 'post_type_label' ), $this->query_vars['post_type'] ) );
|
71 |
}
|
72 |
|
73 |
private function post_type_label( $post_type ) {
|
80 |
}
|
81 |
|
82 |
function get_labels() {
|
83 |
+
return get_object_vars( $this->get_ptype()->labels );
|
84 |
}
|
85 |
|
86 |
+
function can_edit_connections() {
|
87 |
return current_user_can( $this->get_ptype()->cap->edit_posts );
|
88 |
}
|
89 |
|
90 |
+
function can_create_item() {
|
91 |
+
if ( count( $this->query_vars['post_type'] ) > 1 )
|
92 |
+
return false;
|
93 |
+
|
94 |
+
if ( count( $this->query_vars ) > 1 )
|
95 |
+
return false;
|
96 |
+
|
97 |
+
return true;
|
98 |
+
}
|
99 |
+
|
100 |
function do_query( $args ) {
|
101 |
return new WP_Query( $args );
|
102 |
}
|
103 |
|
104 |
+
function capture_query( $args ) {
|
105 |
+
$q = new WP_Query;
|
106 |
+
$q->_p2p_capture = true;
|
107 |
+
|
108 |
+
$q->query( $args );
|
109 |
+
|
110 |
+
return $q->_p2p_sql;
|
111 |
+
}
|
112 |
+
|
113 |
function translate_qv( $qv ) {
|
114 |
$map = array(
|
115 |
+
'include' => 'post__in',
|
116 |
'exclude' => 'post__not_in',
|
117 |
'search' => 's',
|
118 |
'page' => 'paged',
|
126 |
return $qv;
|
127 |
}
|
128 |
|
129 |
+
function is_indeterminate( $side ) {
|
130 |
+
$common = array_intersect(
|
131 |
+
$this->query_vars['post_type'],
|
132 |
+
$side->query_vars['post_type']
|
133 |
+
);
|
134 |
+
|
135 |
+
return !empty( $common );
|
136 |
+
}
|
137 |
+
|
138 |
function item_recognize( $arg ) {
|
139 |
+
$class = $this->item_type;
|
140 |
+
|
141 |
+
if ( is_a( $arg, $class ) ) {
|
142 |
+
if ( !$this->recognize_post_type( $arg->post_type ) )
|
143 |
return false;
|
144 |
+
|
145 |
+
return $arg;
|
|
|
|
|
|
|
146 |
}
|
147 |
|
148 |
+
if ( is_a( $arg, 'P2P_Item' ) )
|
149 |
+
return false;
|
150 |
+
|
151 |
+
$raw_item = $this->recognize( $arg );
|
152 |
+
if ( !$raw_item )
|
153 |
return false;
|
154 |
|
155 |
+
return new $class( $raw_item );
|
156 |
}
|
157 |
|
158 |
+
protected function recognize( $arg ) {
|
159 |
$post = get_post( $arg );
|
|
|
|
|
160 |
|
161 |
+
if ( !is_object( $post ) )
|
162 |
+
return false;
|
163 |
+
|
164 |
+
if ( !$this->recognize_post_type( $post->post_type ) )
|
165 |
+
return false;
|
166 |
+
|
167 |
+
return $post;
|
168 |
}
|
169 |
|
170 |
+
public function recognize_post_type( $post_type ) {
|
171 |
+
if ( !post_type_exists( $post_type ) )
|
172 |
+
return false;
|
173 |
+
|
174 |
+
return in_array( $post_type, $this->query_vars['post_type'] );
|
175 |
}
|
176 |
}
|
177 |
|
178 |
|
179 |
class P2P_Side_Attachment extends P2P_Side_Post {
|
180 |
|
181 |
+
protected $item_type = 'P2P_Item_Attachment';
|
182 |
+
|
183 |
function __construct( $query_vars ) {
|
184 |
+
$this->query_vars = $query_vars;
|
185 |
|
186 |
+
$this->query_vars['post_type'] = array( 'attachment' );
|
187 |
+
}
|
188 |
+
|
189 |
+
function can_create_item() {
|
190 |
+
return false;
|
191 |
}
|
192 |
|
193 |
function get_base_qv( $q ) {
|
200 |
|
201 |
class P2P_Side_User extends P2P_Side {
|
202 |
|
203 |
+
protected $item_type = 'P2P_Item_User';
|
204 |
+
|
205 |
+
function __construct( $query_vars ) {
|
206 |
+
$this->query_vars = $query_vars;
|
207 |
+
}
|
208 |
+
|
209 |
function get_desc() {
|
210 |
return __( 'Users', P2P_TEXTDOMAIN );
|
211 |
}
|
215 |
}
|
216 |
|
217 |
function get_labels() {
|
218 |
+
return array(
|
219 |
'singular_name' => __( 'User', P2P_TEXTDOMAIN ),
|
220 |
'search_items' => __( 'Search Users', P2P_TEXTDOMAIN ),
|
221 |
'not_found' => __( 'No users found.', P2P_TEXTDOMAIN ),
|
222 |
);
|
223 |
}
|
224 |
|
225 |
+
function can_edit_connections() {
|
226 |
return current_user_can( 'list_users' );
|
227 |
}
|
228 |
|
229 |
+
function can_create_item() {
|
230 |
+
return false;
|
231 |
+
}
|
232 |
+
|
233 |
function do_query( $args ) {
|
234 |
return new WP_User_Query( $args );
|
235 |
}
|
236 |
|
237 |
+
function capture_query( $args ) {
|
238 |
+
$args['count_total'] = false;
|
239 |
+
|
240 |
+
$uq = new WP_User_Query;
|
241 |
+
$uq->_p2p_capture = true; // needed by P2P_URL_Query
|
242 |
+
|
243 |
+
// see http://core.trac.wordpress.org/ticket/21119
|
244 |
+
$uq->query_vars = wp_parse_args( $args, array(
|
245 |
+
'blog_id' => $GLOBALS['blog_id'],
|
246 |
+
'role' => '',
|
247 |
+
'meta_key' => '',
|
248 |
+
'meta_value' => '',
|
249 |
+
'meta_compare' => '',
|
250 |
+
'include' => array(),
|
251 |
+
'exclude' => array(),
|
252 |
+
'search' => '',
|
253 |
+
'search_columns' => array(),
|
254 |
+
'orderby' => 'login',
|
255 |
+
'order' => 'ASC',
|
256 |
+
'offset' => '',
|
257 |
+
'number' => '',
|
258 |
+
'count_total' => true,
|
259 |
+
'fields' => 'all',
|
260 |
+
'who' => ''
|
261 |
+
) );
|
262 |
+
|
263 |
+
$uq->prepare_query();
|
264 |
+
|
265 |
+
return "SELECT $uq->query_fields $uq->query_from $uq->query_where $uq->query_orderby $uq->query_limit";
|
266 |
+
}
|
267 |
+
|
268 |
function translate_qv( $qv ) {
|
269 |
+
if ( isset( $qv['p2p:include'] ) )
|
270 |
+
$qv['include'] = _p2p_pluck( $qv, 'p2p:include' );
|
271 |
+
|
272 |
if ( isset( $qv['p2p:exclude'] ) )
|
273 |
$qv['exclude'] = _p2p_pluck( $qv, 'p2p:exclude' );
|
274 |
|
283 |
return $qv;
|
284 |
}
|
285 |
|
286 |
+
function is_indeterminate( $side ) {
|
287 |
+
return true;
|
288 |
}
|
289 |
|
290 |
+
function get_base_qv( $q ) {
|
291 |
+
return array_merge( $this->query_vars, $q );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
292 |
}
|
293 |
|
294 |
+
protected function recognize( $arg ) {
|
295 |
+
if ( is_a( $arg, 'WP_User' ) )
|
296 |
+
return $arg;
|
297 |
+
|
298 |
+
return get_user_by( 'id', $arg );
|
299 |
}
|
300 |
}
|
301 |
|
core/storage.php
CHANGED
@@ -38,36 +38,6 @@ class P2P_Storage {
|
|
38 |
" );
|
39 |
}
|
40 |
|
41 |
-
static function upgrade() {
|
42 |
-
global $wpdb;
|
43 |
-
|
44 |
-
$n = 0;
|
45 |
-
|
46 |
-
foreach ( P2P_Connection_Type_Factory::get_all_instances() as $p2p_type => $ctype ) {
|
47 |
-
if ( ! $ctype instanceof P2P_Connection_Type )
|
48 |
-
continue;
|
49 |
-
|
50 |
-
$args = $ctype->set_direction( 'any' )->get_connected_args( array(
|
51 |
-
'connected_items' => 'any',
|
52 |
-
'cache_results' => false,
|
53 |
-
'post_status' => 'any',
|
54 |
-
'nopaging' => true
|
55 |
-
) );
|
56 |
-
|
57 |
-
$args['p2p_type'] = array( 0 => 'any' );
|
58 |
-
|
59 |
-
foreach ( get_posts( $args ) as $post ) {
|
60 |
-
// some connections might be ambiguous, spanning multiple connection types; first one wins
|
61 |
-
if ( $post->p2p_type )
|
62 |
-
continue;
|
63 |
-
|
64 |
-
$n += $wpdb->update( $wpdb->p2p, compact( 'p2p_type' ), array( 'p2p_id' => $post->p2p_id ) );
|
65 |
-
}
|
66 |
-
}
|
67 |
-
|
68 |
-
return $n;
|
69 |
-
}
|
70 |
-
|
71 |
static function uninstall() {
|
72 |
scb_uninstall_table( 'p2p' );
|
73 |
scb_uninstall_table( 'p2pmeta' );
|
38 |
" );
|
39 |
}
|
40 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
static function uninstall() {
|
42 |
scb_uninstall_table( 'p2p' );
|
43 |
scb_uninstall_table( 'p2pmeta' );
|
core/type.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
class P2P_Connection_Type {
|
4 |
|
5 |
-
public $indeterminate
|
6 |
|
7 |
public $object;
|
8 |
|
@@ -24,12 +24,7 @@ class P2P_Connection_Type {
|
|
24 |
}
|
25 |
|
26 |
if ( $this->object['from'] == $this->object['to'] ) {
|
27 |
-
|
28 |
-
$common = array_intersect( $this->side['from']->post_type, $this->side['to']->post_type );
|
29 |
-
|
30 |
-
if ( !empty( $common ) )
|
31 |
-
$this->indeterminate = true;
|
32 |
-
}
|
33 |
} else {
|
34 |
$args['self_connections'] = true;
|
35 |
}
|
@@ -80,14 +75,12 @@ class P2P_Connection_Type {
|
|
80 |
|
81 |
private function set_labels( &$args ) {
|
82 |
foreach ( array( 'from', 'to' ) as $key ) {
|
83 |
-
$labels =
|
|
|
84 |
|
85 |
-
|
86 |
-
$labels = $this->side[ $key ]->get_labels();
|
87 |
-
else
|
88 |
-
$labels = (object) $labels;
|
89 |
|
90 |
-
$this->labels[ $key ] = $labels;
|
91 |
}
|
92 |
}
|
93 |
|
@@ -115,6 +108,12 @@ class P2P_Connection_Type {
|
|
115 |
}
|
116 |
|
117 |
public function __call( $method, $args ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
$directed = $this->find_direction( $args[0] );
|
119 |
if ( !$directed ) {
|
120 |
trigger_error( sprintf( "Can't determine direction for '%s' type.", $this->name ), E_USER_WARNING );
|
@@ -146,48 +145,91 @@ class P2P_Connection_Type {
|
|
146 |
*
|
147 |
* @param mixed A post type, object or object id.
|
148 |
* @param bool Whether to return an instance of P2P_Directed_Connection_Type or just the direction
|
|
|
149 |
*
|
150 |
* @return bool|object|string False on failure, P2P_Directed_Connection_Type instance or direction on success.
|
151 |
*/
|
152 |
-
public function find_direction( $arg, $instantiate = true ) {
|
153 |
if ( is_array( $arg ) )
|
154 |
$arg = reset( $arg );
|
155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
156 |
foreach ( array( 'from', 'to' ) as $direction ) {
|
157 |
-
|
|
|
|
|
158 |
continue;
|
159 |
|
160 |
if ( $this->indeterminate )
|
161 |
$direction = $this->reciprocal ? 'any' : 'from';
|
162 |
|
163 |
-
return $
|
164 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
165 |
|
166 |
return false;
|
167 |
}
|
168 |
|
169 |
-
|
170 |
-
private function find_direction_multiple( $post_types ) {
|
171 |
-
$possible_directions = array();
|
172 |
-
|
173 |
foreach ( array( 'from', 'to' ) as $direction ) {
|
174 |
-
if (
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
}
|
182 |
}
|
183 |
|
184 |
-
|
|
|
|
|
|
|
|
|
185 |
return false;
|
186 |
|
187 |
-
|
188 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
189 |
|
190 |
-
return
|
191 |
}
|
192 |
|
193 |
/** Alias for get_prev() */
|
@@ -277,12 +319,10 @@ class P2P_Connection_Type {
|
|
277 |
$post_types = array_unique( wp_list_pluck( $items, 'post_type' ) );
|
278 |
|
279 |
if ( count( $post_types ) > 1 ) {
|
280 |
-
$direction = $this->find_direction_multiple( $post_types );
|
281 |
$extra_qv['post_type'] = 'any';
|
282 |
-
} else {
|
283 |
-
$direction = $this->find_direction( $post_types[0], false );
|
284 |
}
|
285 |
|
|
|
286 |
if ( !$direction )
|
287 |
return false;
|
288 |
|
@@ -301,6 +341,24 @@ class P2P_Connection_Type {
|
|
301 |
p2p_distribute_connected( $items, $q->items, $prop_name );
|
302 |
}
|
303 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
public function get_desc() {
|
305 |
foreach ( array( 'from', 'to' ) as $key ) {
|
306 |
$$key = $this->side[ $key ]->get_desc();
|
2 |
|
3 |
class P2P_Connection_Type {
|
4 |
|
5 |
+
public $indeterminate;
|
6 |
|
7 |
public $object;
|
8 |
|
24 |
}
|
25 |
|
26 |
if ( $this->object['from'] == $this->object['to'] ) {
|
27 |
+
$this->indeterminate = $this->side['from']->is_indeterminate( $this->side['to'] );
|
|
|
|
|
|
|
|
|
|
|
28 |
} else {
|
29 |
$args['self_connections'] = true;
|
30 |
}
|
75 |
|
76 |
private function set_labels( &$args ) {
|
77 |
foreach ( array( 'from', 'to' ) as $key ) {
|
78 |
+
$labels = $this->side[ $key ]->get_labels();
|
79 |
+
$labels['create'] = __( 'Create connections', P2P_TEXTDOMAIN );
|
80 |
|
81 |
+
_p2p_append( $labels, (array) _p2p_pluck( $args, $key . '_labels' ) );
|
|
|
|
|
|
|
82 |
|
83 |
+
$this->labels[ $key ] = (object) $labels;
|
84 |
}
|
85 |
}
|
86 |
|
108 |
}
|
109 |
|
110 |
public function __call( $method, $args ) {
|
111 |
+
if ( ! method_exists( 'P2P_Directed_Connection_Type', $method ) ) {
|
112 |
+
trigger_error( "Method '$method' does not exist.", E_USER_ERROR );
|
113 |
+
return;
|
114 |
+
}
|
115 |
+
|
116 |
+
// TODO: make find_direction() return the normalized item and pass that along
|
117 |
$directed = $this->find_direction( $args[0] );
|
118 |
if ( !$directed ) {
|
119 |
trigger_error( sprintf( "Can't determine direction for '%s' type.", $this->name ), E_USER_WARNING );
|
145 |
*
|
146 |
* @param mixed A post type, object or object id.
|
147 |
* @param bool Whether to return an instance of P2P_Directed_Connection_Type or just the direction
|
148 |
+
* @param string An object type, such as 'post' or 'user'
|
149 |
*
|
150 |
* @return bool|object|string False on failure, P2P_Directed_Connection_Type instance or direction on success.
|
151 |
*/
|
152 |
+
public function find_direction( $arg, $instantiate = true, $object_type = null ) {
|
153 |
if ( is_array( $arg ) )
|
154 |
$arg = reset( $arg );
|
155 |
|
156 |
+
if ( $object_type ) {
|
157 |
+
$direction = $this->direction_from_object_type( $object_type );
|
158 |
+
if ( !$direction )
|
159 |
+
return false;
|
160 |
+
|
161 |
+
if ( in_array( $direction, array( 'from', 'to' ) ) )
|
162 |
+
return $this->set_direction( $direction, $instantiate );
|
163 |
+
}
|
164 |
+
|
165 |
+
$direction = $this->direction_from_item( $arg );
|
166 |
+
|
167 |
+
if ( $direction )
|
168 |
+
return $this->set_direction( $direction, $instantiate );
|
169 |
+
|
170 |
+
return false;
|
171 |
+
}
|
172 |
+
|
173 |
+
public function direction_from_item( $arg ) {
|
174 |
foreach ( array( 'from', 'to' ) as $direction ) {
|
175 |
+
$item = $this->side[ $direction ]->item_recognize( $arg );
|
176 |
+
|
177 |
+
if ( !$item )
|
178 |
continue;
|
179 |
|
180 |
if ( $this->indeterminate )
|
181 |
$direction = $this->reciprocal ? 'any' : 'from';
|
182 |
|
183 |
+
return $direction;
|
184 |
}
|
185 |
+
}
|
186 |
+
|
187 |
+
public function direction_from_object_type( $current ) {
|
188 |
+
$from = $this->object['from'];
|
189 |
+
$to = $this->object['to'];
|
190 |
+
|
191 |
+
if ( $from == $to && $current == $from )
|
192 |
+
return 'any';
|
193 |
+
|
194 |
+
if ( $current == $from )
|
195 |
+
return 'to';
|
196 |
+
|
197 |
+
if ( $current == $to )
|
198 |
+
return 'from';
|
199 |
|
200 |
return false;
|
201 |
}
|
202 |
|
203 |
+
public function direction_from_types( $object_type, $post_types = null ) {
|
|
|
|
|
|
|
204 |
foreach ( array( 'from', 'to' ) as $direction ) {
|
205 |
+
if ( !$this->_type_check( $direction, $object_type, $post_types ) )
|
206 |
+
continue;
|
207 |
+
|
208 |
+
if ( $this->indeterminate )
|
209 |
+
$direction = $this->reciprocal ? 'any' : 'from';
|
210 |
+
|
211 |
+
return $direction;
|
|
|
212 |
}
|
213 |
|
214 |
+
return false;
|
215 |
+
}
|
216 |
+
|
217 |
+
private function _type_check( $direction, $object_type, $post_types ) {
|
218 |
+
if ( $object_type != $this->object[ $direction ] )
|
219 |
return false;
|
220 |
|
221 |
+
$side = $this->side[ $direction ];
|
222 |
+
|
223 |
+
if ( !method_exists( $side, 'recognize_post_type' ) )
|
224 |
+
return true;
|
225 |
+
|
226 |
+
foreach ( (array) $post_types as $post_type ) {
|
227 |
+
if ( $side->recognize_post_type( $post_type ) ) {
|
228 |
+
return true;
|
229 |
+
}
|
230 |
+
}
|
231 |
|
232 |
+
return false;
|
233 |
}
|
234 |
|
235 |
/** Alias for get_prev() */
|
319 |
$post_types = array_unique( wp_list_pluck( $items, 'post_type' ) );
|
320 |
|
321 |
if ( count( $post_types ) > 1 ) {
|
|
|
322 |
$extra_qv['post_type'] = 'any';
|
|
|
|
|
323 |
}
|
324 |
|
325 |
+
$direction = $this->find_direction_multiple( $post_types );
|
326 |
if ( !$direction )
|
327 |
return false;
|
328 |
|
341 |
p2p_distribute_connected( $items, $q->items, $prop_name );
|
342 |
}
|
343 |
|
344 |
+
// Used in each_connected()
|
345 |
+
private function find_direction_multiple( $post_types ) {
|
346 |
+
$possible_directions = array();
|
347 |
+
|
348 |
+
foreach ( array( 'from', 'to' ) as $direction ) {
|
349 |
+
if ( 'post' == $this->object[$direction] ) {
|
350 |
+
foreach ( $post_types as $post_type ) {
|
351 |
+
if ( !$this->side[ $direction ]->item_recognize( $post_type ) ) {
|
352 |
+
$possible_directions[] = $direction;
|
353 |
+
break;
|
354 |
+
}
|
355 |
+
}
|
356 |
+
}
|
357 |
+
}
|
358 |
+
|
359 |
+
return _p2p_compress_direction( $possible_directions );
|
360 |
+
}
|
361 |
+
|
362 |
public function get_desc() {
|
363 |
foreach ( array( 'from', 'to' ) as $key ) {
|
364 |
$$key = $this->side[ $key ]->get_desc();
|
core/url-query.php
CHANGED
@@ -2,16 +2,41 @@
|
|
2 |
|
3 |
class P2P_URL_Query {
|
4 |
|
5 |
-
function
|
|
|
|
|
|
|
|
|
6 |
add_filter( 'query_vars', array( __CLASS__, 'query_vars' ) );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
}
|
8 |
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
15 |
}
|
16 |
}
|
17 |
|
2 |
|
3 |
class P2P_URL_Query {
|
4 |
|
5 |
+
static function get_custom_qv() {
|
6 |
+
return array( 'connected_type', 'connected_items', 'connected_direction' );
|
7 |
+
}
|
8 |
+
|
9 |
+
static function init() {
|
10 |
add_filter( 'query_vars', array( __CLASS__, 'query_vars' ) );
|
11 |
+
|
12 |
+
if ( is_admin() )
|
13 |
+
add_action( 'pre_user_query', array( __CLASS__, 'user_query' ), 9 );
|
14 |
+
}
|
15 |
+
|
16 |
+
// Make the query vars public
|
17 |
+
static function query_vars( $public_qv ) {
|
18 |
+
return array_merge( $public_qv, self::get_custom_qv() );
|
19 |
}
|
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 |
+
|
34 |
+
// Don't overwrite existing P2P query
|
35 |
+
if ( isset( $query->query_vars['connected_type'] ) )
|
36 |
+
return;
|
37 |
+
|
38 |
+
_p2p_append( $query->query_vars, wp_array_slice_assoc( $_GET,
|
39 |
+
P2P_URL_Query::get_custom_qv() ) );
|
40 |
}
|
41 |
}
|
42 |
|
core/util.php
CHANGED
@@ -8,13 +8,48 @@ function _p2p_expand_direction( $direction ) {
|
|
8 |
return array( $direction );
|
9 |
}
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
/** @internal */
|
12 |
function _p2p_normalize( $items ) {
|
13 |
if ( !is_array( $items ) )
|
14 |
$items = array( $items );
|
15 |
|
16 |
-
|
17 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
return $items;
|
20 |
}
|
8 |
return array( $direction );
|
9 |
}
|
10 |
|
11 |
+
/** @internal */
|
12 |
+
function _p2p_compress_direction( $directions ) {
|
13 |
+
if ( empty( $directions ) )
|
14 |
+
return false;
|
15 |
+
|
16 |
+
if ( count( $directions ) > 1 )
|
17 |
+
return 'any';
|
18 |
+
|
19 |
+
return reset( $directions );
|
20 |
+
}
|
21 |
+
|
22 |
+
/** @internal */
|
23 |
+
function _p2p_flip_direction( $direction ) {
|
24 |
+
$map = array(
|
25 |
+
'from' => 'to',
|
26 |
+
'to' => 'from',
|
27 |
+
'any' => 'any',
|
28 |
+
);
|
29 |
+
|
30 |
+
return $map[ $direction ];
|
31 |
+
}
|
32 |
+
|
33 |
/** @internal */
|
34 |
function _p2p_normalize( $items ) {
|
35 |
if ( !is_array( $items ) )
|
36 |
$items = array( $items );
|
37 |
|
38 |
+
foreach ( $items as &$item ) {
|
39 |
+
if ( is_a( $item, 'P2P_Item' ) )
|
40 |
+
$item = $item->get_id();
|
41 |
+
elseif ( is_object( $item ) )
|
42 |
+
$item = $item->ID;
|
43 |
+
}
|
44 |
+
|
45 |
+
return $items;
|
46 |
+
}
|
47 |
+
|
48 |
+
/** @internal */
|
49 |
+
function _p2p_wrap( $items, $class ) {
|
50 |
+
foreach ( $items as &$item ) {
|
51 |
+
$item = new $class( $item );
|
52 |
+
}
|
53 |
|
54 |
return $items;
|
55 |
}
|
lang/posts-to-posts-it_IT.mo
ADDED
Binary file
|
lang/posts-to-posts-it_IT.po
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# Copyright (C) 2011
|
2 |
+
# This file is distributed under the same license as the package.
|
3 |
+
msgid ""
|
4 |
+
msgstr ""
|
5 |
+
"Project-Id-Version: Posts 2 Posts 1.1.4\n"
|
6 |
+
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
7 |
+
"POT-Creation-Date: 2011-12-01 16:28:04+00:00\n"
|
8 |
+
"MIME-Version: 1.0\n"
|
9 |
+
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
+
"Content-Transfer-Encoding: 8bit\n"
|
11 |
+
"PO-Revision-Date: 2012-06-21 22:25+0200\n"
|
12 |
+
"Last-Translator: Andrea Bersi\n"
|
13 |
+
"Language-Team: \n"
|
14 |
+
"X-Poedit-Language: Italian\n"
|
15 |
+
"X-Poedit-Country: ITALY\n"
|
16 |
+
|
17 |
+
#: admin/box-factory.php:56
|
18 |
+
msgid " (from)"
|
19 |
+
msgstr " (da)"
|
20 |
+
|
21 |
+
#: admin/box-factory.php:57
|
22 |
+
msgid " (to)"
|
23 |
+
msgstr " (a)"
|
24 |
+
|
25 |
+
#: admin/box.php:42
|
26 |
+
msgid "Are you sure you want to delete all connections?"
|
27 |
+
msgstr "Confermi la rimozione di tutte le relazioni?"
|
28 |
+
|
29 |
+
#: admin/box.php:115
|
30 |
+
msgid "Create connections:"
|
31 |
+
msgstr "Crea relazioni:"
|
32 |
+
|
33 |
+
#: admin/box.php:128
|
34 |
+
msgid "Search"
|
35 |
+
msgstr "Cerca"
|
36 |
+
|
37 |
+
#: admin/box.php:136
|
38 |
+
msgid "View All"
|
39 |
+
msgstr "Vedi tutti"
|
40 |
+
|
41 |
+
#: admin/box.php:204
|
42 |
+
msgid "previous"
|
43 |
+
msgstr "precedente"
|
44 |
+
|
45 |
+
#: admin/box.php:205
|
46 |
+
msgid "next"
|
47 |
+
msgstr "successivo"
|
48 |
+
|
49 |
+
#: admin/box.php:206
|
50 |
+
msgid "of"
|
51 |
+
msgstr "di"
|
52 |
+
|
53 |
+
#: admin/fields.php:16
|
54 |
+
msgid "Create connection"
|
55 |
+
msgstr "Crea relazione"
|
56 |
+
|
57 |
+
#: admin/fields.php:30
|
58 |
+
msgid "Delete all connections"
|
59 |
+
msgstr "Cancella tutte le relazioni"
|
60 |
+
|
61 |
+
#: admin/fields.php:39
|
62 |
+
msgid "Delete connection"
|
63 |
+
msgstr "Cancella relazione"
|
64 |
+
|
65 |
+
#: scb/AdminPage.php:165
|
66 |
+
msgid "Settings <strong>saved</strong>."
|
67 |
+
msgstr "Impostazioni <strong>salvate</strong>"
|
68 |
+
|
69 |
+
#: scb/AdminPage.php:178
|
70 |
+
#: scb/AdminPage.php:189
|
71 |
+
msgid "Save Changes"
|
72 |
+
msgstr "Salva"
|
73 |
+
|
74 |
+
#: scb/AdminPage.php:350
|
75 |
+
msgid "Settings"
|
76 |
+
msgstr "Impostazioni"
|
77 |
+
|
78 |
+
#: core/type.php:65
|
79 |
+
msgid "Connected %s"
|
80 |
+
msgstr "Collegato %s"
|
81 |
+
|
82 |
+
#: core/widget.php:15
|
83 |
+
msgid "Posts 2 Posts"
|
84 |
+
msgstr "Posts 2 Posts"
|
85 |
+
|
86 |
+
#: core/widget.php:16
|
87 |
+
msgid "A list of posts connected to the current post"
|
88 |
+
msgstr "Elenco dei contenuti collegati"
|
89 |
+
|
90 |
+
#: core/widget.php:37
|
91 |
+
msgid "Connection type:"
|
92 |
+
msgstr "Tipo relazione:"
|
93 |
+
|
94 |
+
#: core/widget.php:41
|
95 |
+
msgid "Connection listing:"
|
96 |
+
msgstr "Elenco relazioni:"
|
97 |
+
|
98 |
+
#: core/widget.php:47
|
99 |
+
msgid "connected"
|
100 |
+
msgstr "connesso"
|
101 |
+
|
102 |
+
#: core/widget.php:48
|
103 |
+
msgid "related"
|
104 |
+
msgstr "in relazione"
|
105 |
+
|
106 |
+
#: core/widget.php:73
|
107 |
+
msgid "Related %s"
|
108 |
+
msgstr "In relazione %s"
|
109 |
+
|
110 |
+
#: core/storage.php:35
|
111 |
+
msgid "Upgraded %d connections."
|
112 |
+
msgstr "Aggiornato %d relazioni"
|
113 |
+
|
114 |
+
#: core/storage.php:38
|
115 |
+
msgid "The Posts 2 Posts connections need to be upgraded. <a href=\"%s\">Proceed.</a>"
|
116 |
+
msgstr "Posts 2 Posts ha un Upgrade. <a href=\"%s\">Procedi.</a>"
|
117 |
+
|
118 |
+
#: core/side.php:110
|
119 |
+
msgid "Users"
|
120 |
+
msgstr "Utenti"
|
121 |
+
|
122 |
+
#: core/side.php:115
|
123 |
+
msgid "User"
|
124 |
+
msgstr "Utente"
|
125 |
+
|
126 |
+
#: core/side.php:116
|
127 |
+
msgid "Search Users"
|
128 |
+
msgstr "Cerca utenti"
|
129 |
+
|
130 |
+
#: core/side.php:117
|
131 |
+
msgid "No users found."
|
132 |
+
msgstr "Nessun utente trovato."
|
133 |
+
|
lang/posts-to-posts-ro_RO.mo
CHANGED
Binary file
|
lang/posts-to-posts-ro_RO.po
CHANGED
@@ -7,8 +7,8 @@ msgid ""
|
|
7 |
msgstr ""
|
8 |
"Project-Id-Version: Posts 2 Posts\n"
|
9 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
10 |
-
"POT-Creation-Date: 2012-
|
11 |
-
"PO-Revision-Date: 2012-
|
12 |
"Last-Translator: scribu <mail@scribu.net>\n"
|
13 |
"Language-Team: ROMANIAN <LL@li.org>\n"
|
14 |
"Language: \n"
|
@@ -16,55 +16,43 @@ msgstr ""
|
|
16 |
"Content-Type: text/plain; charset=UTF-8\n"
|
17 |
"Content-Transfer-Encoding: 8bit\n"
|
18 |
|
19 |
-
#: admin/box
|
20 |
-
msgid " (from)"
|
21 |
-
msgstr "(de la)"
|
22 |
-
|
23 |
-
#: admin/box-factory.php:76
|
24 |
-
msgid " (to)"
|
25 |
-
msgstr "(la)"
|
26 |
-
|
27 |
-
#: admin/box.php:40
|
28 |
msgid "Are you sure you want to delete all connections?"
|
29 |
msgstr "Sigur vreți să ștergeți toate conexiunile?"
|
30 |
|
31 |
-
#: admin/box.php:
|
32 |
-
msgid "Create connections:"
|
33 |
-
msgstr "Creează conexiuni:"
|
34 |
-
|
35 |
-
#: admin/box.php:138
|
36 |
-
msgid "View All"
|
37 |
-
msgstr "Vezi toate"
|
38 |
-
|
39 |
-
#: admin/box.php:143
|
40 |
msgid "Search"
|
41 |
msgstr "Căutare"
|
42 |
|
43 |
-
#: admin/box.php:
|
44 |
msgid "previous"
|
45 |
msgstr "anterioare"
|
46 |
|
47 |
-
#: admin/box.php:
|
48 |
msgid "next"
|
49 |
msgstr "următoare"
|
50 |
|
51 |
-
#: admin/box.php:
|
52 |
msgid "of"
|
53 |
msgstr "din"
|
54 |
|
55 |
-
#: admin/box.php:
|
56 |
msgid "Can't create connection: %s"
|
57 |
msgstr "Conexiunea nu poate fi creată: %s"
|
58 |
|
59 |
-
#: admin/
|
60 |
-
msgid "
|
61 |
-
msgstr "
|
|
|
|
|
|
|
|
|
62 |
|
63 |
-
#: admin/fields.php:
|
64 |
msgid "Delete all connections"
|
65 |
msgstr "Șterge toate conexiunile"
|
66 |
|
67 |
-
#: admin/fields.php:
|
68 |
msgid "Delete connection"
|
69 |
msgstr "Șterge conexiune"
|
70 |
|
@@ -72,35 +60,35 @@ msgstr "Șterge conexiune"
|
|
72 |
msgid "Connection Types"
|
73 |
msgstr "Tipuri de conexiuni"
|
74 |
|
75 |
-
#: admin/tools.php:
|
76 |
-
msgid "Upgraded %d connections."
|
77 |
-
msgstr "Am actualizat %d conexiuni."
|
78 |
-
|
79 |
-
#: admin/tools.php:34
|
80 |
-
msgid "The Posts 2 Posts connections need to be upgraded. <a href=\"%s\">Proceed.</a>"
|
81 |
-
msgstr "Conexiunile Posts 2 Posts trebuie actualizate. <a href=\"%s\">Pornește.</a>"
|
82 |
-
|
83 |
-
#: admin/tools.php:54
|
84 |
msgid "<em>%s</em> is not a registered connection type."
|
85 |
msgstr "<em>%s</em> nu e un tip de conexiune înregistrat."
|
86 |
|
87 |
-
#: admin/tools.php:
|
88 |
msgid "Converted %1$s connections from <em>%2$s</em> to <em>%3$s</em>."
|
89 |
msgstr "Am convertit %1$s conexiuni din <em>%2$s</em> în <em>%3$s</em>."
|
90 |
|
91 |
-
#: admin/tools.php:
|
92 |
msgid "Name"
|
93 |
msgstr "Nume"
|
94 |
|
95 |
-
#: admin/tools.php:
|
96 |
msgid "Information"
|
97 |
msgstr "Informații"
|
98 |
|
99 |
-
#: admin/tools.php:
|
100 |
msgid "Connections"
|
101 |
msgstr "Conexiuni"
|
102 |
|
103 |
-
#: admin/tools.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
msgid "Convert to registered connection type:"
|
105 |
msgstr "Convertește într-un tip de conexiune înregistrat:"
|
106 |
|
@@ -116,43 +104,47 @@ msgstr "Posts 2 Posts"
|
|
116 |
msgid "A list of posts connected to the current post"
|
117 |
msgstr "O lista de postări conectate la postarea curentă"
|
118 |
|
119 |
-
#: core/extra.php:
|
120 |
msgid "Title:"
|
121 |
msgstr "Titlu:"
|
122 |
|
123 |
-
#: core/extra.php:
|
124 |
msgid "Connection type:"
|
125 |
msgstr "Tipul conexiunii:"
|
126 |
|
127 |
-
#: core/extra.php:
|
128 |
msgid "Connection listing:"
|
129 |
msgstr "Conexiuni de listat:"
|
130 |
|
131 |
-
#: core/extra.php:
|
132 |
msgid "connected"
|
133 |
msgstr "conectate"
|
134 |
|
135 |
-
#: core/extra.php:
|
136 |
msgid "related"
|
137 |
msgstr "înrudite"
|
138 |
|
139 |
-
#: core/side.php:
|
140 |
msgid "Users"
|
141 |
msgstr "Utilizatori"
|
142 |
|
143 |
-
#: core/side.php:
|
144 |
msgid "User"
|
145 |
msgstr "Utilizator"
|
146 |
|
147 |
-
#: core/side.php:
|
148 |
msgid "Search Users"
|
149 |
msgstr "Caută utilizatori"
|
150 |
|
151 |
-
#: core/side.php:
|
152 |
msgid "No users found."
|
153 |
msgstr "Niciun utilizator găsit."
|
154 |
|
155 |
-
#: core/type.php:
|
|
|
|
|
|
|
|
|
156 |
msgid "Connected %s"
|
157 |
msgstr "%s conectate"
|
158 |
|
@@ -165,10 +157,26 @@ msgstr "Setări <strong>salvate</strong>."
|
|
165 |
msgid "Save Changes"
|
166 |
msgstr "Salvează schimbările"
|
167 |
|
168 |
-
#: scb/AdminPage.php:
|
169 |
msgid "Settings"
|
170 |
msgstr "Setări"
|
171 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
#~ msgid "Related %s"
|
173 |
#~ msgstr "%s înrudite"
|
174 |
|
7 |
msgstr ""
|
8 |
"Project-Id-Version: Posts 2 Posts\n"
|
9 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
10 |
+
"POT-Creation-Date: 2012-08-17 07:40:29+00:00\n"
|
11 |
+
"PO-Revision-Date: 2012-08-17 10:42+0200\n"
|
12 |
"Last-Translator: scribu <mail@scribu.net>\n"
|
13 |
"Language-Team: ROMANIAN <LL@li.org>\n"
|
14 |
"Language: \n"
|
16 |
"Content-Type: text/plain; charset=UTF-8\n"
|
17 |
"Content-Transfer-Encoding: 8bit\n"
|
18 |
|
19 |
+
#: admin/box.php:38
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
msgid "Are you sure you want to delete all connections?"
|
21 |
msgstr "Sigur vreți să ștergeți toate conexiunile?"
|
22 |
|
23 |
+
#: admin/box.php:114
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
msgid "Search"
|
25 |
msgstr "Căutare"
|
26 |
|
27 |
+
#: admin/box.php:191
|
28 |
msgid "previous"
|
29 |
msgstr "anterioare"
|
30 |
|
31 |
+
#: admin/box.php:192
|
32 |
msgid "next"
|
33 |
msgstr "următoare"
|
34 |
|
35 |
+
#: admin/box.php:193
|
36 |
msgid "of"
|
37 |
msgstr "din"
|
38 |
|
39 |
+
#: admin/box.php:236
|
40 |
msgid "Can't create connection: %s"
|
41 |
msgstr "Conexiunea nu poate fi creată: %s"
|
42 |
|
43 |
+
#: admin/factory.php:30
|
44 |
+
msgid " (from)"
|
45 |
+
msgstr "(de la)"
|
46 |
+
|
47 |
+
#: admin/factory.php:31
|
48 |
+
msgid " (to)"
|
49 |
+
msgstr "(la)"
|
50 |
|
51 |
+
#: admin/fields.php:7
|
52 |
msgid "Delete all connections"
|
53 |
msgstr "Șterge toate conexiunile"
|
54 |
|
55 |
+
#: admin/fields.php:16
|
56 |
msgid "Delete connection"
|
57 |
msgstr "Șterge conexiune"
|
58 |
|
60 |
msgid "Connection Types"
|
61 |
msgstr "Tipuri de conexiuni"
|
62 |
|
63 |
+
#: admin/tools.php:41
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
msgid "<em>%s</em> is not a registered connection type."
|
65 |
msgstr "<em>%s</em> nu e un tip de conexiune înregistrat."
|
66 |
|
67 |
+
#: admin/tools.php:50
|
68 |
msgid "Converted %1$s connections from <em>%2$s</em> to <em>%3$s</em>."
|
69 |
msgstr "Am convertit %1$s conexiuni din <em>%2$s</em> în <em>%3$s</em>."
|
70 |
|
71 |
+
#: admin/tools.php:64
|
72 |
msgid "Name"
|
73 |
msgstr "Nume"
|
74 |
|
75 |
+
#: admin/tools.php:65
|
76 |
msgid "Information"
|
77 |
msgstr "Informații"
|
78 |
|
79 |
+
#: admin/tools.php:66
|
80 |
msgid "Connections"
|
81 |
msgstr "Conexiuni"
|
82 |
|
83 |
+
#: admin/tools.php:74
|
84 |
+
msgid "No connection types registered."
|
85 |
+
msgstr "Nu există tipuri de conexiuni înregistrate."
|
86 |
+
|
87 |
+
#: admin/tools.php:76
|
88 |
+
msgid "To register a connection type, see <a href=\"%s\">the wiki</a>."
|
89 |
+
msgstr "Pentru a înregistra un tip de conexiune, vezi <a href=\"%s\">wiki-ul</a>."
|
90 |
+
|
91 |
+
#: admin/tools.php:93
|
92 |
msgid "Convert to registered connection type:"
|
93 |
msgstr "Convertește într-un tip de conexiune înregistrat:"
|
94 |
|
104 |
msgid "A list of posts connected to the current post"
|
105 |
msgstr "O lista de postări conectate la postarea curentă"
|
106 |
|
107 |
+
#: core/extra.php:34
|
108 |
msgid "Title:"
|
109 |
msgstr "Titlu:"
|
110 |
|
111 |
+
#: core/extra.php:41
|
112 |
msgid "Connection type:"
|
113 |
msgstr "Tipul conexiunii:"
|
114 |
|
115 |
+
#: core/extra.php:46
|
116 |
msgid "Connection listing:"
|
117 |
msgstr "Conexiuni de listat:"
|
118 |
|
119 |
+
#: core/extra.php:52
|
120 |
msgid "connected"
|
121 |
msgstr "conectate"
|
122 |
|
123 |
+
#: core/extra.php:53
|
124 |
msgid "related"
|
125 |
msgstr "înrudite"
|
126 |
|
127 |
+
#: core/side.php:210
|
128 |
msgid "Users"
|
129 |
msgstr "Utilizatori"
|
130 |
|
131 |
+
#: core/side.php:219
|
132 |
msgid "User"
|
133 |
msgstr "Utilizator"
|
134 |
|
135 |
+
#: core/side.php:220
|
136 |
msgid "Search Users"
|
137 |
msgstr "Caută utilizatori"
|
138 |
|
139 |
+
#: core/side.php:221
|
140 |
msgid "No users found."
|
141 |
msgstr "Niciun utilizator găsit."
|
142 |
|
143 |
+
#: core/type.php:79
|
144 |
+
msgid "Create connections"
|
145 |
+
msgstr "Creează conexiuni"
|
146 |
+
|
147 |
+
#: core/type.php:102
|
148 |
msgid "Connected %s"
|
149 |
msgstr "%s conectate"
|
150 |
|
157 |
msgid "Save Changes"
|
158 |
msgstr "Salvează schimbările"
|
159 |
|
160 |
+
#: scb/AdminPage.php:346
|
161 |
msgid "Settings"
|
162 |
msgstr "Setări"
|
163 |
|
164 |
+
#~ msgid "View All"
|
165 |
+
#~ msgstr "Vezi toate"
|
166 |
+
|
167 |
+
#~ msgid "Create connection"
|
168 |
+
#~ msgstr "Crează conexiune"
|
169 |
+
|
170 |
+
#~ msgid "Upgraded %d connections."
|
171 |
+
#~ msgstr "Am actualizat %d conexiuni."
|
172 |
+
|
173 |
+
#~ msgid ""
|
174 |
+
#~ "The Posts 2 Posts connections need to be upgraded. <a href=\"%s\">Proceed."
|
175 |
+
#~ "</a>"
|
176 |
+
#~ msgstr ""
|
177 |
+
#~ "Conexiunile Posts 2 Posts trebuie actualizate. <a href=\"%s\">Pornește.</"
|
178 |
+
#~ "a>"
|
179 |
+
|
180 |
#~ msgid "Related %s"
|
181 |
#~ msgstr "%s înrudite"
|
182 |
|
lang/posts-to-posts.pot
CHANGED
@@ -4,7 +4,7 @@ msgid ""
|
|
4 |
msgstr ""
|
5 |
"Project-Id-Version: \n"
|
6 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
7 |
-
"POT-Creation-Date: 2012-
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
@@ -12,55 +12,43 @@ msgstr ""
|
|
12 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
|
15 |
-
#: admin/box
|
16 |
-
msgid " (from)"
|
17 |
-
msgstr ""
|
18 |
-
|
19 |
-
#: admin/box-factory.php:76
|
20 |
-
msgid " (to)"
|
21 |
-
msgstr ""
|
22 |
-
|
23 |
-
#: admin/box.php:40
|
24 |
msgid "Are you sure you want to delete all connections?"
|
25 |
msgstr ""
|
26 |
|
27 |
-
#: admin/box.php:
|
28 |
-
msgid "Create connections:"
|
29 |
-
msgstr ""
|
30 |
-
|
31 |
-
#: admin/box.php:138
|
32 |
-
msgid "View All"
|
33 |
-
msgstr ""
|
34 |
-
|
35 |
-
#: admin/box.php:143
|
36 |
msgid "Search"
|
37 |
msgstr ""
|
38 |
|
39 |
-
#: admin/box.php:
|
40 |
msgid "previous"
|
41 |
msgstr ""
|
42 |
|
43 |
-
#: admin/box.php:
|
44 |
msgid "next"
|
45 |
msgstr ""
|
46 |
|
47 |
-
#: admin/box.php:
|
48 |
msgid "of"
|
49 |
msgstr ""
|
50 |
|
51 |
-
#: admin/box.php:
|
52 |
msgid "Can't create connection: %s"
|
53 |
msgstr ""
|
54 |
|
55 |
-
#: admin/
|
56 |
-
msgid "
|
57 |
msgstr ""
|
58 |
|
59 |
-
#: admin/
|
|
|
|
|
|
|
|
|
60 |
msgid "Delete all connections"
|
61 |
msgstr ""
|
62 |
|
63 |
-
#: admin/fields.php:
|
64 |
msgid "Delete connection"
|
65 |
msgstr ""
|
66 |
|
@@ -68,37 +56,35 @@ msgstr ""
|
|
68 |
msgid "Connection Types"
|
69 |
msgstr ""
|
70 |
|
71 |
-
#: admin/tools.php:
|
72 |
-
msgid "Upgraded %d connections."
|
73 |
-
msgstr ""
|
74 |
-
|
75 |
-
#: admin/tools.php:34
|
76 |
-
msgid ""
|
77 |
-
"The Posts 2 Posts connections need to be upgraded. <a href=\"%s\">Proceed.</"
|
78 |
-
"a>"
|
79 |
-
msgstr ""
|
80 |
-
|
81 |
-
#: admin/tools.php:54
|
82 |
msgid "<em>%s</em> is not a registered connection type."
|
83 |
msgstr ""
|
84 |
|
85 |
-
#: admin/tools.php:
|
86 |
msgid "Converted %1$s connections from <em>%2$s</em> to <em>%3$s</em>."
|
87 |
msgstr ""
|
88 |
|
89 |
-
#: admin/tools.php:
|
90 |
msgid "Name"
|
91 |
msgstr ""
|
92 |
|
93 |
-
#: admin/tools.php:
|
94 |
msgid "Information"
|
95 |
msgstr ""
|
96 |
|
97 |
-
#: admin/tools.php:
|
98 |
msgid "Connections"
|
99 |
msgstr ""
|
100 |
|
101 |
-
#: admin/tools.php:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
msgid "Convert to registered connection type:"
|
103 |
msgstr ""
|
104 |
|
@@ -114,43 +100,47 @@ msgstr ""
|
|
114 |
msgid "A list of posts connected to the current post"
|
115 |
msgstr ""
|
116 |
|
117 |
-
#: core/extra.php:
|
118 |
msgid "Title:"
|
119 |
msgstr ""
|
120 |
|
121 |
-
#: core/extra.php:
|
122 |
msgid "Connection type:"
|
123 |
msgstr ""
|
124 |
|
125 |
-
#: core/extra.php:
|
126 |
msgid "Connection listing:"
|
127 |
msgstr ""
|
128 |
|
129 |
-
#: core/extra.php:
|
130 |
msgid "connected"
|
131 |
msgstr ""
|
132 |
|
133 |
-
#: core/extra.php:
|
134 |
msgid "related"
|
135 |
msgstr ""
|
136 |
|
137 |
-
#: core/side.php:
|
138 |
msgid "Users"
|
139 |
msgstr ""
|
140 |
|
141 |
-
#: core/side.php:
|
142 |
msgid "User"
|
143 |
msgstr ""
|
144 |
|
145 |
-
#: core/side.php:
|
146 |
msgid "Search Users"
|
147 |
msgstr ""
|
148 |
|
149 |
-
#: core/side.php:
|
150 |
msgid "No users found."
|
151 |
msgstr ""
|
152 |
|
153 |
-
#: core/type.php:
|
|
|
|
|
|
|
|
|
154 |
msgid "Connected %s"
|
155 |
msgstr ""
|
156 |
|
@@ -162,6 +152,6 @@ msgstr ""
|
|
162 |
msgid "Save Changes"
|
163 |
msgstr ""
|
164 |
|
165 |
-
#: scb/AdminPage.php:
|
166 |
msgid "Settings"
|
167 |
msgstr ""
|
4 |
msgstr ""
|
5 |
"Project-Id-Version: \n"
|
6 |
"Report-Msgid-Bugs-To: http://wordpress.org/tag/p2p\n"
|
7 |
+
"POT-Creation-Date: 2012-08-17 07:40:29+00:00\n"
|
8 |
"MIME-Version: 1.0\n"
|
9 |
"Content-Type: text/plain; charset=UTF-8\n"
|
10 |
"Content-Transfer-Encoding: 8bit\n"
|
12 |
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
13 |
"Language-Team: LANGUAGE <LL@li.org>\n"
|
14 |
|
15 |
+
#: admin/box.php:38
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
msgid "Are you sure you want to delete all connections?"
|
17 |
msgstr ""
|
18 |
|
19 |
+
#: admin/box.php:114
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
msgid "Search"
|
21 |
msgstr ""
|
22 |
|
23 |
+
#: admin/box.php:191
|
24 |
msgid "previous"
|
25 |
msgstr ""
|
26 |
|
27 |
+
#: admin/box.php:192
|
28 |
msgid "next"
|
29 |
msgstr ""
|
30 |
|
31 |
+
#: admin/box.php:193
|
32 |
msgid "of"
|
33 |
msgstr ""
|
34 |
|
35 |
+
#: admin/box.php:236
|
36 |
msgid "Can't create connection: %s"
|
37 |
msgstr ""
|
38 |
|
39 |
+
#: admin/factory.php:30
|
40 |
+
msgid " (from)"
|
41 |
msgstr ""
|
42 |
|
43 |
+
#: admin/factory.php:31
|
44 |
+
msgid " (to)"
|
45 |
+
msgstr ""
|
46 |
+
|
47 |
+
#: admin/fields.php:7
|
48 |
msgid "Delete all connections"
|
49 |
msgstr ""
|
50 |
|
51 |
+
#: admin/fields.php:16
|
52 |
msgid "Delete connection"
|
53 |
msgstr ""
|
54 |
|
56 |
msgid "Connection Types"
|
57 |
msgstr ""
|
58 |
|
59 |
+
#: admin/tools.php:41
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
msgid "<em>%s</em> is not a registered connection type."
|
61 |
msgstr ""
|
62 |
|
63 |
+
#: admin/tools.php:50
|
64 |
msgid "Converted %1$s connections from <em>%2$s</em> to <em>%3$s</em>."
|
65 |
msgstr ""
|
66 |
|
67 |
+
#: admin/tools.php:64
|
68 |
msgid "Name"
|
69 |
msgstr ""
|
70 |
|
71 |
+
#: admin/tools.php:65
|
72 |
msgid "Information"
|
73 |
msgstr ""
|
74 |
|
75 |
+
#: admin/tools.php:66
|
76 |
msgid "Connections"
|
77 |
msgstr ""
|
78 |
|
79 |
+
#: admin/tools.php:74
|
80 |
+
msgid "No connection types registered."
|
81 |
+
msgstr ""
|
82 |
+
|
83 |
+
#: admin/tools.php:76
|
84 |
+
msgid "To register a connection type, see <a href=\"%s\">the wiki</a>."
|
85 |
+
msgstr ""
|
86 |
+
|
87 |
+
#: admin/tools.php:93
|
88 |
msgid "Convert to registered connection type:"
|
89 |
msgstr ""
|
90 |
|
100 |
msgid "A list of posts connected to the current post"
|
101 |
msgstr ""
|
102 |
|
103 |
+
#: core/extra.php:34
|
104 |
msgid "Title:"
|
105 |
msgstr ""
|
106 |
|
107 |
+
#: core/extra.php:41
|
108 |
msgid "Connection type:"
|
109 |
msgstr ""
|
110 |
|
111 |
+
#: core/extra.php:46
|
112 |
msgid "Connection listing:"
|
113 |
msgstr ""
|
114 |
|
115 |
+
#: core/extra.php:52
|
116 |
msgid "connected"
|
117 |
msgstr ""
|
118 |
|
119 |
+
#: core/extra.php:53
|
120 |
msgid "related"
|
121 |
msgstr ""
|
122 |
|
123 |
+
#: core/side.php:210
|
124 |
msgid "Users"
|
125 |
msgstr ""
|
126 |
|
127 |
+
#: core/side.php:219
|
128 |
msgid "User"
|
129 |
msgstr ""
|
130 |
|
131 |
+
#: core/side.php:220
|
132 |
msgid "Search Users"
|
133 |
msgstr ""
|
134 |
|
135 |
+
#: core/side.php:221
|
136 |
msgid "No users found."
|
137 |
msgstr ""
|
138 |
|
139 |
+
#: core/type.php:79
|
140 |
+
msgid "Create connections"
|
141 |
+
msgstr ""
|
142 |
+
|
143 |
+
#: core/type.php:102
|
144 |
msgid "Connected %s"
|
145 |
msgstr ""
|
146 |
|
152 |
msgid "Save Changes"
|
153 |
msgstr ""
|
154 |
|
155 |
+
#: scb/AdminPage.php:346
|
156 |
msgid "Settings"
|
157 |
msgstr ""
|
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.
|
6 |
Author: scribu
|
7 |
Author URI: http://scribu.net/
|
8 |
Plugin URI: http://scribu.net/wordpress/posts-to-posts
|
@@ -10,20 +10,20 @@ Text Domain: posts-to-posts
|
|
10 |
Domain Path: /lang
|
11 |
*/
|
12 |
|
13 |
-
define( 'P2P_PLUGIN_VERSION', '1.
|
14 |
|
15 |
define( 'P2P_TEXTDOMAIN', 'posts-to-posts' );
|
16 |
|
17 |
require dirname( __FILE__ ) . '/scb/load.php';
|
18 |
|
19 |
-
function
|
20 |
$base = dirname( __FILE__ );
|
21 |
|
22 |
load_plugin_textdomain( P2P_TEXTDOMAIN, '', basename( $base ) . '/lang' );
|
23 |
|
24 |
_p2p_load_files( "$base/core", array(
|
25 |
'storage', 'query', 'query-post', 'query-user', 'url-query',
|
26 |
-
'util', '
|
27 |
'api', 'extra'
|
28 |
) );
|
29 |
|
@@ -32,7 +32,7 @@ function _p2p_init() {
|
|
32 |
|
33 |
if ( is_admin() ) {
|
34 |
_p2p_load_files( "$base/admin", array(
|
35 |
-
'mustache',
|
36 |
'box-factory', 'box', 'fields',
|
37 |
'column-factory', 'column',
|
38 |
'tools'
|
@@ -41,8 +41,13 @@ function _p2p_init() {
|
|
41 |
|
42 |
register_uninstall_hook( __FILE__, array( 'P2P_Storage', 'uninstall' ) );
|
43 |
}
|
44 |
-
scb_init( '
|
45 |
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
function _p2p_load_files( $dir, $files ) {
|
48 |
foreach ( $files as $file )
|
2 |
/*
|
3 |
Plugin Name: Posts 2 Posts
|
4 |
Description: Create many-to-many relationships between all types of posts.
|
5 |
+
Version: 1.4
|
6 |
Author: scribu
|
7 |
Author URI: http://scribu.net/
|
8 |
Plugin URI: http://scribu.net/wordpress/posts-to-posts
|
10 |
Domain Path: /lang
|
11 |
*/
|
12 |
|
13 |
+
define( 'P2P_PLUGIN_VERSION', '1.4' );
|
14 |
|
15 |
define( 'P2P_TEXTDOMAIN', 'posts-to-posts' );
|
16 |
|
17 |
require dirname( __FILE__ ) . '/scb/load.php';
|
18 |
|
19 |
+
function _p2p_load() {
|
20 |
$base = dirname( __FILE__ );
|
21 |
|
22 |
load_plugin_textdomain( P2P_TEXTDOMAIN, '', basename( $base ) . '/lang' );
|
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 |
|
32 |
|
33 |
if ( is_admin() ) {
|
34 |
_p2p_load_files( "$base/admin", array(
|
35 |
+
'mustache', 'factory',
|
36 |
'box-factory', 'box', 'fields',
|
37 |
'column-factory', 'column',
|
38 |
'tools'
|
41 |
|
42 |
register_uninstall_hook( __FILE__, array( 'P2P_Storage', 'uninstall' ) );
|
43 |
}
|
44 |
+
scb_init( '_p2p_load' );
|
45 |
|
46 |
+
function _p2p_init() {
|
47 |
+
// Safe hook for calling p2p_register_connection_type()
|
48 |
+
do_action( 'p2p_init' );
|
49 |
+
}
|
50 |
+
add_action( 'wp_loaded', '_p2p_init' );
|
51 |
|
52 |
function _p2p_load_files( $dir, $files ) {
|
53 |
foreach ( $files as $file )
|
readme.txt
CHANGED
@@ -1,9 +1,9 @@
|
|
1 |
=== Posts 2 Posts ===
|
2 |
Contributors: scribu, ciobi
|
3 |
Tags: connections, custom post types, relationships, many-to-many, users
|
4 |
-
Requires at least: 3.
|
5 |
Tested up to: 3.4
|
6 |
-
Stable tag: 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.3.1 =
|
57 |
* sanitize connection fields values on save, preventing security exploits
|
58 |
* improved connection field default value handling
|
1 |
=== Posts 2 Posts ===
|
2 |
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
|
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 =
|
57 |
+
* added 'p2p_init' hook
|
58 |
+
* replaced 'View All' button with '+ Create connections' toggle
|
59 |
+
* improved usability of connection candidate UI
|
60 |
+
* fixed issues related to auto-drafts
|
61 |
+
* show columns on the admin user list screen
|
62 |
+
|
63 |
= 1.3.1 =
|
64 |
* sanitize connection fields values on save, preventing security exploits
|
65 |
* improved connection field default value handling
|
scb/AdminPage.php
CHANGED
@@ -127,7 +127,7 @@ abstract class scbAdminPage {
|
|
127 |
function page_header() {
|
128 |
echo "<div class='wrap'>\n";
|
129 |
screen_icon( $this->args['screen_icon'] );
|
130 |
-
echo "
|
131 |
}
|
132 |
|
133 |
// This is where the page content goes
|
@@ -274,20 +274,6 @@ abstract class scbAdminPage {
|
|
274 |
return $this->row_wrap( $args['title'], $this->input( $args, $formdata ) );
|
275 |
}
|
276 |
|
277 |
-
// Wraps the given content in a <table>
|
278 |
-
function table_wrap( $content ) {
|
279 |
-
return
|
280 |
-
html( 'table class="form-table"', $content );
|
281 |
-
}
|
282 |
-
|
283 |
-
// Wraps the given content in a <tr><td>
|
284 |
-
function row_wrap( $title, $content ) {
|
285 |
-
return
|
286 |
-
html( 'tr',
|
287 |
-
html( 'th scope="row"', $title )
|
288 |
-
.html( 'td', $content ) );
|
289 |
-
}
|
290 |
-
|
291 |
// Mimic scbForms inheritance
|
292 |
function __call( $method, $args ) {
|
293 |
if ( in_array( $method, array( 'input', 'form' ) ) ) {
|
@@ -303,12 +289,12 @@ abstract class scbAdminPage {
|
|
303 |
|
304 |
// Wraps a string in a <script> tag
|
305 |
function js_wrap( $string ) {
|
306 |
-
return "
|
307 |
}
|
308 |
|
309 |
// Wraps a string in a <style> tag
|
310 |
function css_wrap( $string ) {
|
311 |
-
return "
|
312 |
}
|
313 |
|
314 |
|
127 |
function page_header() {
|
128 |
echo "<div class='wrap'>\n";
|
129 |
screen_icon( $this->args['screen_icon'] );
|
130 |
+
echo html( "h2", $this->args['page_title'] );
|
131 |
}
|
132 |
|
133 |
// This is where the page content goes
|
274 |
return $this->row_wrap( $args['title'], $this->input( $args, $formdata ) );
|
275 |
}
|
276 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
277 |
// Mimic scbForms inheritance
|
278 |
function __call( $method, $args ) {
|
279 |
if ( in_array( $method, array( 'input', 'form' ) ) ) {
|
289 |
|
290 |
// Wraps a string in a <script> tag
|
291 |
function js_wrap( $string ) {
|
292 |
+
return html( "script type='text/javascript'", $string );
|
293 |
}
|
294 |
|
295 |
// Wraps a string in a <style> tag
|
296 |
function css_wrap( $string ) {
|
297 |
+
return html( "style type='text/css'", $string );
|
298 |
}
|
299 |
|
300 |
|
scb/Forms.php
CHANGED
@@ -60,34 +60,26 @@ class scbForms {
|
|
60 |
// ____________WRAPPERS____________
|
61 |
|
62 |
|
63 |
-
// Wraps the given content in a <form><table>
|
64 |
static function form_table_wrap( $content, $nonce = 'update_options' ) {
|
65 |
-
|
66 |
-
$output = self::form_wrap( $output, $nonce );
|
67 |
-
|
68 |
-
return $output;
|
69 |
}
|
70 |
|
71 |
-
// Wraps the given content in a <form> tag
|
72 |
static function form_wrap( $content, $nonce = 'update_options' ) {
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
return $output;
|
79 |
}
|
80 |
|
81 |
-
// Wraps the given content in a <table>
|
82 |
static function table_wrap( $content ) {
|
83 |
-
|
84 |
-
|
85 |
-
return $output;
|
86 |
}
|
87 |
|
88 |
-
// Wraps the given content in a <tr><td>
|
89 |
static function row_wrap( $title, $content ) {
|
90 |
-
return
|
|
|
|
|
|
|
91 |
}
|
92 |
|
93 |
|
@@ -141,16 +133,15 @@ class scbForms {
|
|
141 |
*
|
142 |
* @param array $fields List of args that would be sent to scbForms::input()
|
143 |
* @param array $data The data to validate. Defaults to $_POST
|
|
|
144 |
*
|
145 |
* @return array
|
146 |
*/
|
147 |
-
static function validate_post_data( $fields, $data = null ) {
|
148 |
if ( null === $data ) {
|
149 |
$data = stripslashes_deep( $_POST );
|
150 |
}
|
151 |
|
152 |
-
$to_update = array();
|
153 |
-
|
154 |
foreach ( $fields as $field ) {
|
155 |
$value = scbForms::get_value( $field['name'], $data );
|
156 |
|
@@ -266,12 +257,34 @@ class scbForm {
|
|
266 |
}
|
267 |
|
268 |
|
269 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
270 |
|
271 |
protected $args;
|
272 |
|
273 |
public static function create( $args ) {
|
274 |
-
if ( is_a( $args,
|
275 |
return $args;
|
276 |
|
277 |
if ( empty( $args['name'] ) ) {
|
@@ -279,10 +292,15 @@ abstract class scbFormField {
|
|
279 |
}
|
280 |
|
281 |
if ( isset( $args['value'] ) && is_array( $args['value'] ) ) {
|
282 |
-
$args['
|
283 |
unset( $args['value'] );
|
284 |
}
|
285 |
|
|
|
|
|
|
|
|
|
|
|
286 |
if ( isset( $args['extra'] ) && !is_array( $args['extra'] ) )
|
287 |
$args['extra'] = shortcode_parse_atts( $args['extra'] );
|
288 |
|
@@ -293,8 +311,9 @@ abstract class scbFormField {
|
|
293 |
'wrap_each' => scbForms::TOKEN,
|
294 |
) );
|
295 |
|
296 |
-
|
297 |
-
|
|
|
298 |
|
299 |
switch ( $args['type'] ) {
|
300 |
case 'radio':
|
@@ -302,10 +321,12 @@ abstract class scbFormField {
|
|
302 |
case 'select':
|
303 |
return new scbSelectField( $args );
|
304 |
case 'checkbox':
|
305 |
-
if ( isset( $args['
|
306 |
return new scbMultipleChoiceField( $args );
|
307 |
else
|
308 |
return new scbSingleCheckboxField( $args );
|
|
|
|
|
309 |
default:
|
310 |
return new scbTextField( $args );
|
311 |
}
|
@@ -323,13 +344,6 @@ abstract class scbFormField {
|
|
323 |
return isset( $this->args[ $key ] );
|
324 |
}
|
325 |
|
326 |
-
/**
|
327 |
-
* Generate the corresponding HTML for a field
|
328 |
-
*
|
329 |
-
* @param mixed $value The value to use
|
330 |
-
*
|
331 |
-
* @return string
|
332 |
-
*/
|
333 |
public function render( $value = null ) {
|
334 |
if ( null === $value && isset( $this->default ) )
|
335 |
$value = $this->default;
|
@@ -350,15 +364,6 @@ abstract class scbFormField {
|
|
350 |
// The actual rendering
|
351 |
abstract protected function _render( $args );
|
352 |
|
353 |
-
/**
|
354 |
-
* Validates a value against a field.
|
355 |
-
*
|
356 |
-
* @param mixed $value The value to check
|
357 |
-
*
|
358 |
-
* @return mixed null if the validation failed, sanitized value otherwise.
|
359 |
-
*/
|
360 |
-
abstract public function validate( $value );
|
361 |
-
|
362 |
// Handle args for a single checkbox or radio input
|
363 |
protected static function _checkbox( $args ) {
|
364 |
$args = wp_parse_args( $args, array(
|
@@ -415,15 +420,15 @@ abstract class scbFormField {
|
|
415 |
return $input . ' ' . $desc;
|
416 |
}
|
417 |
|
418 |
-
private static function
|
419 |
-
$
|
420 |
|
421 |
-
if ( !empty( $
|
422 |
if ( is_array( $args['desc'] ) ) {
|
423 |
-
$
|
424 |
$args['desc'] = false;
|
425 |
} elseif ( !isset( $args['numeric'] ) || !$args['numeric'] ) {
|
426 |
-
$
|
427 |
}
|
428 |
}
|
429 |
}
|
@@ -469,7 +474,7 @@ class scbTextField extends scbFormField {
|
|
469 |
abstract class scbSingleChoiceField extends scbFormField {
|
470 |
|
471 |
public function validate( $value ) {
|
472 |
-
if ( isset( $this->
|
473 |
return $value;
|
474 |
|
475 |
return null;
|
@@ -510,10 +515,10 @@ class scbSelectField extends scbSingleChoiceField {
|
|
510 |
);
|
511 |
}
|
512 |
|
513 |
-
foreach ( $
|
514 |
$options[] = array(
|
515 |
'value' => $value,
|
516 |
-
'selected' => (
|
517 |
'title' => $title
|
518 |
);
|
519 |
}
|
@@ -541,16 +546,16 @@ class scbRadiosField extends scbSelectField {
|
|
541 |
|
542 |
if ( array( 'foo' ) == $selected ) {
|
543 |
// radio buttons should always have one option selected
|
544 |
-
$selected = key( $
|
545 |
}
|
546 |
|
547 |
$opts = '';
|
548 |
-
foreach ( $
|
549 |
$single_input = scbFormField::_checkbox( array(
|
550 |
'name' => $name,
|
551 |
'type' => 'radio',
|
552 |
'value' => $value,
|
553 |
-
'checked' => (
|
554 |
'desc' => $title,
|
555 |
'desc_pos' => 'after'
|
556 |
) );
|
@@ -566,7 +571,7 @@ class scbRadiosField extends scbSelectField {
|
|
566 |
class scbMultipleChoiceField extends scbFormField {
|
567 |
|
568 |
public function validate( $value ) {
|
569 |
-
return array_intersect( array_keys( $this->
|
570 |
}
|
571 |
|
572 |
protected function _render( $args ) {
|
@@ -581,7 +586,7 @@ class scbMultipleChoiceField extends scbFormField {
|
|
581 |
$checked = array();
|
582 |
|
583 |
$opts = '';
|
584 |
-
foreach ( $
|
585 |
$single_input = scbFormField::_checkbox( array(
|
586 |
'name' => $name . '[]',
|
587 |
'type' => 'checkbox',
|
@@ -634,3 +639,32 @@ class scbSingleCheckboxField extends scbFormField {
|
|
634 |
}
|
635 |
}
|
636 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
// ____________WRAPPERS____________
|
61 |
|
62 |
|
|
|
63 |
static function form_table_wrap( $content, $nonce = 'update_options' ) {
|
64 |
+
return self::form_wrap( self::table_wrap( $content ), $nonce );
|
|
|
|
|
|
|
65 |
}
|
66 |
|
|
|
67 |
static function form_wrap( $content, $nonce = 'update_options' ) {
|
68 |
+
return html( "form method='post' action=''",
|
69 |
+
$content,
|
70 |
+
wp_nonce_field( $nonce, '_wpnonce', $referer = true, $echo = false )
|
71 |
+
);
|
|
|
|
|
72 |
}
|
73 |
|
|
|
74 |
static function table_wrap( $content ) {
|
75 |
+
return html( "table class='form-table'", $content );
|
|
|
|
|
76 |
}
|
77 |
|
|
|
78 |
static function row_wrap( $title, $content ) {
|
79 |
+
return html( "tr",
|
80 |
+
html( "th scope='row'", $title ),
|
81 |
+
html( "td", $content )
|
82 |
+
);
|
83 |
}
|
84 |
|
85 |
|
133 |
*
|
134 |
* @param array $fields List of args that would be sent to scbForms::input()
|
135 |
* @param array $data The data to validate. Defaults to $_POST
|
136 |
+
* @param array $to_update Existing data to populate. Necessary for nested values
|
137 |
*
|
138 |
* @return array
|
139 |
*/
|
140 |
+
static function validate_post_data( $fields, $data = null, $to_update = array() ) {
|
141 |
if ( null === $data ) {
|
142 |
$data = stripslashes_deep( $_POST );
|
143 |
}
|
144 |
|
|
|
|
|
145 |
foreach ( $fields as $field ) {
|
146 |
$value = scbForms::get_value( $field['name'], $data );
|
147 |
|
257 |
}
|
258 |
|
259 |
|
260 |
+
interface scbFormField_I {
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Generate the corresponding HTML for a field
|
264 |
+
*
|
265 |
+
* @param mixed $value The value to use
|
266 |
+
*
|
267 |
+
* @return string
|
268 |
+
*/
|
269 |
+
function render( $value = null );
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Validates a value against a field.
|
273 |
+
*
|
274 |
+
* @param mixed $value The value to check
|
275 |
+
*
|
276 |
+
* @return mixed null if the validation failed, sanitized value otherwise.
|
277 |
+
*/
|
278 |
+
function validate( $value );
|
279 |
+
}
|
280 |
+
|
281 |
+
|
282 |
+
abstract class scbFormField implements scbFormField_I {
|
283 |
|
284 |
protected $args;
|
285 |
|
286 |
public static function create( $args ) {
|
287 |
+
if ( is_a( $args, 'scbFormField_I' ) )
|
288 |
return $args;
|
289 |
|
290 |
if ( empty( $args['name'] ) ) {
|
292 |
}
|
293 |
|
294 |
if ( isset( $args['value'] ) && is_array( $args['value'] ) ) {
|
295 |
+
$args['choices'] = $args['value'];
|
296 |
unset( $args['value'] );
|
297 |
}
|
298 |
|
299 |
+
if ( isset( $args['values'] ) ) {
|
300 |
+
$args['choices'] = $args['values'];
|
301 |
+
unset( $args['values'] );
|
302 |
+
}
|
303 |
+
|
304 |
if ( isset( $args['extra'] ) && !is_array( $args['extra'] ) )
|
305 |
$args['extra'] = shortcode_parse_atts( $args['extra'] );
|
306 |
|
311 |
'wrap_each' => scbForms::TOKEN,
|
312 |
) );
|
313 |
|
314 |
+
// depends on $args['desc']
|
315 |
+
if ( isset( $args['choices'] ) )
|
316 |
+
self::_expand_choices( $args );
|
317 |
|
318 |
switch ( $args['type'] ) {
|
319 |
case 'radio':
|
321 |
case 'select':
|
322 |
return new scbSelectField( $args );
|
323 |
case 'checkbox':
|
324 |
+
if ( isset( $args['choices'] ) )
|
325 |
return new scbMultipleChoiceField( $args );
|
326 |
else
|
327 |
return new scbSingleCheckboxField( $args );
|
328 |
+
case 'custom':
|
329 |
+
return new scbCustomField( $args );
|
330 |
default:
|
331 |
return new scbTextField( $args );
|
332 |
}
|
344 |
return isset( $this->args[ $key ] );
|
345 |
}
|
346 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
347 |
public function render( $value = null ) {
|
348 |
if ( null === $value && isset( $this->default ) )
|
349 |
$value = $this->default;
|
364 |
// The actual rendering
|
365 |
abstract protected function _render( $args );
|
366 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
367 |
// Handle args for a single checkbox or radio input
|
368 |
protected static function _checkbox( $args ) {
|
369 |
$args = wp_parse_args( $args, array(
|
420 |
return $input . ' ' . $desc;
|
421 |
}
|
422 |
|
423 |
+
private static function _expand_choices( &$args ) {
|
424 |
+
$choices =& $args['choices'];
|
425 |
|
426 |
+
if ( !empty( $choices ) && !self::is_associative( $choices ) ) {
|
427 |
if ( is_array( $args['desc'] ) ) {
|
428 |
+
$choices = array_combine( $choices, $args['desc'] ); // back-compat
|
429 |
$args['desc'] = false;
|
430 |
} elseif ( !isset( $args['numeric'] ) || !$args['numeric'] ) {
|
431 |
+
$choices = array_combine( $choices, $choices );
|
432 |
}
|
433 |
}
|
434 |
}
|
474 |
abstract class scbSingleChoiceField extends scbFormField {
|
475 |
|
476 |
public function validate( $value ) {
|
477 |
+
if ( isset( $this->choices[ $value ] ) )
|
478 |
return $value;
|
479 |
|
480 |
return null;
|
515 |
);
|
516 |
}
|
517 |
|
518 |
+
foreach ( $choices as $value => $title ) {
|
519 |
$options[] = array(
|
520 |
'value' => $value,
|
521 |
+
'selected' => ( $value == $selected ),
|
522 |
'title' => $title
|
523 |
);
|
524 |
}
|
546 |
|
547 |
if ( array( 'foo' ) == $selected ) {
|
548 |
// radio buttons should always have one option selected
|
549 |
+
$selected = key( $choices );
|
550 |
}
|
551 |
|
552 |
$opts = '';
|
553 |
+
foreach ( $choices as $value => $title ) {
|
554 |
$single_input = scbFormField::_checkbox( array(
|
555 |
'name' => $name,
|
556 |
'type' => 'radio',
|
557 |
'value' => $value,
|
558 |
+
'checked' => ( $value == $selected ),
|
559 |
'desc' => $title,
|
560 |
'desc_pos' => 'after'
|
561 |
) );
|
571 |
class scbMultipleChoiceField extends scbFormField {
|
572 |
|
573 |
public function validate( $value ) {
|
574 |
+
return array_intersect( array_keys( $this->choices ), (array) $value );
|
575 |
}
|
576 |
|
577 |
protected function _render( $args ) {
|
586 |
$checked = array();
|
587 |
|
588 |
$opts = '';
|
589 |
+
foreach ( $choices as $value => $title ) {
|
590 |
$single_input = scbFormField::_checkbox( array(
|
591 |
'name' => $name . '[]',
|
592 |
'type' => 'checkbox',
|
639 |
}
|
640 |
}
|
641 |
|
642 |
+
|
643 |
+
class scbCustomField implements scbFormField_I {
|
644 |
+
|
645 |
+
protected $args;
|
646 |
+
|
647 |
+
function __construct( $args ) {
|
648 |
+
$this->args = wp_parse_args( $args, array(
|
649 |
+
'render' => 'var_dump',
|
650 |
+
'sanitize' => 'wp_filter_kses',
|
651 |
+
) );
|
652 |
+
}
|
653 |
+
|
654 |
+
public function __get( $key ) {
|
655 |
+
return $this->args[ $key ];
|
656 |
+
}
|
657 |
+
|
658 |
+
public function __isset( $key ) {
|
659 |
+
return isset( $this->args[ $key ] );
|
660 |
+
}
|
661 |
+
|
662 |
+
public function render( $value = null ) {
|
663 |
+
return call_user_func( $this->render, $value, $this );
|
664 |
+
}
|
665 |
+
|
666 |
+
public function validate( $value ) {
|
667 |
+
return call_user_func( $this->sanitize, $value, $this );
|
668 |
+
}
|
669 |
+
}
|
670 |
+
|
scb/Options.php
CHANGED
@@ -35,27 +35,25 @@ class scbOptions {
|
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
-
* Get option values for one
|
39 |
*
|
40 |
-
* @param string|array $field The field
|
41 |
* @return mixed Whatever is in those fields
|
42 |
*/
|
43 |
-
public function get( $field =
|
44 |
-
$data = get_option( $this->key, array() );
|
45 |
|
46 |
-
|
47 |
-
|
48 |
-
return $this->_get( $field, $data );
|
49 |
}
|
50 |
|
51 |
/**
|
52 |
-
* Get default values for one
|
53 |
*
|
54 |
-
* @param string|array $field The field
|
55 |
* @return mixed Whatever is in those fields
|
56 |
*/
|
57 |
-
public function get_defaults( $field =
|
58 |
-
return
|
59 |
}
|
60 |
|
61 |
/**
|
@@ -89,7 +87,7 @@ class scbOptions {
|
|
89 |
* @return bool
|
90 |
*/
|
91 |
public function cleanup() {
|
92 |
-
$this->update( $this->
|
93 |
}
|
94 |
|
95 |
/**
|
@@ -129,19 +127,7 @@ class scbOptions {
|
|
129 |
return wp_array_slice_assoc( $data, array_keys( $this->defaults ) );
|
130 |
}
|
131 |
|
132 |
-
// Get one, more or all fields from an array
|
133 |
private function &_get( $field, $data ) {
|
134 |
-
if ( empty( $field ) )
|
135 |
-
return $data;
|
136 |
-
|
137 |
-
if ( is_string( $field ) )
|
138 |
-
return $data[$field];
|
139 |
-
|
140 |
-
foreach ( $field as $key )
|
141 |
-
if ( isset( $data[$key] ) )
|
142 |
-
$result[] = $data[$key];
|
143 |
-
|
144 |
-
return $result;
|
145 |
}
|
146 |
|
147 |
// Magic method: $options->field
|
35 |
}
|
36 |
|
37 |
/**
|
38 |
+
* Get option values for one or all fields
|
39 |
*
|
40 |
+
* @param string|array $field The field to get
|
41 |
* @return mixed Whatever is in those fields
|
42 |
*/
|
43 |
+
public function get( $field = null, $default = null ) {
|
44 |
+
$data = array_merge( $this->defaults, get_option( $this->key, array() ) );
|
45 |
|
46 |
+
return scbForms::get_value( $field, $data, $default );
|
|
|
|
|
47 |
}
|
48 |
|
49 |
/**
|
50 |
+
* Get default values for one or all fields
|
51 |
*
|
52 |
+
* @param string|array $field The field to get
|
53 |
* @return mixed Whatever is in those fields
|
54 |
*/
|
55 |
+
public function get_defaults( $field = null ) {
|
56 |
+
return scbForms::get_value( $field, $this->defaults );
|
57 |
}
|
58 |
|
59 |
/**
|
87 |
* @return bool
|
88 |
*/
|
89 |
public function cleanup() {
|
90 |
+
$this->update( $this->get(), true );
|
91 |
}
|
92 |
|
93 |
/**
|
127 |
return wp_array_slice_assoc( $data, array_keys( $this->defaults ) );
|
128 |
}
|
129 |
|
|
|
130 |
private function &_get( $field, $data ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
}
|
132 |
|
133 |
// Magic method: $options->field
|
scb/Util.php
CHANGED
@@ -119,7 +119,7 @@ class scbUtil {
|
|
119 |
|
120 |
// Return a standard admin notice
|
121 |
function scb_admin_notice( $msg, $class = 'updated' ) {
|
122 |
-
return "
|
123 |
}
|
124 |
|
125 |
// Transform a list of objects into an associative array
|
@@ -145,6 +145,8 @@ function scb_list_fold( $list, $key, $value ) {
|
|
145 |
*/
|
146 |
if ( ! function_exists( 'html' ) ):
|
147 |
function html( $tag ) {
|
|
|
|
|
148 |
$args = func_get_args();
|
149 |
|
150 |
$tag = array_shift( $args );
|
@@ -165,7 +167,7 @@ function html( $tag ) {
|
|
165 |
list( $closing ) = explode( ' ', $tag, 2 );
|
166 |
}
|
167 |
|
168 |
-
if ( in_array( $closing,
|
169 |
return "<{$tag} />";
|
170 |
}
|
171 |
|
119 |
|
120 |
// Return a standard admin notice
|
121 |
function scb_admin_notice( $msg, $class = 'updated' ) {
|
122 |
+
return html( "div class='$class fade'", html( "p", $msg ) );
|
123 |
}
|
124 |
|
125 |
// Transform a list of objects into an associative array
|
145 |
*/
|
146 |
if ( ! function_exists( 'html' ) ):
|
147 |
function html( $tag ) {
|
148 |
+
static $SELF_CLOSING_TAGS = array( 'area', 'base', 'basefont', 'br', 'hr', 'input', 'img', 'link', 'meta' );
|
149 |
+
|
150 |
$args = func_get_args();
|
151 |
|
152 |
$tag = array_shift( $args );
|
167 |
list( $closing ) = explode( ' ', $tag, 2 );
|
168 |
}
|
169 |
|
170 |
+
if ( in_array( $closing, $SELF_CLOSING_TAGS ) ) {
|
171 |
return "<{$tag} />";
|
172 |
}
|
173 |
|
scb/load.php
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
$GLOBALS['_scb_data'] = array(
|
4 |
'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
|
5 |
'scbWidget', 'scbAdminPage', 'scbBoxesPage',
|
6 |
'scbCron', 'scbHooks',
|
@@ -32,8 +32,10 @@ class scbLoad4 {
|
|
32 |
add_action( 'activate_plugin', array( __CLASS__, 'delayed_activation' ) );
|
33 |
}
|
34 |
|
35 |
-
|
36 |
-
|
|
|
|
|
37 |
}
|
38 |
|
39 |
static function delayed_activation( $plugin ) {
|
1 |
<?php
|
2 |
|
3 |
+
$GLOBALS['_scb_data'] = array( 56, __FILE__, array(
|
4 |
'scbUtil', 'scbOptions', 'scbForms', 'scbTable',
|
5 |
'scbWidget', 'scbAdminPage', 'scbBoxesPage',
|
6 |
'scbCron', 'scbHooks',
|
32 |
add_action( 'activate_plugin', array( __CLASS__, 'delayed_activation' ) );
|
33 |
}
|
34 |
|
35 |
+
if ( did_action( 'plugins_loaded' ) )
|
36 |
+
self::load();
|
37 |
+
else
|
38 |
+
add_action( 'plugins_loaded', array( __CLASS__, 'load' ), 9, 0 );
|
39 |
}
|
40 |
|
41 |
static function delayed_activation( $plugin ) {
|
screenshot-1.png
CHANGED
Binary file
|
screenshot-2.png
CHANGED
Binary file
|
screenshot-4.png
CHANGED
Binary file
|