| 1 |
<?php |
| 2 |
|
| 3 |
// Exit if accessed directly. |
| 4 |
if ( ! defined( 'ABSPATH' ) ) { |
| 5 |
exit; |
| 6 |
} |
| 7 |
|
| 8 |
/** |
| 9 |
* Helper functions to work with licenses, permissions and capabilities. |
| 10 |
* |
| 11 |
* @package Charitable |
| 12 |
* @since 1.8.0 |
| 13 |
* @phpcs:disable Universal.Arrays.DisallowShortArraySyntax.Found |
| 14 |
*/ |
| 15 |
|
| 16 |
/** |
| 17 |
* Search for posts editable by user. |
| 18 |
* |
| 19 |
* @since 1.8.0 |
| 20 |
* @version 1.8.8.6 |
| 21 |
* |
| 22 |
* @param string $search_term Optional search term. Default ''. |
| 23 |
* @param array $args Args { |
| 24 |
* Optional. An array of arguments. |
| 25 |
* |
| 26 |
* @type string $post_type Post type to search for. |
| 27 |
* @type string[] $post_status Post status to search for. |
| 28 |
* @type int $count Number of results to return. Default 20. |
| 29 |
* } |
| 30 |
* |
| 31 |
* @return array |
| 32 |
* @noinspection PhpTernaryExpressionCanBeReducedToShortVersionInspection |
| 33 |
* @noinspection ElvisOperatorCanBeUsedInspection |
| 34 |
*/ |
| 35 |
function charitable_campaign_search_posts( $search_term = '', $args = [] ) { |
| 36 |
|
| 37 |
global $wpdb; |
| 38 |
|
| 39 |
$default_args = [ |
| 40 |
'post_type' => 'page', |
| 41 |
'post_status' => [ 'publish' ], |
| 42 |
'count' => 20, |
| 43 |
]; |
| 44 |
$args = wp_parse_args( $args, $default_args ); |
| 45 |
|
| 46 |
// @todo: add trash access capabilities to MySQL. |
| 47 |
// See edit_post/edit_page case in map_meta_cap(). |
| 48 |
$args['post_status'] = array_diff( $args['post_status'], [ 'trash' ] ); |
| 49 |
|
| 50 |
$user = wp_get_current_user(); |
| 51 |
$user_id = $user ? $user->ID : 0; |
| 52 |
$post_type = get_post_type_object( $args['post_type'] ); |
| 53 |
|
| 54 |
if ( ! $user_id || ! $post_type || $args['count'] <= 0 ) { |
| 55 |
return []; |
| 56 |
} |
| 57 |
|
| 58 |
$last_changed = wp_cache_get_last_changed( 'posts' ); |
| 59 |
$key = __FUNCTION__ . ":$search_term:$last_changed"; |
| 60 |
$cache_posts = wp_cache_get( $key, '', false, $found ); |
| 61 |
|
| 62 |
if ( $found ) { |
| 63 |
return $cache_posts; |
| 64 |
} |
| 65 |
|
| 66 |
$post_title_where = $search_term ? $wpdb->prepare( |
| 67 |
'post_title LIKE %s AND', |
| 68 |
'%' . $wpdb->esc_like( $search_term ) . '%' |
| 69 |
) : |
| 70 |
''; |
| 71 |
|
| 72 |
$post_statuses_array = array_intersect( array_keys( get_post_statuses() ), $args['post_status'] ); |
| 73 |
$post_statuses = charitable_wpdb_prepare_in( $post_statuses_array ); |
| 74 |
$policy_id = (int) get_option( 'wp_page_for_privacy_policy' ); |
| 75 |
$can_delete_published_posts = (int) $user->has_cap( $post_type->cap->delete_published_posts ); |
| 76 |
$can_delete_posts = (int) $user->has_cap( $post_type->cap->delete_posts ); |
| 77 |
$can_delete_others_posts = (int) $user->has_cap( $post_type->cap->delete_others_posts ); |
| 78 |
$can_delete_private_posts = (int) $user->has_cap( $post_type->cap->delete_private_posts ); |
| 79 |
$can_edit_policy = (int) $user->has_cap( map_meta_cap( 'manage_privacy_options', $user_id )[0] ); |
| 80 |
|
| 81 |
// For the case when user is post author. |
| 82 |
// Integers are safe as they're cast to int above. |
| 83 |
$capability_author_where = "post_author = $user_id AND |
| 84 |
( ( post_status IN ( 'publish', 'future' ) AND $can_delete_published_posts ) OR |
| 85 |
( ( post_status NOT IN ( 'publish', 'future', 'trash' ) ) AND $can_delete_posts ) |
| 86 |
)"; |
| 87 |
|
| 88 |
// For the case when accessing someone other's post. |
| 89 |
$capability_other_where = "post_author != $user_id AND |
| 90 |
$can_delete_others_posts AND |
| 91 |
( ( post_status IN ( 'publish', 'future' ) AND $can_delete_published_posts ) OR |
| 92 |
( ( post_status IN ( 'private' ) ) AND $can_delete_private_posts ) |
| 93 |
)"; |
| 94 |
|
| 95 |
// For privacy policy page. |
| 96 |
$capability_policy_where = "ID = $policy_id AND $can_edit_policy"; |
| 97 |
|
| 98 |
$capability_where = '( ' . |
| 99 |
'(' . $capability_author_where . ') OR ' . |
| 100 |
'(' . $capability_other_where . ') OR ' . |
| 101 |
'(' . $capability_policy_where . ')' . |
| 102 |
' )'; |
| 103 |
|
| 104 |
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter |
| 105 |
// $post_title_where is already prepared by $wpdb->prepare() on line 59. |
| 106 |
// $post_statuses is already prepared by charitable_wpdb_prepare_in(). |
| 107 |
// $capability_where uses integers that are cast to int, so they're safe. |
| 108 |
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery |
| 109 |
$posts = $wpdb->get_results( |
| 110 |
$wpdb->prepare( |
| 111 |
"SELECT ID, post_title, post_author |
| 112 |
FROM $wpdb->posts |
| 113 |
WHERE $post_title_where |
| 114 |
post_type = %s AND |
| 115 |
post_status IN ( $post_statuses ) AND |
| 116 |
$capability_where |
| 117 |
ORDER BY post_title LIMIT %d", |
| 118 |
$args['post_type'], |
| 119 |
absint( $args['count'] ) |
| 120 |
) |
| 121 |
); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery |
| 122 |
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared,PluginCheck.Security.DirectDB.UnescapedDBParameter |
| 123 |
|
| 124 |
$posts = $posts ? $posts : []; |
| 125 |
$posts = array_map( |
| 126 |
static function ( $post ) { |
| 127 |
$post->post_title = charitable_get_post_title( $post ); |
| 128 |
|
| 129 |
unset( $post->post_author ); |
| 130 |
|
| 131 |
return $post; |
| 132 |
}, |
| 133 |
$posts |
| 134 |
); |
| 135 |
|
| 136 |
wp_cache_set( $key, $posts ); |
| 137 |
|
| 138 |
return $posts; |
| 139 |
} |
| 140 |
|
| 141 |
/** |
| 142 |
* Search pages by search term and return an array containing |
| 143 |
* `value` and `label` which is the post ID and post title respectively. |
| 144 |
* |
| 145 |
* @since 1.7.9 |
| 146 |
* |
| 147 |
* @param string $search_term The search term. |
| 148 |
* @param array $args Optional. An array of arguments. |
| 149 |
* |
| 150 |
* @return array |
| 151 |
*/ |
| 152 |
function charitable_search_pages_for_dropdown( $search_term, $args = [] ) { |
| 153 |
|
| 154 |
$search_results = charitable_campaign_search_posts( $search_term, $args ); |
| 155 |
$result_pages = []; |
| 156 |
|
| 157 |
// Prepare for ChoicesJS render. |
| 158 |
foreach ( $search_results as $search_result ) { |
| 159 |
$result_pages[] = [ |
| 160 |
'value' => absint( $search_result->ID ), |
| 161 |
'label' => esc_html( $search_result->post_title ), |
| 162 |
]; |
| 163 |
} |
| 164 |
|
| 165 |
return $result_pages; |
| 166 |
} |
| 167 |
|