Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/classified-listing/app/Controllers/Ajax/AjaxGallery.php
+++ b/classified-listing/app/Controllers/Ajax/AjaxGallery.php
@@ -10,6 +10,36 @@
class AjaxGallery {
+ /**
+ * Verify that the current user owns (or can edit) the given listing.
+ * Returns true when the request should be allowed, false otherwise.
+ *
+ * For brand-new listings ($post_id === 0) the caller only needs to be
+ * logged-in (or unregistered posting must be enabled).
+ *
+ * For existing listings the user must be the author or an administrator,
+ * with a special exception for guest temp posts (post_status 'rtcl-temp',
+ * author 0, unregistered posting enabled).
+ */
+ private function current_user_can_edit_listing( $post_id ) {
+ $post_id = absint( $post_id );
+
+ $listing = rtcl()->factory->get_listing( $post_id );
+ if ( ! $listing ) {
+ return false;
+ }
+
+ $post = $listing->get_listing();
+ $post_author = (int) $post->post_author;
+
+ // Guest temp posts created during unregistered posting.
+ if ( 'rtcl-temp' === $post->post_status && 0 === $post_author && Functions::is_enable_post_for_unregister() ) {
+ return true;
+ }
+
+ return Functions::current_user_can( 'edit_' . rtcl()->post_type, $post_id );
+ }
+
public function __construct() {
add_action( 'wp_ajax_rtcl_gallery_upload', [ $this, 'gallery_upload' ] );
add_action( 'wp_ajax_rtcl_gallery_update_order', [ $this, 'gallery_update_order' ] );
@@ -20,7 +50,7 @@
add_action( 'wp_ajax_rtcl_gallery_image_stream', [ $this, 'gallery_image_stream' ] );
- if ( !is_user_logged_in() && Functions::is_enable_post_for_unregister() ) {
+ if ( ! is_user_logged_in() && Functions::is_enable_post_for_unregister() ) {
add_action( 'wp_ajax_nopriv_rtcl_gallery_upload', [ $this, 'gallery_upload' ] );
add_action( 'wp_ajax_nopriv_rtcl_gallery_update_order', [ $this, 'gallery_update_order' ] );
add_action( 'wp_ajax_nopriv_rtcl_gallery_delete', [ $this, 'gallery_delete' ] );
@@ -29,38 +59,69 @@
add_action( 'wp_ajax_nopriv_rtcl_gallery_update', [ $this, 'gallery_update' ] );
add_action( 'wp_ajax_nopriv_rtcl_gallery_image_stream', [ $this, 'gallery_image_stream' ] );
}
-
}
function gallery_delete() {
- if ( !check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ if ( ! check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( ! is_user_logged_in() && apply_filters( 'rtcl_is_disable_post_for_unregister', true ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Registration required to delete listing image.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ $post_id = absint( Functions::request( "post_id" ) );
+ if ( $post_id > 0 && ! $this->current_user_can_edit_listing( $post_id ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" )
+ "error" => __( "You do not have permission to delete images for this listing.", "classified-listing" ),
] );
exit;
}
$attach_id = intval( $_POST["attach_id"] );
- $attach = get_post( $attach_id );
+ $attach = get_post( $attach_id );
if ( $attach === null ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Attachment does not exist.", "classified-listing" )
+ "error" => __( "Attachment does not exist.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( is_user_logged_in() && ( ! current_user_can( 'delete_post', $attach_id ) && ! current_user_can( 'manage_rtcl_listing_images' ) ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "You are not allowed to delete listing images.", "classified-listing" ),
] );
- } elseif ( $attach->post_parent != absint( Functions::request( "post_id" ) ) ) {
+
+ exit;
+ }
+
+ if ( $attach->post_parent != absint( Functions::request( "post_id" ) ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Incorrect attachment ID.", "classified-listing" )
+ "error" => __( "Incorrect attachment ID.", "classified-listing" ),
] );
} elseif ( wp_delete_attachment( $attach_id ) ) {
echo wp_json_encode( [ "result" => 1 ] );
} else {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "File could not be deleted.", "classified-listing" )
+ "error" => __( "File could not be deleted.", "classified-listing" ),
] );
}
@@ -68,38 +129,79 @@
}
function gallery_update_order() {
- if ( !check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ if ( ! check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
wp_send_json_error( [ "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" ) ] );
}
+ if ( ! is_user_logged_in() && apply_filters( 'rtcl_is_disable_post_for_unregister', true ) ) {
+ wp_send_json_error( [ "error" => __( "Registration required to reorder listing image.", "classified-listing" ) ] );
+ }
+
+ if ( is_user_logged_in() && ( ! current_user_can( 'upload_files' ) && ! current_user_can( 'manage_rtcl_listing_images' ) ) ) {
+ wp_send_json_error( [ "error" => __( "You are not allowed to reorder listing images.", "classified-listing" ) ] );
+ }
+
$post_id = intval( Functions::request( "post_id" ) );
- $ordered_keys = !empty( $_POST['ordered_keys'] ) && is_array( $_POST['ordered_keys'] ) ? $_POST['ordered_keys'] : [];
+
+ if ( $post_id > 0 && ! $this->current_user_can_edit_listing( $post_id ) ) {
+ wp_send_json_error( [ "error" => __( "You do not have permission to reorder images for this listing.", "classified-listing" ) ] );
+ }
+
+ $ordered_keys = ! empty( $_POST['ordered_keys'] ) && is_array( $_POST['ordered_keys'] ) ? $_POST['ordered_keys'] : [];
$ordered_keys = $ordered_keys ? array_map( 'intval', $ordered_keys ) : [];
$ordered_keys = $ordered_keys ? array_filter( $ordered_keys ) : [];
- if ( !empty( $ordered_keys ) ) {
+ if ( ! empty( $ordered_keys ) ) {
update_post_meta( $post_id, '_rtcl_attachments_order', $ordered_keys );
}
wp_send_json_success( $ordered_keys );
}
function gallery_upload() {
+ if ( ! check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( ! is_user_logged_in() && apply_filters( 'rtcl_is_disable_post_for_unregister', true ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Registration required to upload listing image.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( is_user_logged_in() && ( ! current_user_can( 'upload_files' ) && ! current_user_can( 'manage_rtcl_listing_images' ) ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "You are not allowed to upload listing images.", "classified-listing" ),
+ ] );
- if ( !check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ exit;
+ }
+
+ $parent_post_id = isset( $_POST["post_id"] ) ? absint( $_POST["post_id"] ) : 0;
+ if ( $parent_post_id > 0 && ! $this->current_user_can_edit_listing( $parent_post_id ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" )
+ "error" => __( "You do not have permission to upload images for this listing.", "classified-listing" ),
] );
exit;
}
- $v = new UploadHelper();
- $field_name = Functions::request( "field_name" );
+
+ $v = new UploadHelper();
+ $field_name = Functions::request( "field_name" );
$form_params = [
"form_scheme" => Functions::request( "form_scheme" ),
];
$form_scheme = apply_filters( "rtcl_form_scheme", Helper::instance()->get( "form" ), $form_params );
$form_scheme = apply_filters( "rtcl_form_load", $form_scheme );
- if ( !empty( $form_scheme["field"] ) && is_array( $form_scheme["field"] ) ) {
+ if ( ! empty( $form_scheme["field"] ) && is_array( $form_scheme["field"] ) ) {
foreach ( $form_scheme["field"] as $key => $field ) {
if ( $field["name"] == $field_name ) {
if ( isset( $field["validator"] ) && is_array( $field["validator"] ) ) {
@@ -107,7 +209,6 @@
$v->add_validator( $vcallback );
}
}
-
}
}
}
@@ -118,7 +219,7 @@
// you can use WP's wp_handle_upload() function:
$status = wp_handle_upload( $_FILES['async-upload'], [
'test_form' => true,
- 'action' => 'rtcl_gallery_upload'
+ 'action' => 'rtcl_gallery_upload',
] );
if ( isset( $status['error'] ) ) {
@@ -145,12 +246,11 @@
'post_mime_type' => $filetype['type'],
'post_title' => preg_replace( '/.[^.]+$/', '', basename( $filename ) ),
'post_content' => '',
- 'post_status' => 'inherit'
+ 'post_status' => 'inherit',
];
// Create post if does not exist
if ( $parent_post_id < 1 ) {
-
add_filter( "post_type_link", "__return_empty_string" );
$parent_post_id = wp_insert_post( apply_filters( "rtcl_insert_temp_post_for_gallery", [
@@ -159,7 +259,7 @@
'post_status' => Functions::get_temp_listing_status(),
'post_author' => wp_get_current_user()->ID,
'post_type' => rtcl()->post_type,
- 'comments_status' => 'closed'
+ 'comments_status' => 'closed',
] ) );
remove_filter( "post_type_link", "__return_empty_string" );
@@ -167,7 +267,7 @@
// Insert the attachment.
$attach_id = wp_insert_attachment( $attachment, $filename, $parent_post_id );
- if ( !is_wp_error( $attach_id ) ) {
+ if ( ! is_wp_error( $attach_id ) ) {
wp_update_attachment_metadata( $attach_id, Functions::generate_attachment_metadata( $attach_id, $filename, Functions::get_image_sizes() ) );
}
// Fix the image guid url
@@ -177,44 +277,70 @@
}
function gallery_image_save() {
+ if ( ! wp_verify_nonce( isset( $_REQUEST[ rtcl()->nonceId ] ) ? $_REQUEST[ rtcl()->nonceId ] : null, rtcl()->nonceText ) && ! check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( ! is_user_logged_in() && apply_filters( 'rtcl_is_disable_post_for_unregister', true ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Registration required to save listing image.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
- if ( !wp_verify_nonce( isset( $_REQUEST[rtcl()->nonceId] ) ? $_REQUEST[rtcl()->nonceId] : null, rtcl()->nonceText ) && !check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ if ( is_user_logged_in() && ( ! current_user_can( 'manage_rtcl_options' ) && ! current_user_can( 'manage_rtcl_listing_images' ) ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" )
+ "error" => __( "You are not allowed to save listing images.", "classified-listing" ),
] );
+
exit;
}
- if ( !Functions::user_can_edit_image() ) {
+ if ( ! Functions::user_can_edit_image() ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "You cannot edit images.", "classified-listing" )
+ "error" => __( "You cannot edit images.", "classified-listing" ),
] );
exit;
}
- $attach_id = absint( Functions::request( "attach_id" ) );
- $action_type = Functions::request( "action_type" );
+ $attach_id = absint( Functions::request( "attach_id" ) );
+ $action_type = Functions::request( "action_type" );
$history_encoded = Functions::request( "history" );
- $post_id = absint( Functions::request( "post_id" ) );
+ $post_id = absint( Functions::request( "post_id" ) );
+
+ if ( $post_id > 0 && ! $this->current_user_can_edit_listing( $post_id ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "You do not have permission to edit images for this listing.", "classified-listing" ),
+ ] );
+ exit;
+ }
$size_dash = Functions::request( "size" );
- $size = str_replace( "_", "-", Functions::request( "size" ) );
+ $size = str_replace( "_", "-", Functions::request( "size" ) );
- $attach = get_post( $attach_id );
+ $attach = get_post( $attach_id );
$history = json_decode( $history_encoded );
if ( $attach->post_parent != $post_id ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" )
+ "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" ),
] );
exit;
}
- if ( !is_array( $history ) ) {
+ if ( ! is_array( $history ) ) {
$history = [];
}
@@ -223,10 +349,10 @@
$file_name = pathinfo( $attached_file, PATHINFO_FILENAME );
if ( $size && $action_type == "edit" ) {
- $upload = Functions::upload_item_data( $attach_id );
- $attached_file = dirname( $attached_file ) . "/" . basename( $upload["sizes"][$size_dash]["url"] );
- } else if ( $action_type == "create" ) {
- $upload = Functions::upload_item_data( $attach_id );
+ $upload = Functions::upload_item_data( $attach_id );
+ $attached_file = dirname( $attached_file ) . "/" . basename( $upload["sizes"][ $size_dash ]["url"] );
+ } elseif ( $action_type == "create" ) {
+ $upload = Functions::upload_item_data( $attach_id );
$attached_file = dirname( $attached_file ) . "/" . basename( $upload["sizes"]["full"]["url"] );
}
@@ -235,24 +361,24 @@
if ( is_wp_error( $image ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => $image->get_error_message()
+ "error" => $image->get_error_message(),
] );
exit;
}
foreach ( $history as $c ) {
- if ( !isset( $c->a ) ) {
+ if ( ! isset( $c->a ) ) {
continue;
}
if ( $c->a == "c" ) {
$image->crop( $c->x, $c->y, $c->w, $c->h );
- } else if ( $c->a == "ro" ) {
+ } elseif ( $c->a == "ro" ) {
$image->rotate( $c->v );
- } else if ( $c->a == "re" ) {
+ } elseif ( $c->a == "re" ) {
// resize
$image->resize( $c->w, $c->h );
- } else if ( $c->a == "f" ) {
+ } elseif ( $c->a == "f" ) {
$image->flip( $c->h, $c->v );
}
}
@@ -260,29 +386,29 @@
$return = new stdClass();
$backup_sizes = get_post_meta( $attach_id, '_wp_attachment_backup_sizes', true );
- $backup_sizes = !is_array( $backup_sizes ) ? [] : get_post_meta( $attach_id, '_wp_attachment_backup_sizes', true );
- $meta = wp_get_attachment_metadata( $attach_id );
+ $backup_sizes = ! is_array( $backup_sizes ) ? [] : get_post_meta( $attach_id, '_wp_attachment_backup_sizes', true );
+ $meta = wp_get_attachment_metadata( $attach_id );
$basename = pathinfo( $attached_file, PATHINFO_BASENAME );
- $dirname = pathinfo( $attached_file, PATHINFO_DIRNAME );
- $ext = pathinfo( $attached_file, PATHINFO_EXTENSION );
+ $dirname = pathinfo( $attached_file, PATHINFO_DIRNAME );
+ $ext = pathinfo( $attached_file, PATHINFO_EXTENSION );
$filename = pathinfo( $attached_file, PATHINFO_FILENAME );
- $suffix = time() . wp_rand( 100, 999 );
+ $suffix = time() . wp_rand( 100, 999 );
$is_resized = preg_match( '/-e([0-9]+)$/', $filename );
if ( $action_type == "create" && $size != "full" ) {
- $sizes = rtcl()->gallery['image_sizes'];
- $filename = sprintf( "%s-%dx%d", $filename, $sizes[$size]["width"], $sizes[$size]["height"] );
+ $sizes = rtcl()->gallery['image_sizes'];
+ $filename = sprintf( "%s-%dx%d", $filename, $sizes[ $size ]["width"], $sizes[ $size ]["height"] );
}
while ( true ) {
- $filename = preg_replace( '/-e([0-9]+)$/', '', $filename );
- $filename .= "-e{$suffix}";
+ $filename = preg_replace( '/-e([0-9]+)$/', '', $filename );
+ $filename .= "-e{$suffix}";
$new_filename = "{$filename}.{$ext}";
- $new_path = "{$dirname}/$new_filename";
+ $new_path = "{$dirname}/$new_filename";
if ( file_exists( $new_path ) ) {
- $suffix++;
+ $suffix ++;
} else {
break;
}
@@ -290,10 +416,10 @@
$saved = $image->save( $new_path );
- if ( !$saved ) {
+ if ( ! $saved ) {
echo wp_json_encode( [
"result" => 0,
- "error" => $image->get_error_message()
+ "error" => $image->get_error_message(),
] );
exit;
}
@@ -301,61 +427,57 @@
if ( $is_resized ) {
// working on already resized file, just delete the old file and set
// new file name in meta $size
- $s = $meta["sizes"][$size];
-
- if ( !empty( $s['file'] ) ) {
+ $s = $meta["sizes"][ $size ];
+ if ( ! empty( $s['file'] ) ) {
// delete old resized file
$delete_file = path_join( $dirname, $s['file'] );
wp_delete_file( $delete_file );
-
}
-
} else {
// working on new image, save the new file name in meta and set backup size
$tag = "$size-orig";
- if ( !isset( $meta['sizes'][$size] ) ) {
- $backup_sizes[$tag] = [
+ if ( ! isset( $meta['sizes'][ $size ] ) ) {
+ $backup_sizes[ $tag ] = [
"file" => basename( $meta["file"] ),
"width" => $meta["width"],
- "height" => $meta["height"]
+ "height" => $meta["height"],
];
} else {
- $backup_sizes[$tag] = $meta['sizes'][$size];
+ $backup_sizes[ $tag ] = $meta['sizes'][ $size ];
}
}
- $meta["sizes"][$size] = [
+ $meta["sizes"][ $size ] = [
"file" => $new_filename,
"width" => $saved["width"],
- "height" => $saved["height"]
+ "height" => $saved["height"],
];
if ( $size == "full" && Functions::request( "apply_to_all" ) == "1" ) {
$save_path = $dirname;
- $new_file = $new_path;
+ $new_file = $new_path;
- $sizes = rtcl()->gallery['image_sizes'];
+ $sizes = rtcl()->gallery['image_sizes'];
$size_keys = array_keys( $sizes );
foreach ( $size_keys as $size_key ) {
-
// 1. IF exists delete backup file
// 2. MOVE size to backup_size
// 3. generate new size
// 4. save new size
- if ( !isset( $backup_sizes[$size_key . '-orig'] ) ) {
- $backup_sizes[$size_key . '-orig'] = $meta["sizes"][$size_key];
+ if ( ! isset( $backup_sizes[ $size_key . '-orig' ] ) ) {
+ $backup_sizes[ $size_key . '-orig' ] = $meta["sizes"][ $size_key ];
}
- if ( isset( $meta["sizes"][$size_key] ) ) {
- wp_delete_file( $meta["sizes"][$size_key]["file"] );
+ if ( isset( $meta["sizes"][ $size_key ] ) ) {
+ wp_delete_file( $meta["sizes"][ $size_key ]["file"] );
}
- $cs = $sizes[$size_key];
+ $cs = $sizes[ $size_key ];
$interm_file_name = sprintf( "%s-%dx%d-e%s.png", $file_name, $cs["width"], $cs["height"], $suffix );
$image = wp_get_image_editor( $new_file );
@@ -363,111 +485,164 @@
$file = $image->save( dirname( $new_file ) . "/" . $interm_file_name );
- $meta["sizes"][$size_key] = [
+ $meta["sizes"][ $size_key ] = [
"file" => $file["file"],
"width" => $file["width"],
"height" => $file["height"],
- "mime-type" => $file["mime-type"]
+ "mime-type" => $file["mime-type"],
];
}
-
}
wp_update_attachment_metadata( $attach_id, $meta );
update_post_meta( $attach_id, '_wp_attachment_backup_sizes', $backup_sizes );
$return->result = 1;
- $return->file = Functions::upload_item_data( $attach_id );
+ $return->file = Functions::upload_item_data( $attach_id );
echo wp_json_encode( $return );
exit;
}
function gallery_image_restore() {
- if ( !check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ if ( ! check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( ! is_user_logged_in() && apply_filters( 'rtcl_is_disable_post_for_unregister', true ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Registration required to restore listing image.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( is_user_logged_in() && ( ! current_user_can( 'manage_rtcl_options' ) && ! current_user_can( 'manage_rtcl_listing_images' ) ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" )
+ "error" => __( "You are not allowed to restore listing images.", "classified-listing" ),
] );
exit;
}
- if ( !Functions::user_can_edit_image() ) {
+ if ( ! Functions::user_can_edit_image() ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "You cannot edit images.", "classified-listing" )
+ "error" => __( "You cannot edit images.", "classified-listing" ),
] );
+
exit;
}
- $size = Functions::request( "size" );
+ $size = Functions::request( "size" );
$attach_id = Functions::request( "attach_id" );
- $post_id = intval( Functions::request( "post_id" ) );
+ $post_id = intval( Functions::request( "post_id" ) );
+
+ if ( $post_id > 0 && ! $this->current_user_can_edit_listing( $post_id ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "You do not have permission to restore images for this listing.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
$attach = get_post( $attach_id );
if ( $attach->post_parent != $post_id ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" )
+ "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" ),
] );
exit;
}
if ( $size === "full" ) {
// restore all
- $keys = array_keys( rtcl()->gallery['image_sizes'] );
+ $keys = array_keys( rtcl()->gallery['image_sizes'] );
$restore = array_merge( [ "full" ], $keys );
} else {
$restore = [ str_replace( "_", "-", $size ) ];
}
- $meta = wp_get_attachment_metadata( $attach_id );
+ $meta = wp_get_attachment_metadata( $attach_id );
$attachment_dir = dirname( get_attached_file( $attach_id ) );
- $backup_sizes = get_post_meta( $attach_id, '_wp_attachment_backup_sizes', true );
+ $backup_sizes = get_post_meta( $attach_id, '_wp_attachment_backup_sizes', true );
foreach ( $restore as $r ) {
- if ( isset( $backup_sizes[$r . '-orig'] ) ) {
- wp_delete_file( $attachment_dir . "/" . $meta["sizes"][$r]["file"] );
- $meta["sizes"][$r] = $backup_sizes[$r . '-orig'];
- unset( $backup_sizes[$r . '-orig'] );
+ if ( isset( $backup_sizes[ $r . '-orig' ] ) ) {
+ wp_delete_file( $attachment_dir . "/" . $meta["sizes"][ $r ]["file"] );
+ $meta["sizes"][ $r ] = $backup_sizes[ $r . '-orig' ];
+ unset( $backup_sizes[ $r . '-orig' ] );
}
}
wp_update_attachment_metadata( $attach_id, $meta );
update_post_meta( $attach_id, '_wp_attachment_backup_sizes', $backup_sizes );
- $result = new stdClass();
+ $result = new stdClass();
$result->result = 1;
- $result->file = Functions::upload_item_data( $attach_id );
+ $result->file = Functions::upload_item_data( $attach_id );
echo wp_json_encode( $result );
exit;
}
function gallery_update() {
+ if ( ! check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" ),
+ ] );
- if ( !check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ exit;
+ }
+
+ if ( ! is_user_logged_in() && apply_filters( 'rtcl_is_disable_post_for_unregister', true ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Registration required to update listing image.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ if ( is_user_logged_in() && ( ! current_user_can( 'manage_rtcl_options' ) && ! current_user_can( 'manage_rtcl_listing_images' ) ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" )
+ "error" => __( "You are not allowed to update listing images.", "classified-listing" ),
] );
+
exit;
}
$post_id = intval( $_POST["post_id"] );
+ if ( $post_id > 0 && ! $this->current_user_can_edit_listing( $post_id ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "You do not have permission to update images for this listing.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
$attach_id = intval( $_POST["attach_id"] );
- $caption = trim( Functions::request( "caption", "" ) );
- $content = trim( Functions::request( "content", "" ) );
- $featured = intval( $_POST["featured"] );
+ $caption = trim( Functions::request( "caption", "" ) );
+ $content = trim( Functions::request( "content", "" ) );
+ $featured = intval( $_POST["featured"] );
$attach = get_post( $attach_id );
if ( $attach->post_parent != $post_id ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" )
+ "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" ),
] );
exit;
}
@@ -475,7 +650,7 @@
$result = wp_update_post( [
"ID" => $attach_id,
"post_content" => $content,
- "post_excerpt" => $caption
+ "post_excerpt" => $caption,
] );
if ( $result instanceof WP_Error ) {
@@ -496,41 +671,68 @@
}
function gallery_image_stream() {
+ if ( ! wp_verify_nonce( isset( $_REQUEST[ rtcl()->nonceId ] ) ? $_REQUEST[ rtcl()->nonceId ] : null, rtcl()->nonceText ) && ! check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" ),
+ ] );
- if ( !wp_verify_nonce( isset( $_REQUEST[rtcl()->nonceId] ) ? $_REQUEST[rtcl()->nonceId] : null, rtcl()->nonceText ) && !check_ajax_referer( 'rtcl-gallery', '_ajax_nonce', false ) ) {
+ exit;
+ }
+
+ if ( ! is_user_logged_in() && apply_filters( 'rtcl_is_disable_post_for_unregister', true ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Invalid Session. Please refresh the page and try again.", "classified-listing" )
+ "error" => __( "Registration required to edit listing image.", "classified-listing" ),
] );
+
exit;
}
- if ( !Functions::user_can_edit_image() ) {
+ if ( is_user_logged_in() && ( ! current_user_can( 'manage_rtcl_options' ) && ! current_user_can( 'manage_rtcl_listing_images' ) ) ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "You cannot edit images.", "classified-listing" )
+ "error" => __( "You are not allowed to edit listing images.", "classified-listing" ),
] );
+
exit;
}
- $attach_id = Functions::request( "attach_id" );
+ if ( ! Functions::user_can_edit_image() ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "You cannot edit images.", "classified-listing" ),
+ ] );
+
+ exit;
+ }
+
+ $attach_id = Functions::request( "attach_id" );
$history_encoded = Functions::request( "history" );
- $size = Functions::request( "size" );
- $post_id = absint( Functions::request( "post_id" ) );
+ $size = Functions::request( "size" );
+ $post_id = absint( Functions::request( "post_id" ) );
+
+ if ( $post_id > 0 && ! $this->current_user_can_edit_listing( $post_id ) ) {
+ echo wp_json_encode( [
+ "result" => 0,
+ "error" => __( "You do not have permission to access images for this listing.", "classified-listing" ),
+ ] );
+ exit;
+ }
$attach = get_post( $attach_id );
if ( $attach->post_parent != $post_id ) {
echo wp_json_encode( [
"result" => 0,
- "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" )
+ "error" => __( "Incorrect Post or Attachment ID.", "classified-listing" ),
] );
exit;
}
$history = json_decode( $history_encoded );
- if ( !is_array( $history ) ) {
+ if ( ! is_array( $history ) ) {
$history = [];
}
@@ -543,8 +745,8 @@
}
if ( $size ) {
- $upload = Functions::upload_item_data( $attach_id );
- $attached_file = dirname( $attached_file ) . "/" . basename( $upload["sizes"][$size]["url"] );
+ $upload = Functions::upload_item_data( $attach_id );
+ $attached_file = dirname( $attached_file ) . "/" . basename( $upload["sizes"][ $size ]["url"] );
} else {
$upload = Functions::upload_item_data( $attach_id );
if ( isset( $upload["sizes"]["full"]["is_intermidiate"] ) && $upload["sizes"]["full"]["is_intermidiate"] ) {
@@ -554,25 +756,25 @@
$image = wp_get_image_editor( $attached_file );
- if ( !empty( $history ) ) {
+ if ( ! empty( $history ) ) {
foreach ( $history as $c ) {
- if ( !isset( $c->a ) ) {
+ if ( ! isset( $c->a ) ) {
continue;
}
if ( $c->a == "c" ) {
$image->crop( intval( $c->x ), intval( $c->y ), $c->w, $c->h );
- } else if ( $c->a == "ro" ) {
+ } elseif ( $c->a == "ro" ) {
$image->rotate( $c->v );
- } else if ( $c->a == "re" ) {
+ } elseif ( $c->a == "re" ) {
// resize
$image->resize( $c->w, $c->h );
- } else if ( $c->a == "f" ) {
+ } elseif ( $c->a == "f" ) {
$image->flip( $c->h, $c->v );
}
}
}
- if ( !is_wp_error( $image ) ) {
+ if ( ! is_wp_error( $image ) ) {
$image->stream();
}
--- a/classified-listing/app/Controllers/Ajax/FormBuilderAjax.php
+++ b/classified-listing/app/Controllers/Ajax/FormBuilderAjax.php
@@ -177,7 +177,7 @@
$post_arg['post_author'] = $user_id;
}
} else {
- if ( current_user_can( 'manage_options' ) && !in_array( $listing->get_listing()->post_author, [ apply_filters( 'rtcl_listing_post_user_id', get_current_user_id() ), get_current_user_id() ] ) ) {
+ if ( current_user_can( 'manage_options' ) && ! in_array( $listing->get_listing()->post_author, [ apply_filters( 'rtcl_listing_post_user_id', get_current_user_id() ), get_current_user_id() ] ) ) {
$postingType = 'update';
}
}
@@ -1499,6 +1499,14 @@
return;
}
+ $listing_id = isset( $_POST['listingId'] ) ? absint( $_POST['listingId'] ) : 0;
+
+ if ( ! current_user_can( 'manage_categories' ) && ! apply_filters( 'rtcl_user_can_create_tag', false, $listing_id ) ) {
+ wp_send_json_error( __( "You don't have permission to create tags.", 'classified-listing' ) );
+
+ return;
+ }
+
$tagName = ! empty( $_POST['tag_name'] ) ? sanitize_text_field( $_POST['tag_name'] ) : '';
if ( empty( $tagName ) ) {
wp_send_json_error( __( 'Tag name is required', 'classified-listing' ) );
@@ -1506,6 +1514,29 @@
return;
}
+ // Enforce a sane length limit.
+ $maxLength = apply_filters( 'rtcl_tag_name_max_length', 64 );
+ if ( mb_strlen( $tagName ) > $maxLength ) {
+ wp_send_json_error(
+ /* translators: %d: maximum allowed characters */
+ sprintf( __( 'Tag name must not exceed %d characters.', 'classified-listing' ), $maxLength ),
+ );
+
+ return;
+ }
+
+ // Prevent duplicate tags – return the existing term instead of creating a new one.
+ $existingTerm = term_exists( $tagName, rtcl()->tag );
+ if ( $existingTerm ) {
+ $term = get_term( is_array( $existingTerm ) ? $existingTerm['term_id'] : $existingTerm, rtcl()->tag );
+ if ( $term && ! is_wp_error( $term ) ) {
+ wp_send_json_success( [
+ 'data' => $term,
+ ] );
+
+ return;
+ }
+ }
$newTag = wp_create_term( $tagName, rtcl()->tag );
if ( is_wp_error( $newTag ) ) {
@@ -1515,7 +1546,7 @@
}
$term = get_term( $newTag['term_id'], rtcl()->tag );
- if ( ! $term || is_wp_error( $newTag ) ) {
+ if ( ! $term || is_wp_error( $term ) ) {
wp_send_json_error( __( 'Error while creating new tag.', 'classified-listing' ) );
return;
--- a/classified-listing/app/Controllers/Hooks/TemplateLoader.php
+++ b/classified-listing/app/Controllers/Hooks/TemplateLoader.php
@@ -92,7 +92,7 @@
$default_file = 'single-' . rtcl()->post_type . '.php';
} elseif ( Functions::is_listing_taxonomy() ) {
$object = get_queried_object();
- if ( is_tax( rtcl()->category ) || is_tax( rtcl()->location ) ) {
+ if ( is_tax( rtcl()->category ) || is_tax( rtcl()->location ) || is_tax( rtcl()->tag ) ) {
$default_file = 'taxonomy-' . $object->taxonomy . '.php';
} else {
$default_file = 'archive-' . rtcl()->post_type . '.php';
@@ -174,6 +174,7 @@
if ( $queried_object && isset( $queried_object->taxonomy ) ) {
$queried_tax = $queried_object->taxonomy;
}
+ $tag = '';
switch ( $queried_tax ) {
case 'rtcl_location':
$location = $queried_object->slug;
@@ -183,6 +184,11 @@
$category = $queried_object->slug;
$location = get_query_var( 'rtcl_location' );
break;
+ case 'rtcl_tag':
+ $tag = $queried_object->slug;
+ $category = get_query_var( 'rtcl_category' );
+ $location = get_query_var( 'rtcl_location' );
+ break;
default:
$category = get_query_var( 'rtcl_category' );
$location = get_query_var( 'rtcl_location' );
@@ -196,9 +202,12 @@
'limit' => apply_filters( 'rtcl_loop_listing_per_page', Functions::get_option_item( 'rtcl_archive_listing_settings', 'listings_per_page' ) )
];
- if ( Functions::is_listing_category() || Functions::is_listing_location() ) {
+ if ( Functions::is_listing_category() || Functions::is_listing_location() || Functions::is_listing_tag() ) {
$shortcode_args['category'] = $category;
$shortcode_args['location'] = $location;
+ if ( $tag ) {
+ $shortcode_args['tag'] = $tag;
+ }
} else {
// Default theme archive for all other taxonomies.
return;
--- a/classified-listing/app/Helpers/Functions.php
+++ b/classified-listing/app/Helpers/Functions.php
@@ -358,6 +358,17 @@
}
/**
+ * Check is Listing Tag archive page
+ *
+ * @param string $term
+ *
+ * @return bool
+ */
+ public static function is_listing_tag( $term = '' ) {
+ return is_tax( rtcl()->tag, $term );
+ }
+
+ /**
* Is_ajax - Returns true when the page is loaded via ajax.
*
* @return bool
--- a/classified-listing/app/Helpers/Upgrade.php
+++ b/classified-listing/app/Helpers/Upgrade.php
@@ -6,46 +6,50 @@
use RtclModelsRoles;
-class Upgrade
-{
+class Upgrade {
- static function init() {
- add_action('init', [__CLASS__, 'run_upgrade']);
- }
+ static function init() {
+ add_action( 'init', [ __CLASS__, 'run_upgrade' ] );
+ }
- public static function run_upgrade() {
+ public static function run_upgrade() {
// self::upgrade_to_1_5_5();
// self::upgrade_to_1_5_59();
- }
+ self::upgrade_to_5_3_10();
+ }
- public static function upgrade_to_1_5_59() {
- $old_version = get_option('rtcl_pro_version');
- if ($old_version && version_compare($old_version, '1.5.59') < 0) {
- Roles::remove_default_caps();
- Roles::create_roles();
- update_option('rtcl_queue_flush_rewrite_rules', 'yes');
- self::update_rtcl_version('1.5.59');
- }
- }
-
- public static function upgrade_to_1_5_5() {
- $old_version = get_option('rtcl_pro_version');
- if ($old_version && version_compare($old_version, '1.5.5') < 0) {
- if ($listings_page_id = Functions::get_page_id('listings')) {
- $my_post = array(
- 'ID' => $listings_page_id,
- 'post_content' => ''
- );
- wp_update_post($my_post);
- }
- update_option('rtcl_queue_flush_rewrite_rules', 'yes');
- self::update_rtcl_version('1.5.5');
- }
- }
-
- static function update_rtcl_version($version = '') {
- $version = $version ?: RTCL_VERSION;
- delete_option('rtcl_pro_version');
- add_option('rtcl_pro_version', $version);
- }
+ public static function upgrade_to_5_3_10() {
+ Roles::add_listing_gallery_caps();
+ }
+
+ public static function upgrade_to_1_5_59() {
+ $old_version = get_option( 'rtcl_pro_version' );
+ if ( $old_version && version_compare( $old_version, '1.5.59' ) < 0 ) {
+ Roles::remove_default_caps();
+ Roles::create_roles();
+ update_option( 'rtcl_queue_flush_rewrite_rules', 'yes' );
+ self::update_rtcl_version( '1.5.59' );
+ }
+ }
+
+ public static function upgrade_to_1_5_5() {
+ $old_version = get_option( 'rtcl_pro_version' );
+ if ( $old_version && version_compare( $old_version, '1.5.5' ) < 0 ) {
+ if ( $listings_page_id = Functions::get_page_id( 'listings' ) ) {
+ $my_post = [
+ 'ID' => $listings_page_id,
+ 'post_content' => '',
+ ];
+ wp_update_post( $my_post );
+ }
+ update_option( 'rtcl_queue_flush_rewrite_rules', 'yes' );
+ self::update_rtcl_version( '1.5.5' );
+ }
+ }
+
+ static function update_rtcl_version( $version = '' ) {
+ $version = $version ?: RTCL_VERSION;
+ delete_option( 'rtcl_pro_version' );
+ add_option( 'rtcl_pro_version', $version );
+ }
}
No newline at end of file
--- a/classified-listing/app/Models/Roles.php
+++ b/classified-listing/app/Models/Roles.php
@@ -4,431 +4,430 @@
use WP_Roles;
-class Roles
-{
+class Roles {
- /**
- * Create roles and capabilities.
- */
- public static function create_roles() {
- global $wp_roles;
-
- if (!class_exists('WP_Roles')) {
- return;
- }
-
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
- }
-
- // Dummy gettext calls to get strings in the catalog.
- _x('Listing manager', 'User role', 'classified-listing');
-
-
- // Shop manager role.
- add_role(
- 'rtcl_manager',
- 'Listing Manager',
- array(
- 'level_9' => true,
- 'level_8' => true,
- 'level_7' => true,
- 'level_6' => true,
- 'level_5' => true,
- 'level_4' => true,
- 'level_3' => true,
- 'level_2' => true,
- 'level_1' => true,
- 'level_0' => true,
- 'read' => true,
- 'read_private_pages' => true,
- 'read_private_posts' => true,
- 'edit_posts' => true,
- 'edit_pages' => true,
- 'edit_published_posts' => true,
- 'edit_published_pages' => true,
- 'edit_private_pages' => true,
- 'edit_private_posts' => true,
- 'edit_others_posts' => true,
- 'edit_others_pages' => true,
- 'publish_posts' => true,
- 'publish_pages' => true,
- 'delete_posts' => true,
- 'delete_pages' => true,
- 'delete_private_pages' => true,
- 'delete_private_posts' => true,
- 'delete_published_pages' => true,
- 'delete_published_posts' => true,
- 'delete_others_posts' => true,
- 'delete_others_pages' => true,
- 'manage_categories' => true,
- 'manage_links' => true,
- 'moderate_comments' => true,
- 'upload_files' => true,
- 'export' => true,
- 'import' => true,
- 'list_users' => true,
- 'edit_theme_options' => true,
- )
- );
-
- $capabilities = self::get_core_caps();
-
- foreach ($capabilities as $cap_group) {
- foreach ($cap_group as $cap) {
- $wp_roles->add_cap('rtcl_manager', $cap);
- $wp_roles->add_cap('administrator', $cap);
- }
- }
- }
-
- /**
- * Remove Classified Listing roles.
- */
- public static function remove_roles() {
- global $wp_roles;
-
- if (!class_exists('WP_Roles')) {
- return;
- }
-
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
- }
-
- $capabilities = self::get_core_caps();
-
- foreach ($capabilities as $cap_group) {
- foreach ($cap_group as $cap) {
- $wp_roles->remove_cap('rtcl_manager', $cap);
- $wp_roles->remove_cap('administrator', $cap);
- }
- }
-
- remove_role('rtcl_manager');
- }
-
- public static function add_default_caps() {
- global $wp_roles;
-
- if (class_exists('WP_Roles')) {
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles();
- }
- }
-
- if (is_object($wp_roles)) {
-
- // Add the "administrator" capabilities
- $capabilities = self::get_core_caps();
- foreach ($capabilities as $cap_group) {
- foreach ($cap_group as $cap) {
- $wp_roles->add_cap('administrator', $cap);
- }
- }
-
- // Add Default caps
- $role_caps = self::get_roles_default_caps();
-
- foreach ($role_caps as $role => $caps) {
- if (is_array($caps) && !empty($caps)) {
- foreach ($caps as $cap) {
- $wp_roles->add_cap($role, $cap);
- }
- }
- // Add extra role caps with specific role
- do_action('rtcl_roles_add_default_caps_' . $role, $wp_roles, rtcl()->post_type);
- }
-
- // Add extra work when rtcl role is
- do_action('rtcl_roles_add_default_caps', $wp_roles, rtcl()->post_type);
- }
- }
-
- /**
- * @param array | string $roles
- */
- public static function add_core_caps($roles) {
- if (empty($roles)) {
- return;
- }
-
- $roles = is_array($roles) ? $roles : [$roles];
-
- global $wp_roles;
-
- if (class_exists('WP_Roles')) {
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles();
- }
- }
-
- if (is_object($wp_roles)) {
- foreach ($roles as $role) {
- $capabilities = self::get_core_caps();
- foreach ($capabilities as $cap_group) {
- foreach ($cap_group as $cap) {
- $wp_roles->add_cap($role, $cap);
- }
- }
- }
- }
- }
-
- public static function remove_code_caps($roles) {
- if (empty($roles)) {
- return;
- }
-
- $roles = is_array($roles) ? $roles : [$roles];
-
- global $wp_roles;
-
- if (class_exists('WP_Roles')) {
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles();
- }
- }
-
- if (is_object($wp_roles)) {
- foreach ($roles as $role) {
- $capabilities = self::get_core_caps();
- foreach ($capabilities as $cap_group) {
- foreach ($cap_group as $cap) {
- $wp_roles->remove_cap($role, $cap);
- }
- }
- }
- }
- }
-
- public static function get_core_caps() {
-
- $capabilities = array();
- $capabilities['core'] = ['manage_rtcl_options', 'manage_rtcl_reports', 'manage_rtcl_store'];
- $capability_types = ['rtcl_listing', 'rtcl_pricing', 'rtcl_payment'];
-
- foreach ($capability_types as $capability_type) {
-
- $capabilities[$capability_type] = array(
- "add_{$capability_type}",
- "edit_{$capability_type}",
- "read_{$capability_type}",
- "delete_{$capability_type}",
- "edit_{$capability_type}s",
- "edit_others_{$capability_type}s",
- "publish_{$capability_type}s",
- "read_private_{$capability_type}s",
- "delete_{$capability_type}s",
- "delete_private_{$capability_type}s",
- "delete_published_{$capability_type}s",
- "delete_others_{$capability_type}s",
- "edit_private_{$capability_type}s",
- "edit_published_{$capability_type}s",
- );
- }
-
- return apply_filters('rtcl_roles_get_core_caps', $capabilities);
- }
-
- public static function get_roles_default_caps() {
-
- $caps = [
- 'editor' => [
- 'add_' . rtcl()->post_type,
- 'edit_' . rtcl()->post_type . 's',
- 'edit_others_' . rtcl()->post_type . 's',
- 'publish_' . rtcl()->post_type . 's',
- 'read_private_' . rtcl()->post_type . 's',
- 'delete_' . rtcl()->post_type . 's',
- 'delete_private_' . rtcl()->post_type . 's',
- 'delete_published_' . rtcl()->post_type . 's',
- 'delete_others_' . rtcl()->post_type . 's',
- 'edit_private_' . rtcl()->post_type . 's',
- 'edit_published_' . rtcl()->post_type . 's',
- ],
- 'author' => [
- 'add_' . rtcl()->post_type,
- 'edit_' . rtcl()->post_type . 's',
- 'publish_' . rtcl()->post_type . 's',
- 'delete_' . rtcl()->post_type . 's',
- 'delete_published_' . rtcl()->post_type . 's',
- 'edit_published_' . rtcl()->post_type . 's',
- ],
- 'contributor' => [
- 'add_' . rtcl()->post_type,
- 'edit_' . rtcl()->post_type . 's',
- 'publish_' . rtcl()->post_type . 's',
- 'delete_' . rtcl()->post_type . 's',
- 'delete_published_' . rtcl()->post_type . 's',
- 'edit_published_' . rtcl()->post_type . 's',
- ],
- 'subscriber' => [
- 'add_' . rtcl()->post_type,
- 'edit_' . rtcl()->post_type . 's',
- 'publish_' . rtcl()->post_type . 's',
- 'delete_' . rtcl()->post_type . 's',
- 'delete_published_' . rtcl()->post_type . 's',
- 'edit_published_' . rtcl()->post_type . 's',
- ]
- ];
-
- return apply_filters('rtcl_roles_get_roles_default_caps', $caps);
- }
-
- public static function get_default_caps() {
- $caps = [
- 'add_' . rtcl()->post_type,
- 'edit_' . rtcl()->post_type . 's',
- 'publish_' . rtcl()->post_type . 's',
- 'delete_' . rtcl()->post_type . 's',
- 'delete_published_' . rtcl()->post_type . 's',
- 'edit_published_' . rtcl()->post_type . 's',
- ];
-
- return apply_filters('rtcl_roles_get_default_caps', $caps);
- }
-
- /**
- * @param array | string $roles
- */
- public static function add_custom_caps($roles) {
- if (empty($roles)) {
- return;
- }
-
- $roles = is_array($roles) ? $roles : [$roles];
-
- global $wp_roles;
-
- if (class_exists('WP_Roles')) {
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles();
- }
- }
-
- if (is_object($wp_roles)) {
- $caps = self::get_default_caps();
- foreach ($roles as $role) {
- if (is_array($caps) && !empty($caps)) {
- foreach ($caps as $cap) {
- $wp_roles->add_cap($role, $cap);
- }
- }
- }
- }
-
- }
-
-
- /**
- * @param array | string $roles
- */
- public static function remove_custom_caps($roles) {
- if (!$roles) {
- return;
- }
-
- $roles = is_array($roles) ? $roles : [$roles];
-
- global $wp_roles;
-
- if (class_exists('WP_Roles')) {
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles();
- }
- }
-
- if (is_object($wp_roles)) {
- $caps = self::get_default_caps();
- foreach ($roles as $role) {
- if (is_array($caps) && !empty($caps)) {
- foreach ($caps as $cap) {
- $wp_roles->remove_cap($role, $cap);
- }
- }
- }
- }
-
- }
-
- public static function meta_caps($caps, $cap, $user_id, $args) {
-
- // If editing, deleting, or reading a listing, get the post and post type object.
- if ('edit_' . rtcl()->post_type == $cap || 'delete_' . rtcl()->post_type == $cap || 'read_' . rtcl()->post_type == $cap) {
- $post = get_post($args[0]);
- $post_type = get_post_type_object($post->post_type);
-
- // Set an empty array for the caps.
- $caps = array();
- }
-
- // If editing a listing, assign the required capability.
- if ('edit_' . rtcl()->post_type == $cap) {
- if ($user_id == $post->post_author) {
- $caps[] = $post_type->cap->edit_listings;
- } else {
- $caps[] = $post_type->cap->edit_others_listings;
- }
- } // If deleting a listing, assign the required capability.
- else if ('delete_' . rtcl()->post_type == $cap) {
- if ($user_id == $post->post_author) {
- $caps[] = $post_type->cap->delete_listings;
- } else {
- $caps[] = $post_type->cap->delete_others_listings;
- }
- } // If reading a private listing, assign the required capability.
- else if ('read_' . rtcl()->post_type == $cap) {
- if ('private' != $post->post_status) {
- $caps[] = 'read';
- } elseif ($user_id == $post->post_author) {
- $caps[] = 'read';
- } else {
- $caps[] = $post_type->cap->read_private_listings;
- }
- }
-
- // Return the capabilities required by the user.
- return $caps;
-
- }
-
- public static function remove_default_caps() {
-
- global $wp_roles;
-
- if (class_exists('WP_Roles')) {
- if (!isset($wp_roles)) {
- $wp_roles = new WP_Roles();
- }
- }
-
- if (is_object($wp_roles)) {
-
- // Remove the "administrator" Capabilities
- $capabilities = self::get_core_caps();
-
- foreach ($capabilities as $cap_group) {
- foreach ($cap_group as $cap) {
- $wp_roles->remove_cap('administrator', $cap);
- }
- }
-
- // Remove Default caps
- $role_caps = self::get_roles_default_caps();
-
- foreach ($role_caps as $role => $caps) {
- if (is_array($caps) && !empty($caps)) {
- foreach ($caps as $cap) {
- $wp_roles->remove_cap($role, $cap);
- }
- }
- // Remove extra role caps with specific role
- do_action('rtcl_roles_remove_default_caps_' . $role, $wp_roles, rtcl()->post_type);
- }
-
- // Remove extra work when rtcl role is remove cap
- do_action('rtcl_roles_remove_default_caps', $wp_roles, rtcl()->post_type);
- }
- }
+ /**
+ * Create roles and capabilities.
+ */
+ public static function create_roles() {
+ global $wp_roles;
+
+ if ( ! class_exists( 'WP_Roles' ) ) {
+ return;
+ }
+
+ if ( ! isset( $wp_roles ) ) {
+ $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
+ }
+
+ // Dummy gettext calls to get strings in the catalog.
+ _x( 'Listing manager', 'User role', 'classified-listing' );
+
+ // Gallery upload capability.
+ self::add_listing_gallery_caps();
+
+ // Shop manager role.
+ add_role(
+ 'rtcl_manager',
+ 'Listing Manager',
+ [
+ 'level_9' => true,
+ 'level_8' => true,
+ 'level_7' => true,
+ 'level_6' => true,
+ 'level_5' => true,
+ 'level_4' => true,
+ 'level_3' => true,
+ 'level_2' => true,
+ 'level_1' => true,
+ 'level_0' => true,
+ 'read' => true,
+ 'read_private_pages' => true,
+ 'read_private_posts' => true,
+ 'edit_posts' => true,
+ 'edit_pages' => true,
+ 'edit_published_posts' => true,
+ 'edit_published_pages' => true,
+ 'edit_private_pages' => true,
+ 'edit_private_posts' => true,
+ 'edit_others_posts' => true,
+ 'edit_others_pages' => true,
+ 'publish_posts' => true,
+ 'publish_pages' => true,
+ 'delete_posts' => true,
+ 'delete_pages' => true,
+ 'delete_private_pages' => true,
+ 'delete_private_posts' => true,
+ 'delete_published_pages' => true,
+ 'delete_published_posts' => true,
+ 'delete_others_posts' => true,
+ 'delete_others_pages' => true,
+ 'manage_categories' => true,
+ 'manage_links' => true,
+ 'moderate_comments' => true,
+ 'upload_files' => true,
+ 'export' => true,
+ 'import' => true,
+ 'list_users' => true,
+ 'edit_theme_options' => true,
+ ],
+ );
+
+ $capabilities = self::get_core_caps();
+
+ foreach ( $capabilities as $cap_group ) {
+ foreach ( $cap_group as $cap ) {
+ $wp_roles->add_cap( 'rtcl_manager', $cap );
+ $wp_roles->add_cap( 'administrator', $cap );
+ }
+ }
+ }
+
+ public static function add_listing_gallery_caps() {
+ $role = get_role( 'subscriber' );
+
+ if ( $role && ! $role->has_cap( 'manage_rtcl_listing_images' ) ) {
+ $role->add_cap( 'manage_rtcl_listing_images' );
+ }
+ }
+
+ /**
+ * Remove Classified Listing roles.
+ */
+ public static function remove_roles() {
+ global $wp_roles;
+
+ if ( ! class_exists( 'WP_Roles' ) ) {
+ return;
+ }
+
+ if ( ! isset( $wp_roles ) ) {
+ $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
+ }
+
+ $capabilities = self::get_core_caps();
+
+ foreach ( $capabilities as $cap_group ) {
+ foreach ( $cap_group as $cap ) {
+ $wp_roles->remove_cap( 'rtcl_manager', $cap );
+ $wp_roles->remove_cap( 'administrator', $cap );
+ }
+ }
+
+ remove_role( 'rtcl_manager' );
+ }
+
+ public static function add_default_caps() {
+ global $wp_roles;
+
+ if ( class_exists( 'WP_Roles' ) ) {
+ if ( ! isset( $wp_roles ) ) {
+ $wp_roles = new WP_Roles();
+ }
+ }
+
+ if ( is_object( $wp_roles ) ) {
+ // Add the "administrator" capabilities
+ $capabilities = self::get_core_caps();
+ foreach ( $capabilities as $cap_group ) {
+ foreach ( $cap_group as $cap ) {
+ $wp_roles->add_cap( 'administrator', $cap );
+ }
+ }
+
+ // Add Default caps
+ $role_caps = self::get_roles_default_caps();
+
+ foreach ( $role_caps as $role => $caps ) {
+ if ( is_array( $caps ) && ! empty( $caps ) ) {
+ foreach ( $caps as $cap ) {
+ $wp_roles->add_cap( $role, $cap );
+ }
+ }
+ // Add extra role caps with specific role
+ do_action( 'rtcl_roles_add_default_caps_' . $role, $wp_roles, rtcl()->post_type );
+ }
+
+ // Add extra work when rtcl role is
+ do_action( 'rtcl_roles_add_default_caps', $wp_roles, rtcl()->post_type );
+ }
+ }
+
+ /**
+ * @param array | string $roles
+ */
+ public static function add_core_caps( $roles ) {
+ if ( empty( $roles ) ) {
+ return;
+ }
+
+ $roles = is_array( $roles ) ? $roles : [ $roles ];
+
+ global $wp_roles;
+
+ if ( class_exists( 'WP_Roles' ) ) {
+ if ( ! isset( $wp_roles ) ) {
+ $wp_roles = new WP_Roles();
+ }
+ }
+
+ if ( is_object( $wp_roles ) ) {
+ foreach ( $roles as $role ) {
+ $capabilities = self::get_core_caps();
+ foreach ( $capabilities as $cap_group ) {
+ foreach ( $cap_group as $cap ) {
+ $wp_roles->add_cap( $role, $cap );
+ }
+ }
+ }
+ }
+ }
+
+ public static function remove_code_caps( $roles ) {
+ if ( empty( $roles ) ) {
+ return;
+ }
+
+ $roles = is_array( $roles ) ? $roles : [ $roles ];
+
+ global $wp_roles;
+
+ if ( class_exists( 'WP_Roles' ) ) {
+ if ( ! isset( $wp_roles ) ) {
+ $wp_roles = new WP_Roles();
+ }
+ }
+
+ if ( is_object( $wp_roles ) ) {
+ foreach ( $roles as $role ) {
+ $capabilities = self::get_core_caps();
+ foreach ( $capabilities as $cap_group ) {
+ foreach ( $cap_group as $cap ) {
+ $wp_roles->remove_cap( $role, $cap );
+ }
+ }
+ }
+ }
+ }
+
+ public static function get_core_caps() {
+ $capabilities = [];
+ $capabilities['core'] = [ 'manage_rtcl_options', 'manage_rtcl_reports', 'manage_rtcl_store' ];
+ $capability_types = [ 'rtcl_listing', 'rtcl_pricing', 'rtcl_payment' ];
+
+ foreach ( $capability_types as $capability_type ) {
+ $capabilities[ $capability_type ] = [
+ "add_{$capability_type}",
+ "edit_{$capability_type}",
+ "read_{$capability_type}",
+ "delete_{$capability_type}",
+ "edit_{$capability_type}s",
+ "edit_others_{$capability_type}s",
+ "publish_{$capability_type}s",
+ "read_private_{$capability_type}s",
+ "delete_{$capability_type}s",
+ "delete_private_{$capability_type}s",
+ "delete_published_{$capability_type}s",
+ "delete_others_{$capability_type}s",
+ "edit_private_{$capability_type}s",
+ "edit_published_{$capability_type}s",
+ ];
+ }
+
+ return apply_filters( 'rtcl_roles_get_core_caps', $capabilities );
+ }
+
+ public static function get_roles_default_caps() {
+ $caps = [
+ 'editor' => [
+ 'add_' . rtcl()->post_type,
+ 'edit_' . rtcl()->post_type . 's',
+ 'edit_others_' . rtcl()->post_type . 's',
+ 'publish_' . rtcl()->post_type . 's',
+ 'read_private_' . rtcl()->post_type . 's',
+ 'delete_' . rtcl()->post_type . 's',
+ 'delete_private_' . rtcl()->post_type . 's',
+ 'delete_published_' . rtcl()->post_type . 's',
+ 'delete_others_' . rtcl()->post_type . 's',
+ 'edit_private_' . rtcl()->post_type . 's',
+ 'edit_published_' . rtcl()->post_type . 's',
+ ],
+ 'author' => [
+ 'add_' . rtcl()->post_type,
+ 'edit_' . rtcl()->post_type . 's',
+ 'publish_' . rtcl()->post_type . 's',
+ 'delete_' . rtcl()->post_type . 's',
+ 'delete_published_' . rtcl()->post_type . 's',
+ 'edit_published_' . rtcl()->post_type . 's',
+ ],
+ 'contributor' => [
+ 'add_' . rtcl()->post_type,
+ 'edit_' . rtcl()->post_type . 's',
+ 'publish_' . rtcl()->post_type . 's',
+ 'delete_' . rtcl()->post_type . 's',
+ 'delete_published_' . rtcl()->post_type . 's',
+ 'edit_published_' . rtcl()->post_type . 's',
+ ],
+ 'subscriber' => [
+ 'add_' . rtcl()->post_type,
+ 'edit_' . rtcl()->post_type . 's',
+ 'publish_' . rtcl()->post_type . 's',
+ 'delete_' . rtcl()->post_type . 's',
+ 'delete_published_' . rtcl()->post_type . 's',
+ 'edit_published_' . rtcl()->post_type . 's',
+ ],
+ ];
+
+ return apply_filters( 'rtcl_roles_get_roles_default_caps', $caps );
+ }
+
+ public static function get_default_caps() {
+ $caps = [
+ 'add_' . rtcl()->post_type,
+ 'edit_' . rtcl()->po