Published : August 14, 2026

CVE-2026-16586: Contest Gallery ‘cgRealId’ PoC, Patch Analysis & Rule

Severity Medium (CVSS 6.5)
CWE 89
Vulnerable Version 30.0.7
Patched Version 31.0.0
Disclosed August 13, 2026

Analysis Overview

Atomic Edge analysis of CVE-2026-16586: This vulnerability allows authenticated attackers with author-level access to perform second-order SQL injection through the ‘cg_multiple_files_for_post’ AJAX action, leading to the ‘cgRealId’ parameter. The flaw exists in Contest Gallery versions up to and including 30.0.7. The attack can extract sensitive database information, and the severity is rated as 6.5 (Medium).

The root cause lies in the ‘contest-gallery/ajax/ajax-functions-backend.php’ file, specifically in the ‘post_cg_multiple_files_for_post’ function and its related database queries. The code retrieves the ‘realId’ from the ‘cgRealId’ POST parameter and uses it in multiple SQL queries without proper preparation. The vulnerable code includes direct string concatenation into SQL statements, such as “SELECT * FROM $tablename WHERE id=’$realId'” and “UPDATE $tablename SET MultipleFiles=’$MultipleFilesNew’ WHERE id = $realId”. The ‘cgMultipleFilesForPost’ data is also processed and serialized without escaping, allowing a malicious value to persist and then trigger the second-order injection. The patch adds proper escaping using ‘absint()’ and replaces direct queries with ‘$wpdb->prepare()’ statements.

To exploit this vulnerability, an attacker with author-level access authenticates to the WordPress admin and sends a crafted AJAX request to ‘admin-ajax.php’ with the ‘action’ parameter set to ‘post_cg_multiple_files_for_post’. The attacker includes a ‘cgRealId’ parameter containing a SQL injection payload, such as a value that breaks out of the current query and appends additional SQL statements. Additionally, the attacker can manipulate the ‘cgMultipleFilesForPost’ parameter to store a serialized payload that, when later processed, injects SQL into the ‘MultipleFiles’ UPDATE query. The lack of nonce validation and insufficient input sanitization makes this possible.

The patch introduces several critical fixes. It adds ‘absint()’ to sanitize ‘WpUpload’ and ‘realId’ variables before they are used in SQL queries. It replaces all direct SQL string concatenation with ‘$wpdb->prepare()’ calls, ensuring that numeric values are safely cast and string values are properly escaped. The patch also adds ‘cg_require_backend_access()’ and ‘cg_check_nonce()’ to various backend AJAX handlers, enforcing proper authentication and CSRF protection. Furthermore, the patch adds validation to ‘cgRealId’ and ‘WpUpload’ by casting them to absolute integers, preventing malicious payloads from entering the SQL queries.

Exploiting this vulnerability allows an authenticated attacker with author-level access to perform SQL injection attacks. The attacker can extract sensitive information from the WordPress database, including user credentials, API keys, and other confidential data. The second-order nature of the attack means the injection payload is stored during one request and then triggered during a subsequent legitimate update, making it more difficult to detect. A successful exploit can lead to complete database compromise, enabling privilege escalation, data manipulation, and potentially remote code execution if database access is combined with other vulnerabilities.

Differential between vulnerable and patched code

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

Code Diff
--- a/contest-gallery/ajax/ajax-functions-backend.php
+++ b/contest-gallery/ajax/ajax-functions-backend.php
@@ -38,6 +38,8 @@
     }
 }

+include_once(__DIR__.'/../v10/v10-admin/export/user-data-export-jobs.php');
+
 if (!function_exists('cg_backend_ajax_validate_gallery_hash_json')) {
     function cg_backend_ajax_validate_gallery_hash_json($GalleryID, $galleryHash) {
         $GalleryID = absint($GalleryID);
@@ -125,6 +127,11 @@
             'error' => ''
         ];

+        if (cg_get_version() == 'contest-gallery') {
+            $result['error'] = 'pdf_preview_not_available';
+            return $result;
+        }
+
         $wp_upload_dir = wp_upload_dir();
         $cgWpUploadToReplace = 0;
         $cgNewWpUploadWhichReplace = 0;
@@ -134,6 +141,8 @@
         if (empty($realId)) {
             $realId = (!empty($_POST['cgRealId'])) ? absint($_POST['cgRealId']) : 0;
         }
+        $WpUpload = absint($WpUpload);
+        $realId = absint($realId);
         if (empty($cg_base_64)) {
             $cg_base_64 = (!empty($_POST['cg_base_64'])) ? $_POST['cg_base_64'] : '';
         }
@@ -149,21 +158,21 @@
             return $result;
         }

-        $realIdRow = $wpdb->get_row("SELECT * FROM $tablename WHERE id='$realId'");
+        $realIdRow = $wpdb->get_row($wpdb->prepare("SELECT * FROM $tablename WHERE id = %d", $realId));
         if (empty($realIdRow)) {
             $result['error'] = 'missing_real_id_row';
             return $result;
         }

-        $WpUploadRow = $wpdb->get_row("SELECT * FROM $tablename_posts WHERE ID='$WpUpload'");
+        $WpUploadRow = $wpdb->get_row($wpdb->prepare("SELECT * FROM $tablename_posts WHERE ID = %d", $WpUpload));
         if (empty($WpUploadRow)) {
             $result['error'] = 'missing_wp_upload_row';
             return $result;
         }

         if (!empty($cgWpUploadToReplace) && !empty($cgNewWpUploadWhichReplace) && !empty($realIdRow->EcommerceEntry)) {
-            $EcommerceEntry = $realIdRow->EcommerceEntry;
-            $ecommerceEntry = $wpdb->get_row("SELECT * FROM $tablename_ecommerce_entries WHERE id='$EcommerceEntry'");
+            $EcommerceEntry = absint($realIdRow->EcommerceEntry);
+            $ecommerceEntry = $wpdb->get_row($wpdb->prepare("SELECT * FROM $tablename_ecommerce_entries WHERE id = %d", $EcommerceEntry));
             $removedWpUploadIdsFromSale = [$cgWpUploadToReplace];
             cg_replace_ecommerce_file($realIdRow->id, $realIdRow->GalleryID, $ecommerceEntry, $cgNewWpUploadWhichReplace, [], $removedWpUploadIdsFromSale);
         }
@@ -307,9 +316,17 @@
                     $MultipleFilesNew[$order] = $file;
                 }
                 $MultipleFilesNew = serialize($MultipleFilesNew);
