| 开发者 |
smartsteve
freemius |
|---|---|
| 更新时间 | 2026年6月15日 17:52 |
| PHP版本: | 7.4 及以上 |
| WordPress版本: | 7.0 |
| 版权: | GPL-2.0-or-later |
| 版权网址: | 版权信息 |
.htaccesshttponly + SameSite=Laxcustomer-cloud-gallery folder to /wp-content/plugins/ or install via Plugins → Add New → Upload Plugin.[ccgal_gallery id="42"]) and paste it into any page.openssl, gd or imagickNo. Photos stay in your Google Drive or Dropbox account. The plugin only fetches thumbnails (cached locally for performance) and streams originals on demand. No image data is sent to any third-party or plugin-developer server.
Yes — at least one. You create a free OAuth app in Google Cloud Console or Dropbox App Console (both free) and paste the credentials into the plugin settings. A step-by-step guide is included.
Yes. Connect both and choose the storage provider per gallery.
Yes. The gallery is rendered in a self-contained shortcode block and does not depend on theme templates or scripts.
Download nonces expire after 24 hours. The visitor needs to reload the page to get a fresh nonce — the gallery itself remains accessible as long as the page session (password cookie) is valid.
Yes — just paste the folder URL or folder ID when creating a gallery. The plugin reads the folder contents via the cloud API.
No direct card processing. Orders are sent by e-mail; payment is collected via PayPal.me link or SEPA bank transfer details that you configure. This keeps the plugin PCI-DSS-free.
The Free plugin stores only a random visitor cookie ID, used to remember a visitor's favourites between page loads. No e-mail address, no IP address in plain text, no third-party transmission. A cookie-control switch per gallery lets visitors opt out entirely. See the Privacy Policy section below for details.
<details> element with the item count visible in the header even when collapsed. Each section has a per-section limit dropdown (5/10/25/50/All, default 10). The visitor activity table now uses true pagination (25 per page default) so that galleries with hundreds of visitors no longer produce a 10,000-pixel-long scroll page.includes/class-dropbox-adapter.php (download_to_file, stream_to_output, download_thumbnail) and includes/class-google-drive-adapter.php (stream_to_output) have been fully ported to wp_remote_request() / wp_remote_get() with stream => true. File downloads write directly to disk via the WordPress HTTP API (no PHP memory buffering); the streaming-to-browser cases stream the response body to a WordPress temp file via wp_tempnam() and then echo it back in 64 KB chunks, with HTTP 206 Range support preserved by forwarding the Range header. The Dropbox content-type issue is solved by sending Content-Type: application/octet-stream, which Dropbox accepts on /files/download and /files/get_thumbnail_v2. The plugin no longer contains a single curl_*() or CURLOPT_* reference in its own code; only the Freemius licensing SDK in vendor/ still uses cURL, which the Plugin Review Team's guidelines explicitly permit for third-party vendor libraries.banner-*.{png,jpg}, icon-*.{png,jpg,svg}, screenshot-*.{png,jpg}, blueprints/ or header.png files exist in the plugin ZIP, and that all plugin-resource references use the dynamic functions plugins_url() / plugin_dir_path() / plugin_dir_url() (via the CCGAL_URL / CCGAL_DIR constants) rather than hardcoded /wp-content/plugins/... paths. Listing assets (banner, icon, screenshots) are prepared in the source repository under .wordpress-org/ for deployment to the SVN /assets/ root after approval — they are deliberately excluded from the plugin ZIP per the Plugin Assets handbook.state.viewedInLightbox Set in assets/js/gallery.js is now cleared when the lightbox closes, so a visitor who closes the lightbox and reopens the same image is counted as a new engagement (the server-side 10-minute dedup window still applies on top of this — see below).$wpdb->insert() calls in record_view, record_image_view and record_download now log to error_log() if the insert fails (gated on WP_DEBUG), so future silent-skip failures are observable instead of being swallowed by a 200 OK response.includes/class-dashboard__premium_only.php): the "Reset tracking data" button on the gallery detail page AND the per-visitor "Daten löschen" button now correctly delete favorites in addition to views and downloads. Previously the favorites table was untouched, so the UI promise ("Deletes all favorites, downloads and views") was not honoured and the per-visitor delete looked like a no-op when the visitor had only favorited images and no other activity.includes/class-tracking__premium_only.php::get_gallery_stats): the top-card counter now counts distinct cookies across ALL activity tables (views ∪ favorites ∪ downloads), not just page-load views. Previously the counter only saw visitors who had a file_id IS NULL row, so visitors whose page-load was suppressed by the 1-hour dedup window or who arrived via a full-page cache (no PHP execution) — and only triggered AJAX-based image-views or downloads — were invisible to the top counter even though they correctly appeared in the "Besucheraktivität" table below. Both numbers now agree.class-tracking__premium_only.php). Free has zero stats footprint on disk; Pro hooks into the Free build via generic action/filter names (e.g. ccgal_download_completed, ccgal_gallery_deleted, ccgal_uninstall_tables) so the Free code stays decoupled.recordView()/recordImageView() functions and the trackBulkComplete() beacon are gone. The Free gallery.js now only dispatches generic ccgal:gallery-opened / ccgal:image-opened CustomEvents; the bulk-download helper calls a renamed notifyBulkCompleted ping to a ccgal_notify_bulk_complete AJAX endpoint. None of those reach a database table in Free.ccgal_/CCGAL_/ccgal- prefix to comply with the wp.org "prefix must be over 4 characters" rule. The browser visitor cookie keeps its legacy name wpg_visitor so existing visitor favourites remain attached after the migration — the only intentional exception._system_page meta marker, the daily cron event and the thumbnail cache directory. The routine excludes its own version-marker option from the bulk rename (so the guard can still be read on a re-activation if anything below crashes), extends set_time_limit(300) for large postmeta tables, and writes a transient admin notice if a RENAME TABLE fails (e.g. missing ALTER permission on shared hosting). Shortcodes in existing post_content are rewritten in place ([ccg_gallery], [hochzeitsgalerie], [customer_cloud_gallery] → [ccgal_gallery]; same for the print variant). The migration guards against re-runs via the legacy/new db-version markers.ccgal_serve_image and ccgal_stream_video now require a gallery-scoped nonce (ccgal_gallery_<id>) issued by the gallery renderer, in addition to the existing file-in-folder check. Draft / private / trashed galleries are rejected on the public branch unless the caller has edit_post capability. $_SERVER['HTTP_RANGE'] is now unslashed and length-capped before the strict preg_match validator. $_COOKIE['wpg_visitor'] is now sanitized through a hex-only whitelist matching the generator. $_REQUEST['gallery'], $_REQUEST['count'] and the array-branch of $_REQUEST['files'] are now consistently wp_unslash()-ed before further sanitization. json_decode() of the _REQUEST['files'] payload runs with depth=4 so a JSON bomb cannot DoS the file-IDs parser.Plugin URI header has been removed from the main plugin file because the SSL certificate for the linked domain is not yet provisioned. The Author URI is unaffected.ccgal_download_manifest exposes the gallery's file list (JSON: id/name/size) under the same gallery-scoped nonce; a separate completion endpoint (renamed to ccgal_notify_bulk_complete in 1.12.1) fires a single ccgal_download_completed action when the client-side ZIP is finished, so extension modules can react without per-file inserts. New assets/js/sw-zip.js service worker is registered on demand from the gallery scope and only activated when the bulk-download button is used. Manifests are cached as 60-second transients per gallery to protect Drive/Dropbox API quota against repeated clicks. The legacy ccgal_download_zip endpoint is unchanged.__premium_only.php suffix so the Free build no longer ships any Pro implementation code. Inline <script> blocks moved out of PHP into proper enqueued asset files for better caching and CSP compatibility.customer_cloud_gallery and customer_cloud_gallery_print shortcodes have been removed. The new prefixed shortcodes [ccgal_gallery] and [ccgal_print] are now the only supported names. Existing pages are automatically migrated on plugin update — the post content is rewritten in place once, so no user action is required.unlink() with wp_delete_file() in cache, adapters and uninstaller; switched DOS-timestamp generation in the ZIP streamer from date() to gmdate() to avoid runtime-timezone side effects; added missing translators: comments on plural and placeholder strings in dashboard and orders admin; reordered placeholder example text to use positional %1$s/%2$s syntax; rewrote printf( esc_html__( "…#%d" ), $id ) patterns in email templates and admin notices as echo esc_html( sprintf( __( "…" ), $id ) ) so the placeholder substitution is itself escaped.$wpdb->prepare() results across an assignment (visitor-stats aggregation in class-tracking.php and the orders CSV-export query in class-orders.php). The CSV-export ternary was also split into a clean if/else so each branch can carry its own technical justification; behaviour is unchanged.php://output streams in CSV export handlers (class-orders.php, class-dashboard.php) and best-effort cache hygiene calls (@touch, @rename in class-cache.php). The Dropbox adapter's paired fopen/fclose around cURL CURLOPT_FILE are documented inline since cURL requires a real PHP file pointer. Uninstaller rmdir() calls were already annotated in 1.11.6.class-google-drive-adapter.php::get_media_download_url to wp_remote_head() (HEAD with redirection => 0 to read the Location header). All remaining cURL calls — Drive stream_to_output, Dropbox download_to_file / stream_to_output / download_thumbnail — are kept and annotated with technical reasons: WP HTTP API has no streaming-write callback (CURLOPT_WRITEFUNCTION) and Dropbox content endpoints require an empty Content-Type header that wp_remote_post() cannot send. Migrating these to WP HTTP API would have forced double I/O via temp files for every gallery download.phpcs:disable blocks with technical justifications across class-tracking.php, class-orders.php, class-print-settings.php, class-rest-api.php, class-admin.php, class-downloads.php, class-print-page.php, class-google-oauth.php, class-dropbox-oauth.php. Direct database queries on plugin-owned custom tables (wp_ccgal_orders, wp_ccgal_order_items, wp_ccgal_views, wp_ccgal_favorites, wp_ccgal_downloads) are by design — they are not cached because they are written and read inside the same request lifecycle. Nonce-verification suppressions on read-only listing/sort/filter parameters are paired with concrete justifications. OAuth callbacks use the OAuth state parameter instead of WordPress nonces (a session-bound nonce cannot survive a redirect through Google/Dropbox). Outbound wp_redirect() calls (OAuth auth endpoint, signed Drive media URLs) are kept because wp_safe_redirect() would block external hosts. Added missing wp_unslash() calls on $_COOKIE['ccgal_visitor'] and $_SERVER['REMOTE_ADDR'] in class-tracking.php and class-print-rest.php.class-tracking.php::ip_hash, class-print-rest.php::get_visitor_id) now uses filter_var( …, FILTER_VALIDATE_IP ) instead of sanitize_text_field — sanitize_text_field strips %xx sequences and would mangle IPv6 zone-id syntax (e.g. fe80::1%eth0).class-google-drive-adapter.php::get_media_download_url now handles the case where wp_remote_retrieve_header() returns an array of duplicate Location headers (rare but possible behind some CDN layers); previously the array would be cast to the literal string "Array" and the call would falsely return ccgal_bad_location.class-rest-api.php::serve_image now use wp_safe_redirect() instead of wp_redirect() — the targets are same-origin cache URLs, so the safer redirect is appropriate.paypal.me/USERNAME/25.00EUR). Previously the link omitted the currency, so PayPal would default to the receiver's account currency (often USD for new accounts), forcing customers to pay in the wrong currency.CCGAL_Welcome::render_drive_setup_guide(), render_dropbox_setup_guide()) and emit byte-identical translatable strings.admin_menu priority 9999 and resolves the URL via menu_page_url(), with a graceful fallback to the gallery list page.wp_set_script_translations() for the ccgal-gallery, ccgal-admin and ccgal-print scripts so JS strings can be translated through the standard language-pack system.ccgal_print_formats, ccgal_paper_price_lists, OAuth tokens, payment/email settings, etc.) are now stored with autoload=false to avoid loading them on every page request site-wide.wp_next_scheduled() on every page load.class-orders.php order list query refactored to use %i placeholder for the column identifier and a strict literal toggle for ASC/DESC, with documented phpcs:ignore on the few remaining intentional interpolations.class-text-overrides.php translate() call uses a literal text-domain and documented phpcs:ignore on the dynamic msgid lookup (the override mechanism is dynamic by design).readme.txt — the visitor cookie value is a random identifier stored as-is, and it is the IP address that is stored as a salted SHA-256 hash (not the cookie ID).printf( esc_html__( ... ), '<a ...>...' ) patterns with wp_kses( sprintf( __( ... ), ... ), $allowed ) so format-string output is correctly escaped while link tags are explicitly whitelisted.wp_safe_redirect() instead of wp_redirect().$_POST['order_id'].esc_url_raw() for defence-in-depth.Author URI from the plugin header (matched Plugin URI, which the WordPress.org review process disallows).button:focus globally — now reset via :focus:not(:focus-visible) so the base appearance is restored on mouse-click; keyboard focus styling unchangeduninstall.php and moved the cleanup logic into the Freemius after_uninstall hook (CCGAL_Uninstaller::cleanup) — required by Freemius deployment policyccgal-print-options so bookmarks survive Free→Pro upgradewp_redirect() to wp_safe_redirect() for consistencyccgal_allow_print post-meta with WordPress for proper authorization handlingwp-galerie to customer-cloud-gallery (matches new wp.org plugin slug)text-transform: capitalize — resolved with text-transform: none on .ccgal-btn