-                $wpdb->query("UPDATE $tablename SET MultipleFiles='$MultipleFilesNew' WHERE id = $realId");
+                $wpdb->query($wpdb->prepare(
+                    "UPDATE $tablename SET MultipleFiles = %s WHERE id = %d",
+                    $MultipleFilesNew,
+                    $realId
+                ));
             } else {
-                $wpdb->query("UPDATE $tablename SET PdfPreview=$attach_id WHERE id = $realId");
+                $wpdb->query($wpdb->prepare(
+                    "UPDATE $tablename SET PdfPreview = %d WHERE id = %d",
+                    $attach_id,
+                    $realId
+                ));
             }

             if (!$isFromFrontendUpload && !empty($realIdRow->Active)) {
@@ -319,13 +336,19 @@
                 $thumbSizesWp['medium_size_w'] = get_option("medium_size_w");
                 $thumbSizesWp['large_size_w'] = get_option("large_size_w");
                 $imageArray = array();
-                $pid = $realIdRow->id;
-                $GalleryID = $realIdRow->GalleryID;
-                $row = $wpdb->get_row("SELECT DISTINCT $tablename_posts.*, $tablename.* FROM $tablename_posts, $tablename WHERE
-                          (($tablename.id = $pid) AND $tablename.GalleryID='$GalleryID' AND $tablename.Active='1' and $tablename_posts.ID = $tablename.WpUpload)
+                $pid = absint($realIdRow->id);
+                $GalleryID = absint($realIdRow->GalleryID);
+                $row = $wpdb->get_row($wpdb->prepare(
+                    "SELECT DISTINCT $tablename_posts.*, $tablename.* FROM $tablename_posts, $tablename WHERE
+                          (($tablename.id = %d) AND $tablename.GalleryID = %d AND $tablename.Active = '1' and $tablename_posts.ID = $tablename.WpUpload)
                           OR
-                          (($tablename.id = $pid) AND $tablename.GalleryID='$GalleryID' AND $tablename.Active='1' AND $tablename.WpUpload = 0)
-                          GROUP BY $tablename.id  ORDER BY $tablename.id DESC LIMIT 0, 1");
+                          (($tablename.id = %d) AND $tablename.GalleryID = %d AND $tablename.Active = '1' AND $tablename.WpUpload = 0)
+                          GROUP BY $tablename.id ORDER BY $tablename.id DESC LIMIT 0, 1",
+                    $pid,
+                    $GalleryID,
+                    $pid,
+                    $GalleryID
+                ));
                 cg_create_json_files_when_activating($GalleryID, $row, $thumbSizesWp, $uploadFolder, $imageArray);
             }

@@ -633,6 +656,7 @@
 if (!function_exists('post_cg_gallery_view_control_backend')) {
     function post_cg_gallery_view_control_backend()
     {
+        cg_require_backend_access();

         contest_gal1ery_db_check();

@@ -711,6 +735,8 @@
 if (!function_exists('post_cg_gallery_save_categories_changes')) {
     function post_cg_gallery_save_categories_changes()
     {
+        cg_require_backend_access();
+
         contest_gal1ery_db_check();

         $isBackendCall = true;
@@ -744,6 +770,8 @@
 if (!function_exists('post_cg_change_invoice')) {
     function post_cg_change_invoice()
     {
+        cg_require_backend_access();
+
         contest_gal1ery_db_check();

         $isBackendCall = true;
@@ -783,6 +811,8 @@
 if (!function_exists('post_cg_twitter_get')) {
     function post_cg_twitter_get()
     {
+        cg_require_backend_access();
+
         //contest_gal1ery_db_check();

 	    $_POST = cg1l_sanitize_post($_POST);
@@ -814,14 +844,15 @@
 	            //curl_setopt($ch, CURLOPT_URL, "https://publish.twitter.com/oembed?theme=dark&url=".$post_cg_twitter_url);
 	            curl_setopt($ch, CURLOPT_URL, "https://publish.twitter.com/oembed?url=".$post_cg_twitter_url);
 	            curl_setopt($ch, CURLOPT_HEADER, false);
-	            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+	            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+	            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
 	            curl_setopt($ch, CURLOPT_SSLVERSION , 6); //NEW ADDITION
 	            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 	            $result = curl_exec($ch);
-	            curl_close($ch);
+	            $curlErrorNumber = curl_errno($ch);
 	            $error_msg = curl_error($ch);
-	            if (curl_errno($ch)) {
-		            $error_msg = curl_error($ch);
+	            curl_close($ch);
+	            if ($curlErrorNumber) {
 		            $result = '';
 	            }else{
 		            $result = str_replace('n', '', $result);
@@ -855,6 +886,8 @@
 if (!function_exists('post_cg_social_platform_input')) {
     function post_cg_social_platform_input()
     {
+        cg_require_backend_access();
+
         contest_gal1ery_db_check();

         $blockquote = '';
@@ -969,6 +1002,7 @@
 if (!function_exists('post_cg_social_platforms_query')) {
     function post_cg_social_platforms_query()
     {
+	    cg_require_backend_access();

 	    contest_gal1ery_db_check();

@@ -1011,6 +1045,7 @@
 if (!function_exists('post_cg_social_platforms_add_to_gallery')) {
     function post_cg_social_platforms_add_to_gallery()
     {
+	    cg_require_backend_access();

 	    contest_gal1ery_db_check();

@@ -1113,6 +1148,7 @@
 if (!function_exists('post_cg_gallery_sort_files')) {
     function post_cg_gallery_sort_files()
     {
+        cg_require_backend_access();

         contest_gal1ery_db_check();

@@ -1421,47 +1457,41 @@
 if (!function_exists('post_cg_test_ecom_keys')) {
     function post_cg_test_ecom_keys()
     {
-        contest_gal1ery_db_check();
-
-        if (defined('DOING_AJAX') && DOING_AJAX) {
-
-            $user = wp_get_current_user();
-
-            if (
-                is_super_admin($user->ID) ||
-                in_array('administrator', (array)$user->roles) ||
-                in_array('editor', (array)$user->roles) ||
-                in_array('author', (array)$user->roles)
-            ) {
-
-                $isTest = false;
-                $cg_client = sanitize_text_field($_GET['cg_client']);
-                $cg_secret = sanitize_text_field($_GET['cg_secret']);
-                if(intval($_GET['cg_test_env'])==1){
-                    $isTest = true;
-                }
-
-				if(empty($cg_secret)){// cause without secret an access token will be at least generated, but can not be used for further requests
-					$accessToken='error' ;
-				}else{
-					$accessToken = cg_paypal_get_access_token($cg_client,$cg_secret,$isTest);
-				}
-
-                if($accessToken!='error' && $accessToken!='no-internet'){
-                    echo '###cgkeytrue###';
-                }else{
-                    echo '###cgkeyfalse###';
-                }
+        if (!defined('DOING_AJAX') || !DOING_AJAX) {
+            exit();
+        }

-            } else {
-                echo "<div id='cgSaveCategoriesCouldNotBeChanged'><h2>MISSINGRIGHTS<br>This area can be edited only as administrator, editor or author.</h2></div>";
-                exit();
-            }
+        cg_require_global_settings_access();
+        cg_check_nonce();
+        contest_gal1ery_db_check();

-            exit();
-        } else {
-            exit();
+        $isTest = (
+            isset($_POST['cg_test_env']) &&
+            !is_array($_POST['cg_test_env']) &&
+            intval($_POST['cg_test_env']) === 1
+        );
+        $cg_client = (
+            isset($_POST['cg_client']) &&
+            !is_array($_POST['cg_client'])
+        ) ? sanitize_text_field(wp_unslash($_POST['cg_client'])) : '';
+        $cg_secret = (
+            isset($_POST['cg_secret']) &&
+            !is_array($_POST['cg_secret'])
+        ) ? sanitize_text_field(wp_unslash($_POST['cg_secret'])) : '';
+
+        if($cg_secret === ''){// cause without secret an access token will be at least generated, but can not be used for further requests
+            $accessToken='error';
+        }else{
+            $accessToken = cg_paypal_get_access_token($cg_client,$cg_secret,$isTest);
+        }
+
+        if($accessToken!='error' && $accessToken!='no-internet'){
+            echo '###cgkeytrue###';
+        }else{
+            echo '###cgkeyfalse###';
         }
+
+        exit();
     }
 }
 // sort files ---- END
@@ -1471,45 +1501,41 @@
 if (!function_exists('post_cg_test_stripe_keys')) {
     function post_cg_test_stripe_keys()
     {
-        contest_gal1ery_db_check();
-
-        if (defined('DOING_AJAX') && DOING_AJAX) {
-
-            $user = wp_get_current_user();
-
-            if (
-                is_super_admin($user->ID) ||
-                in_array('administrator', (array)$user->roles) ||
-                in_array('editor', (array)$user->roles) ||
-                in_array('author', (array)$user->roles)
-            ) {
-
-                $cg_client = sanitize_text_field($_GET['cg_client']);
-                $cg_secret = sanitize_text_field($_GET['cg_secret']);
-
-                $tokenError = '';
-
-				if(empty($cg_client) || empty($cg_secret)){// cause without secret an access token will be at least generated, but can not be used for further requests
-					$tokenError='client or secret not provided';
-				}else{
-					$tokenError = cg_test_stripe_keys($cg_client,$cg_secret);
-				}
-
-                if(!empty($tokenError)){
-	                echo '###cgmessage###'.$tokenError.'###cgmessage###';
-                }else{
-	                echo '###cgkeytrue###';
-                }
+        if (!defined('DOING_AJAX') || !DOING_AJAX) {
+            exit();
+        }

-            } else {
-                echo "<div id='cgSaveCategoriesCouldNotBeChanged'><h2>MISSINGRIGHTS<br>This area can be edited only as administrator, editor or author.</h2></div>";
-                exit();
-            }
+        cg_require_global_settings_access();
+        cg_check_nonce();
+        contest_gal1ery_db_check();

-            exit();
-        } else {
-            exit();
+        $isTest = (
+            isset($_POST['cg_test_env']) &&
+            !is_array($_POST['cg_test_env']) &&
+            intval($_POST['cg_test_env']) === 1
+        );
+        $cg_client = (
+            isset($_POST['cg_client']) &&
+            !is_array($_POST['cg_client'])
+        ) ? sanitize_text_field(wp_unslash($_POST['cg_client'])) : '';
+        $cg_secret = (
+            isset($_POST['cg_secret']) &&
+            !is_array($_POST['cg_secret'])
+        ) ? sanitize_text_field(wp_unslash($_POST['cg_secret'])) : '';
+
+        if($cg_client === '' || $cg_secret === ''){// cause without secret an access token will be at least generated, but can not be used for further requests
+            $tokenError='client or secret not provided';
+        }else{
+            $tokenError = cg_test_stripe_keys($cg_client,$cg_secret);
+        }
+
+        if(!empty($tokenError)){
+            echo '###cgmessage###'.$tokenError.'###cgmessage###';
+        }else{
+            echo '###cgkeytrue###';
         }
+
+        exit();
     }
 }
 // sort files ---- END
@@ -1521,6 +1547,8 @@
 if (!function_exists('post_cg_shortcode_interval_conf')) {
     function post_cg_shortcode_interval_conf()
     {
+        cg_require_backend_access();
+
         contest_gal1ery_db_check();

         $isBackendCall = true;
@@ -1567,6 +1595,7 @@
 if (!function_exists('post_cg_show_paypal_api_response')) {
     function post_cg_show_paypal_api_response()
     {
+        cg_require_backend_access();

         contest_gal1ery_db_check();

@@ -1659,6 +1688,7 @@
 add_action( 'wp_ajax_post_cg_download_original_source_for_ecommerce_sale', 'post_cg_download_original_source_for_ecommerce_sale' );
 if(!function_exists('post_cg_download_original_source_for_ecommerce_sale')){
     function post_cg_download_original_source_for_ecommerce_sale() {
+        cg_require_backend_access();

         $_POST = cg1l_sanitize_post($_POST);

@@ -1700,58 +1730,24 @@
     }
 }

-// set for paypal sell
-add_action( 'wp_ajax_post_cg_paypal_invoicing', 'post_cg_paypal_invoicing' );
-if(!function_exists('post_cg_paypal_invoicing')){
-    function post_cg_paypal_invoicing() {
-
-        $_POST = cg1l_sanitize_post($_POST);
-
-        contest_gal1ery_db_check();
-
-        $isBackendCall = true;
-        $isAjaxCall = true;
-
-        $isAjaxCategoriesCall = true;
-
-        global $wp_version;
-        $sanitize_textarea_field = ($wp_version<4.7) ? 'sanitize_text_field' : 'sanitize_textarea_field';
-
-        if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
-
-            $user = wp_get_current_user();
-
-            if (
-                is_super_admin($user->ID) ||
-                in_array( 'administrator', (array) $user->roles ) ||
-                in_array( 'editor', (array) $user->roles ) ||
-                in_array( 'author', (array) $user->roles )
-            ) {
-
-                cg_get_paypal_data();
-
-              die;
-
-            }else{
-                echo "MISSINGRIGHTS - This area can be edited only as administrator, editor or author.";
-                exit();
-            }
-
-            exit();
-        }
-        else {
-            exit();
-        }
-    }
-}
-// set for paypal sell --- END
-
 // check nickname
 add_action( 'wp_ajax_post_cg_check_nickname_edit_profile', 'post_cg_check_nickname_edit_profile' );
 if(!function_exists('post_cg_check_nickname_edit_profile')){
     function post_cg_check_nickname_edit_profile() {

         $_POST = cg1l_sanitize_post($_POST);
+        $cg_user_id = (!empty($_POST['cg_user_id']) && !is_array($_POST['cg_user_id'])) ? absint($_POST['cg_user_id']) : 0;
+
+        if (
+            empty($cg_user_id) ||
+            !current_user_can('edit_user', $cg_user_id) ||
+            check_ajax_referer('update-user_'.$cg_user_id, '_wpnonce', false) === false
+        ) {
+            status_header(403);
+            echo 'do-nothing';
+            die;
+        }
+
         contest_gal1ery_db_check();

         $isBackendCall = true;
@@ -1769,8 +1765,6 @@
             if($hasUserGroupAllowedToEdit){

                 $nickname = sanitize_text_field($_POST['nickname']);
-                $cg_user_id = absint($_POST['cg_user_id']);
-
                 global $wpdb;

                 $table_usermeta = $wpdb->prefix . "usermeta";
@@ -1806,13 +1800,22 @@
         $tablename = $wpdb->base_prefix . "contest_gal1ery";

         $_POST = cg1l_sanitize_post($_POST);
+        $user = wp_get_current_user();
+        $WpUserId = (!empty($_POST['user_id']) && !is_array($_POST['user_id'])) ? absint($_POST['user_id']) : 0;
+
+        if (
+            empty($WpUserId) ||
+            !current_user_can('edit_user', $WpUserId) ||
+            check_ajax_referer('update-user_'.$WpUserId, '_wpnonce', false) === false
+        ) {
+            status_header(403);
+            die('do-nothing');
+        }
+
         if(!empty($_FILES) AND !empty($_FILES['cg_input_image_upload_file']) AND !empty($_FILES['cg_input_image_upload_file']['tmp_name']) AND !empty($_FILES['cg_input_image_upload_file']['tmp_name'][0])){
             $_FILES = cg1l_sanitize_files($_FILES,'cg_input_image_upload_file',2100000);
         }

-        $user = wp_get_current_user();
-        $WpUserId  = absint($_POST['user_id']);
-
         $isAdministrator = false;

         if(is_super_admin($user->ID) || in_array( 'administrator', (array) $user->roles )){
@@ -1820,7 +1823,8 @@
         }

         if($user->ID != $WpUserId && $isAdministrator != true){// another user or not administrator user can't edit profile image
-            return;
+            status_header(403);
+            die('do-nothing');
         }

         if(!empty($_POST['cg_input_image_upload_file_to_delete_wp_id'])){// then image must be removed!
--- a/contest-gallery/ajax/ajax-functions-frontend.php
+++ b/contest-gallery/ajax/ajax-functions-frontend.php
@@ -671,6 +671,26 @@
     }
 }

+add_action('wp_ajax_nopriv_post_cg_rate_v10_average', 'post_cg_rate_v10_average');
+add_action('wp_ajax_post_cg_rate_v10_average', 'post_cg_rate_v10_average');
+if (!function_exists('post_cg_rate_v10_average')) {
+
+    function post_cg_rate_v10_average()
+    {
+
+        if (defined('DOING_AJAX') && DOING_AJAX) {
+
+            cg_check_frontend_nonce();
+
+            require_once(__DIR__.'/../v10/v10-frontend/data/rating/rate-picture-average.php');
+
+            exit();
+        } else {
+            exit();
+        }
+    }
+}
+
 add_action('wp_ajax_nopriv_post_cg1l_current_frontend_nonce', 'post_cg1l_current_frontend_nonce');
 add_action('wp_ajax_post_cg1l_current_frontend_nonce', 'post_cg1l_current_frontend_nonce');// has to run also for logged in users
 if (!function_exists('post_cg1l_current_frontend_nonce')) {
--- a/contest-gallery/check-language.php
+++ b/contest-gallery/check-language.php
@@ -180,6 +180,10 @@

 __('Rating quantity ascend');$l_RatingQuantityAscend = "Rating quantity ascend"; $language_RatingQuantityAscend = (!empty($translations[$l_RatingQuantityAscend]) && $is_frontend) ? $translations[$l_RatingQuantityAscend] : ((empty(trim(__($l_RatingQuantityAscend,$domain)))) ? __($l_RatingQuantityAscend,$domainDefault) : __($l_RatingQuantityAscend,$domain)); if(empty($translations[$l_RatingQuantityAscend])){$translations[$l_RatingQuantityAscend]='';}

+__('Rating average descend');$l_RatingAverageDescend = "Rating average descend"; $language_RatingAverageDescend = (!empty($translations[$l_RatingAverageDescend]) && $is_frontend) ? $translations[$l_RatingAverageDescend] : ((empty(trim(__($l_RatingAverageDescend,$domain)))) ? __($l_RatingAverageDescend,$domainDefault) : __($l_RatingAverageDescend,$domain)); if(empty($translations[$l_RatingAverageDescend])){$translations[$l_RatingAverageDescend]='';}
+
+__('Rating average ascend');$l_RatingAverageAscend = "Rating average ascend"; $language_RatingAverageAscend = (!empty($translations[$l_RatingAverageAscend]) && $is_frontend) ? $translations[$l_RatingAverageAscend] : ((empty(trim(__($l_RatingAverageAscend,$domain)))) ? __($l_RatingAverageAscend,$domainDefault) : __($l_RatingAverageAscend,$domain)); if(empty($translations[$l_RatingAverageAscend])){$translations[$l_RatingAverageAscend]='';}
+
 __('Rating sum descend');$l_RatingSumDescend = "Rating sum descend"; $language_RatingSumDescend = (!empty($translations[$l_RatingSumDescend]) && $is_frontend) ? $translations[$l_RatingSumDescend] : ((empty(trim(__($l_RatingSumDescend,$domain)))) ? __($l_RatingSumDescend,$domainDefault) : __($l_RatingSumDescend,$domain)); if(empty($translations[$l_RatingSumDescend])){$translations[$l_RatingSumDescend]='';}

 __('Rating sum ascend');$l_RatingSumAscend = "Rating sum ascend"; $language_RatingSumAscend = (!empty($translations[$l_RatingSumAscend]) && $is_frontend) ? $translations[$l_RatingSumAscend] : ((empty(trim(__($l_RatingSumAscend,$domain)))) ? __($l_RatingSumAscend,$domainDefault) : __($l_RatingSumAscend,$domain)); if(empty($translations[$l_RatingSumAscend])){$translations[$l_RatingSumAscend]='';}
@@ -276,6 +280,10 @@

 __('Your vote');$l_YourVote = "Your vote"; $language_YourVote = (!empty($translations[$l_YourVote]) && $is_frontend) ? $translations[$l_YourVote] : ((empty(trim(__($l_YourVote,$domain)))) ? __($l_YourVote,$domainDefault) : __($l_YourVote,$domain)); if(empty($translations[$l_YourVote])){$translations[$l_YourVote]='';}

+__('rating');$l_Rating = "rating"; $language_Rating = (!empty($translations[$l_Rating]) && $is_frontend) ? $translations[$l_Rating] : ((empty(trim(__($l_Rating,$domain)))) ? __($l_Rating,$domainDefault) : __($l_Rating,$domain)); if(empty($translations[$l_Rating])){$translations[$l_Rating]='';}
+
+__('ratings');$l_Ratings = "ratings"; $language_Ratings = (!empty($translations[$l_Ratings]) && $is_frontend) ? $translations[$l_Ratings] : ((empty(trim(__($l_Ratings,$domain)))) ? __($l_Ratings,$domainDefault) : __($l_Ratings,$domain)); if(empty($translations[$l_Ratings])){$translations[$l_Ratings]='';}
+
 // Upload/Registry
 __('The name field must contain two characters or more');$l_TheNameFieldMustContainTwoCharactersOrMore= "The name field must contain two characters or more";$language_TheNameFieldMustContainTwoCharactersOrMore = (!empty($translations[$l_TheNameFieldMustContainTwoCharactersOrMore]) && $is_frontend) ? $translations[$l_TheNameFieldMustContainTwoCharactersOrMore] : ((empty(trim(__($l_TheNameFieldMustContainTwoCharactersOrMore,$domain)))) ? __($l_TheNameFieldMustContainTwoCharactersOrMore,$domainDefault) : __($l_TheNameFieldMustContainTwoCharactersOrMore,$domain)); if(empty($translations[$l_SortBy])){$translations[$l_TheNameFieldMustContainTwoCharactersOrMore]='';}

--- a/contest-gallery/functions/backend/ajax/openai/post-cg-check-openai-key.php
+++ b/contest-gallery/functions/backend/ajax/openai/post-cg-check-openai-key.php
@@ -5,7 +5,17 @@
 if (!function_exists('post_cg_check_openai_key')) {
     function post_cg_check_openai_key() {

-        $apiKey = cg1l_sanitize_method($_GET['cgOpenAiKey']);
+        cg_require_global_settings_access();
+        cg_check_nonce();
+
+        $apiKey = '';
+        if(isset($_POST['cgOpenAiKey']) && !is_array($_POST['cgOpenAiKey'])){
+            $apiKey = trim(cg1l_sanitize_method(wp_unslash($_POST['cgOpenAiKey'])));
+        }
+        if($apiKey === ''){
+            return;
+        }
+
         $cgOpenAiKeyIsValid = false;
         $cgOpenAiKeyErrorMessage = '';

--- a/contest-gallery/functions/backend/render/cg-database-installation-container.php
+++ b/contest-gallery/functions/backend/render/cg-database-installation-container.php
@@ -0,0 +1,44 @@
+<?php
+
+if(!defined('ABSPATH')){exit;}
+
+if(!function_exists('cg_database_installation_container')){
+    function cg_database_installation_container(){
+        if(!function_exists('cg_database_install_is_pending') || !cg_database_install_is_pending() || !cg_database_install_current_user_can_complete()){
+            return;
+        }
+
+        global $wpdb;
+
+        $isFirstGallery = false;
+        $i = cg_database_install_get_current_table_suffix();
+        if(function_exists('cg_contest_gallery_required_tables_exist') && cg_contest_gallery_required_tables_exist($i,true)){
+            $tableNameOptions = $wpdb->prefix . 'contest_gal1ery_options';
+            $isFirstGallery = !(bool)$wpdb->get_var("SELECT id FROM $tableNameOptions LIMIT 1");
+        }
+
+        $redirectText = $isFirstGallery
+            ? 'You will be redirected to your first gallery automatically.'
+            : 'You will be redirected automatically.';
+
+        echo '<div id="cgDatabaseInstallationContainer" class="cg_backend_action_container cg_database_installation_container cg_do_not_remove_when_ajax_load cg_do_not_remove_when_main_empty cg_hide" data-cg-pending="1" data-cg-ajax-url="'.esc_url(admin_url('admin-ajax.php')).'" data-cg-nonce="'.esc_attr(wp_create_nonce('cg_complete_database_install')).'" role="dialog" aria-modal="true" aria-labelledby="cgDatabaseInstallationHeadline" aria-describedby="cgDatabaseInstallationText">'
+            .'<div class="cg_database_installation_content">'
+                .'<div class="cg_database_installation_kicker">One-time setup</div>'
+                .'<div class="cg_database_installation_main">'
+                    .'<div class="cg_database_installation_copy">'
+                        .'<h2 id="cgDatabaseInstallationHeadline">Preparing Contest Gallery</h2>'
+                        .'<p id="cgDatabaseInstallationText">Contest Gallery setup is in progress and will be finished shortly.</p>'
+                        .'<p class="cg_database_installation_redirect">'.esc_html($redirectText).'</p>'
+                    .'</div>'
+                    .'<div class="cg_database_installation_icon" aria-hidden="true"><span></span></div>'
+                .'</div>'
+                .'<div class="cg_database_installation_chips" aria-hidden="true"><span>Entries</span><span>Upload form</span><span>Registration</span><span>Shortcodes</span></div>'
+                .'<div class="cg_database_installation_loader" role="status" aria-label="Contest Gallery setup is in progress"><span></span></div>'
+                .'<p id="cgDatabaseInstallationError" class="cg_database_installation_error cg_hide">Setup could not be completed. Reload the page and try again.</p>'
+                .'<button type="button" id="cgDatabaseInstallationReload" class="cg_backend_button cg_hide">Reload and retry</button>'
+            .'</div>'
+        .'</div>';
+    }
+}
+
+?>
--- a/contest-gallery/functions/backend/render/cg-user-data-export-container.php
+++ b/contest-gallery/functions/backend/render/cg-user-data-export-container.php
@@ -0,0 +1,31 @@
+<?php
+
+if(!defined('ABSPATH')){exit;}
+
+if(!function_exists('cg_user_data_export_container')){
+	function cg_user_data_export_container(){
+		echo '<div id="cgUserDataExportModalContainer" class="cg_backend_action_container cg_hide cg_user_data_export_modal cg_do_not_remove_when_ajax_load cg_do_not_remove_when_main_empty" data-cg-job-id="" role="dialog" aria-modal="true" aria-labelledby="cgUserDataExportHeadline" aria-describedby="cgUserDataExportText">'
+			.'<span class="cg_message_close cg_user_data_export_close"></span>'
+			.'<div class="cg-user-data-export-modal">'
+				.'<div class="cg-user-data-export-kicker">Registered users data export</div>'
+				.'<h2 id="cgUserDataExportHeadline">Preparing export</h2>'
+				.'<p id="cgUserDataExportText">The export job is being prepared.</p>'
+				.'<div class="cg-user-data-export-progressbar"><span id="cgUserDataExportProgressBar"></span></div>'
+				.'<div class="cg-user-data-export-meta">'
+					.'<span>Progress: <strong id="cgUserDataExportPercent">0%</strong></span>'
+					.'<span>Users: <strong id="cgUserDataExportUsers">0/0</strong></span>'
+				.'</div>'
+				.'<div id="cgUserDataExportError" class="cg-user-data-export-result cg-user-data-export-result-error cg_hide"></div>'
+				.'<div id="cgUserDataExportDownloadInfo" class="cg-user-data-export-download-info cg_hide">The temporary CSV parts are removed automatically after 24 hours.</div>'
+				.'<div class="cg-user-data-export-actions">'
+					.'<button type="button" id="cgUserDataExportCancel" class="cg_backend_button cg-user-data-export-button cg-user-data-export-button-ghost">Cancel export</button>'
+					.'<button type="button" id="cgUserDataExportRetry" class="cg_backend_button cg-user-data-export-button cg-user-data-export-button-primary cg_hide">Retry</button>'
+					.'<a id="cgUserDataExportDownload" class="cg_backend_button cg-user-data-export-button cg-user-data-export-button-primary cg_hide" href="#">Download CSV</a>'
+					.'<button type="button" id="cgUserDataExportClose" class="cg_backend_button cg-user-data-export-button cg-user-data-export-button-ghost cg_hide">Close</button>'
+				.'</div>'
+			.'</div>'
+			.'</div>';
+	}
+}
+
+?>
--- a/contest-gallery/functions/backend/render/openai/cg-openai-containers.php
+++ b/contest-gallery/functions/backend/render/openai/cg-openai-containers.php
@@ -7,7 +7,11 @@
         $assetsPath = plugins_url() . "/" . cg_get_version() . "/v10/v10-css/backend/assets";
         $assign_fields_png = plugins_url('/../../../../v10/v10-css/assign-fields.png', __FILE__);

-        $enterOpenAiKey = '<a href="?page=' . cg_get_version() . '/index.php&option_id=' . $GalleryID . '&edit_options=true&cg_go_to=cgOpenAiKeyRowColumn">Enter OpenAI Api key</a>';
+        if(cg_user_can_manage_global_settings()){
+            $openAiKeySettingsMessage = '<a href="?page=' . cg_get_version() . '/index.php&option_id=' . absint($GalleryID) . '&edit_options=true&cg_go_to=cgOpenAiKeyRowColumn">Open the OpenAI settings</a>';
+        }else{
+            $openAiKeySettingsMessage = 'Please contact an administrator to configure the OpenAI API key.';
+        }

         echo "<div id='cgOpenAiContainer' class='cg_media_container cg_hide' data-cg-gid='$GalleryID'>";
         ?>
@@ -215,12 +219,8 @@
                     <b>No OpenAI API key entered</b><br>
                     Get your API key from OpenAI within minutes:<br>
                     <a href="https://platform.openai.com/api-keys" target="_blank">...openai.com/api-keys</a>
-                    <br><br>Enter your API key in "Edit options" to connect to your OpenAI account:<br>
-                    <?php echo $enterOpenAiKey; ?>
-                </div>
-                <div class="cg_openai_button_container cg_hide">
-                    <input type='text' id='cgOpenAiKeyInput'' > <input type="button" id="cgOpenAiKeySubmit"
-                                                                       class="cg_disabled_one" value="Send">
+                    <br><br>
+                    <?php echo $openAiKeySettingsMessage; ?>
                 </div>
                 <div id="cgOpenAiKeyError" class="cg_hide">
                 </div>
@@ -262,11 +262,7 @@
         <div id='cgOpenAiKeyNotValid' class='cg_openai_main cg_hide'>
             <div class="cg_openai_header">
                 <b>API key not valid</b><br>
-                Enter new API key to connect to your OpenAI account.
-            </div>
-            <div class="cg_openai_button_container">
-                <input type='text' id='cgOpenAiKeyInput'' > <input type="button" id="cgOpenAiKeySubmit"
-                                                                   class="cg_disabled_one" value="Send">
+                <?php echo $openAiKeySettingsMessage; ?>
             </div>
         </div>
         <input type='hidden' name='cgGalleryHash'
@@ -278,4 +274,4 @@
     }
 }

-?>
 No newline at end of file
+?>
--- a/contest-gallery/functions/ecommerce/backend/gallery/cg-ecommerce-export-orders.php
+++ b/contest-gallery/functions/ecommerce/backend/gallery/cg-ecommerce-export-orders.php
@@ -1,376 +1,196 @@
 <?php
-if(!function_exists('cg_ecommerce_export_orders')){
-	function cg_ecommerce_export_orders(){

-		if(!current_user_can('manage_options')){
-			echo "Logged in user have to be able to manage_options to execute export.";die;
-		}
+if(!defined('CG_ECOMMERCE_ORDERS_EXPORT_BATCH_SIZE')){
+	define('CG_ECOMMERCE_ORDERS_EXPORT_BATCH_SIZE',100);
+}

+if(!function_exists('cg_ecommerce_export_orders_get_batch')){
+	function cg_ecommerce_export_orders_get_batch($beforeOrderId,$batchSize){
 		global $wpdb;

-		$tablename_ecommerce_orders_items = $wpdb->prefix . "contest_gal1ery_ecommerce_orders_items";
+		$ordersTable = $wpdb->prefix . "contest_gal1ery_ecommerce_orders";
+		$itemsTable = $wpdb->prefix . "contest_gal1ery_ecommerce_orders_items";
+		$orderColumns = "sale_orders.id,
+			sale_orders.OrderNumber,
+			sale_orders.Tstamp,
+			sale_orders.PayPalTransactionId,
+			sale_orders.StripePiId,
+			sale_orders.PayerEmail,
+			sale_orders.InvoiceAddressFirstName,
+			sale_orders.InvoiceAddressLastName,
+			sale_orders.InvoiceAddressCompany,
+			sale_orders.InvoiceAddressLine1,
+			sale_orders.InvoiceAddressLine2,
+			sale_orders.InvoiceAddressCity,
+			sale_orders.InvoiceAddressPostalCode,
+			sale_orders.InvoiceAddressStateShort,
+			sale_orders.InvoiceAddressStateTranslation,
+			sale_orders.InvoiceAddressCountryShort,
+			sale_orders.InvoiceAddressCountryTranslation,
+			sale_orders.TaxNr,
+			sale_orders.ShippingAddressFirstName,
+			sale_orders.ShippingAddressLastName,
+			sale_orders.ShippingAddressCompany,
+			sale_orders.ShippingAddressLine1,
+			sale_orders.ShippingAddressLine2,
+			sale_orders.ShippingAddressCity,
+			sale_orders.ShippingAddressPostalCode,
+			sale_orders.ShippingAddressStateShort,
+			sale_orders.ShippingAddressStateTranslation,
+			sale_orders.ShippingAddressCountryShort,
+			sale_orders.ShippingAddressCountryTranslation,
+			sale_orders.ShippingNet,
+			sale_orders.ShippingGross,
+			sale_orders.PriceTotalNetItemsWithShipping,
+			sale_orders.PriceTotalGrossItemsWithShipping,
+			sale_orders.CurrencyShort,
+			sale_orders.CurrencyPosition,
+			sale_orders.LogForDatabase,
+			sale_orders.IsTest";

-        $start = 0;
-		if (isset($_POST["cg_start"])) {
-			$muster = "/^[0-9]+$/";
-			if (preg_match($muster, $_POST["cg_start"]) == 0) {
-				$start = 0;
-			} else {
-				$start = $_POST["cg_start"];
-			}
+		if(!empty($_GET['cg_order_id'])){
+			return $wpdb->get_results($wpdb->prepare(
+				"SELECT $orderColumns
+				FROM $ordersTable AS sale_orders
+				WHERE sale_orders.id = %d",
+				absint($_GET['cg_order_id'])
+			));
 		}

-		$step = 50;
-		if (isset($_POST["cg_step"])) {
-			$muster = "/^[0-9]+$/"; // reg. Ausdruck für Zahlen
-			if (preg_match($muster, $_POST["cg_step"]) == 0) {
-				$step = 50;
-			} else {
-				$step = $_POST["cg_step"];
-			}
+		$whereClauses = array();
+		$whereValues = array();
+		$filterClauses = array();
+		$filterValues = array();
+
+		$PayPalTransactionId = cg_ecommerce_get_orders_get_post_text('cg_paypal_transaction_id');
+		$PayerEmail = cg_ecommerce_get_orders_get_post_text('cg_payer_email');
+		$OrderNumber = cg_ecommerce_get_orders_get_post_text('cg_order_number');
+		$ItemIdsSearchValue = cg_ecommerce_get_orders_get_post_text('cg_item_ids');
+		$GalleryIdsSearchValue = cg_ecommerce_get_orders_get_post_text('cg_gallery_ids');
+		$ItemIds = cg_ecommerce_get_orders_get_post_ids('cg_item_ids');
+		$GalleryIds = cg_ecommerce_get_orders_get_post_ids('cg_gallery_ids');
+
+		if($PayPalTransactionId!==''){
+			$PayPalTransactionIdLike = '%'.$wpdb->esc_like($PayPalTransactionId).'%';
+			$filterClauses[] = "(sale_orders.PayPalTransactionId LIKE %s OR sale_orders.StripePiId LIKE %s)";
+			$filterValues[] = $PayPalTransactionIdLike;
+			$filterValues[] = $PayPalTransactionIdLike;
 		}

-		$return = cg_ecommerce_get_orders($start,$step,true);
-		$saleOrders = $return['saleOrders'];
+		if($PayerEmail!==''){
+			$filterClauses[] = "sale_orders.PayerEmail LIKE %s";
+			$filterValues[] = '%'.$wpdb->esc_like($PayerEmail).'%';
+		}

-		$currenciesArray = cg_get_ecommerce_currencies_array_formatted_by_short_key();
+		if($ItemIdsSearchValue!==''){
+			if(count($ItemIds)){
+				$ItemPlaceholders = implode(',',array_fill(0,count($ItemIds),'%d'));
+				$filterClauses[] = "EXISTS (
+					SELECT 1
+					FROM $itemsTable AS item_filter
+					WHERE item_filter.ParentOrder = sale_orders.id
+						AND item_filter.pid IN ($ItemPlaceholders)
+				)";
+				foreach($ItemIds as $ItemId){
+					$filterValues[] = $ItemId;
+				}
+			}else{
+				$filterClauses[] = '1 = 0';
+			}
+		}

-		$saleItemsIdsByOrderIdArray = [];
-		$saleItemsCollectedOrderIds = [];
-		$saleItemsArray = [];
-
-		foreach($saleOrders as $saleOrder){
-			$OrderId = $saleOrder->id;
-			$saleItemsCollectedOrderIds[] = $OrderId;
-			$saleItemsArray[$saleOrder->id] = [];
-		}
-
-		$saleItems = array();
-		if(!empty($saleItemsCollectedOrderIds)){
-			$SaleItemsPlaceholders = implode(',', array_fill(0, count($saleItemsCollectedOrderIds), '%d'));
-			$saleItemsQuery = "SELECT * FROM $tablename_ecommerce_orders_items WHERE ParentOrder IN ($SaleItemsPlaceholders)";
-			$saleItems = $wpdb->get_results(cg_ecommerce_get_orders_prepare_query($wpdb, $saleItemsQuery, $saleItemsCollectedOrderIds));
-		}
-
-		foreach($saleItems as $saleItem){
-			if(!isset($saleItemsIdsByOrderIdArray[$saleItem->ParentOrder])){
-				$saleItemsIdsByOrderIdArray[$saleItem->ParentOrder] = [];
+		if($OrderNumber!==''){
+			$filterClauses[] = "sale_orders.OrderNumber LIKE %s";
+			$filterValues[] = '%'.$wpdb->esc_like($OrderNumber).'%';
+		}
+
+		if($GalleryIdsSearchValue!==''){
+			if(count($GalleryIds)){
+				$GalleryPlaceholders = implode(',',array_fill(0,count($GalleryIds),'%d'));
+				$filterClauses[] = "EXISTS (
+					SELECT 1
+					FROM $itemsTable AS gallery_filter
+					WHERE gallery_filter.ParentOrder = sale_orders.id
+						AND gallery_filter.GalleryID IN ($GalleryPlaceholders)
+				)";
+				foreach($GalleryIds as $GalleryId){
+					$filterValues[] = $GalleryId;
+				}
+			}else{
+				$filterClauses[] = '1 = 0';
 			}
-			$saleItemsIdsByOrderIdArray[$saleItem->ParentOrder][] = $saleItem->pid;
-			$saleItemsArray[$saleItem->ParentOrder][] = $saleItem;
 		}

-		$k = 0;
+		$whereClauses[] = 'sale_orders.id > 0';
+		if(count($filterClauses)){
+			$whereClauses[] = '('.implode(' OR ',$filterClauses).')';
+			$whereValues = array_merge($whereValues,$filterValues);
+		}
+		if(!empty($beforeOrderId)){
+			$whereClauses[] = 'sale_orders.id < %d';
+			$whereValues[] = absint($beforeOrderId);
+		}

-		$csvData = array();
+		$query = "SELECT $orderColumns
+			FROM $ordersTable AS sale_orders
+			WHERE ".implode(' AND ',$whereClauses)."
+			ORDER BY sale_orders.id DESC
+			LIMIT %d";
+		$whereValues[] = absint($batchSize);

-		$i=0;
-		$r=0;
-
-		$csvData[$i][$k]="Order number";
-		$k++;
-		$csvData[$i][$k]="Purchase date";
-		$k++;
-		$csvData[$i][$k]="PayPal transaction ID";
-		$k++;
-		$csvData[$i][$k]="Stripe Payment Intent ID";
-		$k++;
-		$csvData[$i][$k]="Payer email";
-		$k++;
-		$csvData[$i][$k]="Invoice address first name ";
-		$k++;
-		$csvData[$i][$k]="Invoice address last name ";
-		$k++;
-		$csvData[$i][$k]="Invoice address company";
-		$k++;
-		$csvData[$i][$k]="Invoice address address line 1";
-		$k++;
-		$csvData[$i][$k]="Invoice address address line 2";
-		$k++;
-		$csvData[$i][$k]="Invoice address city";
-		$k++;
-		$csvData[$i][$k]="Invoice address postal code";
-		$k++;
-		$csvData[$i][$k]="Invoice address state short";
-		$k++;
-		$csvData[$i][$k]="Invoice address state";
-		$k++;
-		$csvData[$i][$k]="Invoice address country short";
-		$k++;
-		$csvData[$i][$k]="Invoice address country";
-		$k++;
-		$csvData[$i][$k]="VAT Number";
-		$k++;
-		$csvData[$i][$k]="Shipping address first name ";
-		$k++;
-		$csvData[$i][$k]="Shipping address last name ";
-		$k++;
-		$csvData[$i][$k]="Shipping address company";
-		$k++;
-		$csvData[$i][$k]="Shipping address address line 1";
-		$k++;
-		$csvData[$i][$k]="Shipping address address line 2";
-		$k++;
-		$csvData[$i][$k]="Shipping address city";
-		$k++;
-		$csvData[$i][$k]="Shipping address postal code";
-		$k++;
-		$csvData[$i][$k]="Shipping address state short";
-		$k++;
-		$csvData[$i][$k]="Shipping address state";
-		$k++;
-		$csvData[$i][$k]="Shipping address country short";
-		$k++;
-		$csvData[$i][$k]="Shipping address country";
-		$k++;
-		$csvData[$i][$k]="Shipping default net";
-		$k++;
-		$csvData[$i][$k]="Shipping default gross";
-		$k++;
-		$csvData[$i][$k]="Total net (with shipping if exists)";
-		$k++;
-		$csvData[$i][$k]="Total gross (with shipping if exists)";
-		$k++;
-		$csvData[$i][$k]="Quantity";
-		$k++;
-		$csvData[$i][$k]="Type";
-		$k++;
-		$csvData[$i][$k]="Title";
-		$k++;
-		$csvData[$i][$k]="Price unit net";
-		$k++;
-		$csvData[$i][$k]="Price total net";
-		$k++;
-		$csvData[$i][$k]="Tax percentage";
-		$k++;
-		$csvData[$i][$k]="Tax total";
-		$k++;
-		$csvData[$i][$k]="Price total gross";
-		$k++;
-		$csvData[$i][$k]="Shipping alternative net";
-		$k++;
-		$csvData[$i][$k]="Shipping alternative gross";
-		$k++;
-		$csvData[$i][$k]="Entry ID";
-		$k++;
-		$csvData[$i][$k]="Gallery ID";
-		$k++;
-		$csvData[$i][$k]="Environment";
-		$k++;
-
-		/*echo "<pre>";
-		print_r($saleItemsArray);
-		echo "</pre>";
-
-		die;*/
-
-		// Simple amount of orders
-		$order = 0;
-
-		foreach($saleOrders as $saleOrder){
-				$i++;
-				$k = 0;
-				$order++;
-				$purchaseTime = cg_get_time_based_on_wp_timezone_conf($saleOrder->Tstamp,'d-M-Y H:i:s');
-				$TaxNr =  $saleOrder->TaxNr;
-				$PayerEmail =  $saleOrder->PayerEmail;
-				$LogForDatabase =  unserialize($saleOrder->LogForDatabase);
-				$PriceDivider = $LogForDatabase['PriceDivider'];
-				$CurrencyShort = $saleOrder->CurrencyShort;
-				$CurrencyPosition = $saleOrder->CurrencyPosition;
+		return $wpdb->get_results(cg_ecommerce_get_orders_prepare_query($wpdb,$query,$whereValues));
+	}
+}

-				$csvData[$i][$k]=$saleOrder->OrderNumber;
-				$k++;
-				$csvData[$i][$k]=$purchaseTime;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->PayPalTransactionId;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->StripePiId;
-				$k++;
-				$csvData[$i][$k]=$PayerEmail;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressFirstName;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressLastName;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressCompany;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressLine1;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressLine2;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressCity;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressPostalCode;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressStateShort;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressStateTranslation;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressCountryShort;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->InvoiceAddressCountryTranslation;
-				$k++;
-				$csvData[$i][$k]=$TaxNr;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressFirstName;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressLastName;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressCompany;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressLine1;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressLine2;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressCity;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressPostalCode;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressStateShort;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressStateTranslation;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressCountryShort;
-				$k++;
-				$csvData[$i][$k]=$saleOrder->ShippingAddressCountryTranslation;
-				$k++;
-
-				$hasDefaultShipping = false;
-				// check if has alternative shipping only
-				foreach($saleItemsArray[$saleOrder->id] as $saleOrderItem){
-					if($saleOrderItem->IsShipping && !$saleOrderItem->IsAlternativeShipping){
-						$hasDefaultShipping = true;
-					}
-				}
+if(!function_exists('cg_ecommerce_export_orders_get_items')){
+	function cg_ecommerce_export_orders_get_items($orderIds){
+		global $wpdb;

-				if($hasDefaultShipping){
-					$csvData[$i][$k]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrder->ShippingNet);
-				}else{
-					$csvData[$i][$k]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,0);
-				}
+		if(empty($orderIds)){
+			return array();
+		}

-				$k++;
+		$itemsTable = $wpdb->prefix . "contest_gal1ery_ecommerce_orders_items";
+		$placeholders = implode(',',array_fill(0,count($orderIds),'%d'));
+		$query = "SELECT
+				ParentOrder,
+				Units,
+				IsDownload,
+				IsShipping,
+				IsUpload,
+				IsAlternativeShipping,
+				SaleTitle,
+				PriceUnitNet,
+				PriceTotalNet,
+				TaxPercentage,
+				TaxValueTotal,
+				PriceTotalGross,
+				AlternativeShippingNet,
+				AlternativeShippingGross,
+				pid,
+				GalleryID
+			FROM $itemsTable
+			WHERE ParentOrder IN ($placeholders)
+			ORDER BY id ASC";

-				if($hasDefaultShipping){
-					$csvData[$i][$k]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrder->ShippingGross);
-				}else{
-					$csvData[$i][$k]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,0);
-				}
+		return $wpdb->get_results(cg_ecommerce_get_orders_prepare_query($wpdb,$query,$orderIds));
+	}
+}

-				$k++;
-				$csvData[$i][$k]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrder->PriceTotalNetItemsWithShipping);
-				$k++;
-				$csvData[$i][$k]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrder->PriceTotalGrossItemsWithShipping);
-				$k++;
-
-				foreach($saleItemsArray[$saleOrder->id] as $saleOrderItem){
-					$koi = 0;// key order item
-					/*var_dump('$saleOrder->id');
-					var_dump($saleOrder->id);
-					echo "<pre>";
-						print_r($saleOrderItem);
-					echo "</pre>";
-					die;*/
-					$i++;
-					$type = '';
-					if($saleOrderItem->IsDownload){$type='download';}
-					if($saleOrderItem->IsShipping){$type='shipping';}
-					if($saleOrderItem->IsUpload){$type='upload';}
-					//$csvData[$i][0]="Purchase Date";
-					//$csvData[$i][1]="PayPal Transaction ID";
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]='';
-					$koi++;
-					$csvData[$i][$koi]=$saleOrderItem->Units;
-					$koi++;
-					$csvData[$i][$koi]=($type=='shipping' && $saleOrderItem->AlternativeShippingNet>0) ? 'shipping alternative' : $type;
-					$koi++;
-					$csvData[$i][$koi]=contest_gal1ery_convert_for_html_output_without_nl2br($saleOrderItem->SaleTitle);
-					$koi++;
-					$csvData[$i][$koi]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->PriceUnitNet);
-					$koi++;
-					$csvData[$i][$koi]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->PriceTotalNet);
-					$koi++;
-					$csvData[$i][$koi]=cg_ecommerce_price_to_show($currenciesArray,'%','right',$PriceDivider,$saleOrderItem->TaxPercentage);
-					$koi++;
-					$csvData[$i][$koi]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->TaxValueTotal);
-					$koi++;
-					$csvData[$i][$koi]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->PriceTotalGross);
-					$koi++;
-					$csvData[$i][$koi]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->AlternativeShippingNet);
-					$koi++;
-					$csvData[$i][$koi]=cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->AlternativeShippingGross);
-					$koi++;
-					$csvData[$i][$koi]=$saleOrderItem->pid;
-					$koi++;
-					$csvData[$i][$koi]=$saleOrderItem->GalleryID;
-					$koi++;
-					$csvData[$i][$koi]=($saleOrder->IsTest) ? 'test' : 'live';
-					$koi++;
-				}
-			}
+if(!function_exists('cg_ecommerce_export_orders_write_csv_row')){
+	function cg_ecommerce_export_orders_write_csv_row($fp,$row){
+		return fputcsv($fp,cg_neutralize_csv_array($row),';');
+	}
+}
+
+if(!function_exists('cg_ecommerce_export_orders')){
+	function cg_ecommerce_export_orders(){
+
+		if(!current_user_can('manage_options')){
+			echo "Logged in user have to be able to manage_options to execute export.";die;
+		}
+
+		$currenciesArray = cg_get_ecommerce_currencies_array_formatted_by_short_key();

 		if(!empty($_GET['cg_order_id'])){
 			$filename = "cg-order-".absint($_GET['cg_order_id']).".csv";
@@ -379,24 +199,175 @@
 			$filename = "cg-orders-".$exportTime.".csv";
 		}

-        $csvData = cg_neutralize_csv_array($csvData);
+		nocache_headers();
+		header("Content-type: text/csv; charset=UTF-8");
+		header('Content-Disposition: attachment; filename="'.$filename.'"');
+
+		$fp = fopen("php://output",'w');
+		if($fp===false){
+			echo "CSV export could not be created.";
+			die;
+		}

-		header("Content-type: text/csv");
-		header("Content-Disposition: attachment; filename=$filename");
+		fwrite($fp,chr(0xEF).chr(0xBB).chr(0xBF));

-		ob_start();
+		$header = array(
+			"Order number",
+			"Purchase date",
+			"PayPal transaction ID",
+			"Stripe Payment Intent ID",
+			"Payer email",
+			"Invoice address first name ",
+			"Invoice address last name ",
+			"Invoice address company",
+			"Invoice address address line 1",
+			"Invoice address address line 2",
+			"Invoice address city",
+			"Invoice address postal code",
+			"Invoice address state short",
+			"Invoice address state",
+			"Invoice address country short",
+			"Invoice address country",
+			"VAT Number",
+			"Shipping address first name ",
+			"Shipping address last name ",
+			"Shipping address company",
+			"Shipping address address line 1",
+			"Shipping address address line 2",
+			"Shipping address city",
+			"Shipping address postal code",
+			"Shipping address state short",
+			"Shipping address state",
+			"Shipping address country short",
+			"Shipping address country",
+			"Shipping default net",
+			"Shipping default gross",
+			"Total net (with shipping if exists)",
+			"Total gross (with shipping if exists)",
+			"Quantity",
+			"Type",
+			"Title",
+			"Price unit net",
+			"Price total net",
+			"Tax percentage",
+			"Tax total",
+			"Price total gross",
+			"Shipping alternative net",
+			"Shipping alternative gross",
+			"Entry ID",
+			"Gallery ID",
+			"Environment"
+		);
+		cg_ecommerce_export_orders_write_csv_row($fp,$header);
+
+		$beforeOrderId = 0;
+		do{
+			$saleOrders = cg_ecommerce_export_orders_get_batch($beforeOrderId,CG_ECOMMERCE_ORDERS_EXPORT_BATCH_SIZE);
+			if(empty($saleOrders)){
+				break;
+			}

-		$fp = fopen("php://output", 'w');
-		fputs($fp, $bom =( chr(0xEF) . chr(0xBB) . chr(0xBF) ));
-		foreach ($csvData as $fields) {
-			fputcsv($fp, $fields, ";");
-		}
-		fclose($fp);
-		$masterReturn = ob_get_clean();
-		echo $masterReturn;
-		die();
+			$orderIds = array();
+			$saleItemsArray = array();
+			$hasDefaultShippingByOrder = array();
+			foreach($saleOrders as $saleOrder){
+				$orderId = absint($saleOrder->id);
+				$orderIds[] = $orderId;
+				$saleItemsArray[$orderId] = array();
+				$hasDefaultShippingByOrder[$orderId] = false;
+			}
+
+			$saleItems = cg_ecommerce_export_orders_get_items($orderIds);
+			foreach($saleItems as $saleItem){
+				$orderId = absint($saleItem->ParentOrder);
+				if(!isset($saleItemsArray[$orderId])){
+					continue;
+				}
+				$saleItemsArray[$orderId][] = $saleItem;
+				if(!empty($saleItem->IsShipping) && empty($saleItem->IsAlternativeShipping)){
+					$hasDefaultShippingByOrder[$orderId] = true;
+				}
+			}
+
+			foreach($saleOrders as $saleOrder){
+				$orderId = absint($saleOrder->id);
+				$purchaseTime = cg_get_time_based_on_wp_timezone_conf($saleOrder->Tstamp,'d-M-Y H:i:s');
+				$LogForDatabase = maybe_unserialize($saleOrder->LogForDatabase);
+				$PriceDivider = (is_array($LogForDatabase) && isset($LogForDatabase['PriceDivider']))
+					? $LogForDatabase['PriceDivider']
+					: '.';
+				$CurrencyShort = $saleOrder->CurrencyShort;
+				$CurrencyPosition = $saleOrder->CurrencyPosition;
+				$hasDefaultShipping = !empty($hasDefaultShippingByOrder[$orderId]);
+
+				$orderRow = array(
+					$saleOrder->OrderNumber,
+					$purchaseTime,
+					$saleOrder->PayPalTransactionId,
+					$saleOrder->StripePiId,
+					$saleOrder->PayerEmail,
+					$saleOrder->InvoiceAddressFirstName,
+					$saleOrder->InvoiceAddressLastName,
+					$saleOrder->InvoiceAddressCompany,
+					$saleOrder->InvoiceAddressLine1,
+					$saleOrder->InvoiceAddressLine2,
+					$saleOrder->InvoiceAddressCity,
+					$saleOrder->InvoiceAddressPostalCode,
+					$saleOrder->InvoiceAddressStateShort,
+					$saleOrder->InvoiceAddressStateTranslation,
+					$saleOrder->InvoiceAddressCountryShort,
+					$saleOrder->InvoiceAddressCountryTranslation,
+					$saleOrder->TaxNr,
+					$saleOrder->ShippingAddressFirstName,
+					$saleOrder->ShippingAddressLastName,
+					$saleOrder->ShippingAddressCompany,
+					$saleOrder->ShippingAddressLine1,
+					$saleOrder->ShippingAddressLine2,
+					$saleOrder->ShippingAddressCity,
+					$saleOrder->ShippingAddressPostalCode,
+					$saleOrder->ShippingAddressStateShort,
+					$saleOrder->ShippingAddressStateTranslation,
+					$saleOrder->ShippingAddressCountryShort,
+					$saleOrder->ShippingAddressCountryTranslation,
+					cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$hasDefaultShipping ? $saleOrder->ShippingNet : 0),
+					cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$hasDefaultShipping ? $saleOrder->ShippingGross : 0),
+					cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrder->PriceTotalNetItemsWithShipping),
+					cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrder->PriceTotalGrossItemsWithShipping)
+				);
+				cg_ecommerce_export_orders_write_csv_row($fp,$orderRow);
+
+				foreach($saleItemsArray[$orderId] as $saleOrderItem){
+					$type = '';
+					if($saleOrderItem->IsDownload){$type='download';}
+					if($saleOrderItem->IsShipping){$type='shipping';}
+					if($saleOrderItem->IsUpload){$type='upload';}

+					$itemRow = array_fill(0,32,'');
+					$itemRow[] = $saleOrderItem->Units;
+					$itemRow[] = ($type==='shipping' && $saleOrderItem->AlternativeShippingNet>0) ? 'shipping alternative' : $type;
+					$itemRow[] = contest_gal1ery_convert_for_html_output_without_nl2br($saleOrderItem->SaleTitle);
+					$itemRow[] = cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->PriceUnitNet);
+					$itemRow[] = cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->PriceTotalNet);
+					$itemRow[] = cg_ecommerce_price_to_show($currenciesArray,'%','right',$PriceDivider,$saleOrderItem->TaxPercentage);
+					$itemRow[] = cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->TaxValueTotal);
+					$itemRow[] = cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->PriceTotalGross);
+					$itemRow[] = cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->AlternativeShippingNet);
+					$itemRow[] = cg_ecommerce_price_to_show($currenciesArray,$CurrencyShort,$CurrencyPosition,$PriceDivider,$saleOrderItem->AlternativeShippingGross);
+					$itemRow[] = $saleOrderItem->pid;
+					$itemRow[] = $saleOrderItem->GalleryID;
+					$itemRow[] = ($saleOrder->IsTest) ? 'test' : 'live';
+					cg_ecommerce_export_orders_write_csv_row($fp,$itemRow);
+				}
+			}
+
+			$lastOrder = end($saleOrders);
+			$beforeOrderId = absint($lastOrder->id);
+			$isFinished = !empty($_GET['cg_order_id']) || count($saleOrders)<CG_ECOMMERCE_ORDERS_EXPORT_BATCH_SIZE;
+			unset($saleOrders,$saleItems,$saleItemsArray,$hasDefaultShippingByOrder);
+		}while(!$isFinished);

+		fclose($fp);
+		die();
 	}
 }

--- a/contest-gallery/functions/ecommerce/backend/options/cg-create-get-ecommerce-options.php
+++ b/contest-gallery/functions/ecommerce/backend/options/cg-create-get-ecommerce-options.php
@@ -65,7 +65,7 @@
                 0,$OrderConfirmationMailHeader,$OrderConfirmationMailReply,
                 $OrderConfirmationMailSubject,$OrderConfirmationMail,
                 $AllowedCountries,15,5,
-                'You have to be registered and logged in to be able to purchase.','You have to be registered and logged in to see the order summary.',
+                'You have to be registered and logged in to be able to purchase.','You have to be registered and logged in to see the order summary.'
             ) );
         }

@@ -155,4 +155,4 @@
         ];
         return $array;
     }
-}
 No newline at end of file
+}
--- a/contest-gallery/functions/ecommerce/backend/options/cg-ecommerce-change-options-and-sizes.php
+++ b/contest-gallery/functions/ecommerce/backend/options/cg-ecommerce-change-options-and-sizes.php
@@ -2,6 +2,8 @@
 if(!function_exists('cg_ecommerce_change_options_and_sizes')){
     function cg_ecommerce_change_options_and_sizes($GalleryID){

+        cg_require_global_settings_access();
+
         global $wpdb;

         $tablenameEcommerceOptions = $wpdb->prefix . "contest_gal1ery_ecommerce_options";
@@ -65,16 +67,16 @@
 	    $PayPalApiActive = isset($_POST['PayPalApiActive']) ? 1 : 2;
 	    $PayPalTestActive = !empty($_POST['PayPalTestActive']) ? 1 : 0;
 	    $PayPalSandboxClientId = sanitize_text_field(isset($_POST['PayPalSandboxClientId']) ? $_POST['PayPalSandboxClientId'] : $PayPalSandboxClientId);
-        $PayPalSandboxSecret = sanitize_text_field(isset($_POST['PayPalSandboxSecret']) ? $_POST['PayPalSan

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.