Changeset 3004370
- Timestamp:
- 12/01/2023 05:46:36 PM (2 years ago)
- Location:
- nextgen-gallery/trunk
- Files:
-
- 2 deleted
- 26 edited
-
assets/css/admin.css (modified) (1 diff)
-
assets/css/admin.min.css (modified) (1 diff)
-
assets/scss/admin.scss (modified) (2 diffs)
-
changelog.txt (modified) (1 diff)
-
composer.json (modified) (1 diff)
-
composer.lock (modified) (4 diffs)
-
nggallery.php (modified) (5 diffs)
-
products/photocrati_nextgen/modules/legacy_compat/module.legacy_compat.php (modified) (2 diffs)
-
products/photocrati_nextgen/modules/legacy_compat/package.module.legacy_compat.php (modified) (3 diffs)
-
products/photocrati_nextgen/modules/marketing/module.marketing.php (modified) (1 diff)
-
products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php (modified) (1 diff)
-
readme.txt (modified) (2 diffs)
-
src/DataStorage/Manager.php (modified) (4 diffs)
-
src/DataTypes/Image.php (modified) (1 diff)
-
src/Display/DisplayManager.php (modified) (1 diff)
-
src/Display/StaticAssets.php (modified) (1 diff)
-
src/DisplayType/LegacyTemplateLocator.php (modified) (1 diff)
-
src/IGW/ATPManager.php (modified) (1 diff)
-
src/Legacy/admin/manage-galleries.php (modified) (1 diff)
-
src/Legacy/admin/manage.php (modified) (1 diff)
-
src/Views (deleted)
-
vendor/autoload.php (modified) (1 diff)
-
vendor/composer/ClassLoader.php (modified) (25 diffs)
-
vendor/composer/InstalledVersions.php (modified) (4 diffs)
-
vendor/composer/autoload_real.php (modified) (3 diffs)
-
vendor/composer/autoload_static.php (modified) (2 diffs)
-
vendor/composer/installed.json (modified) (1 diff)
-
vendor/imagely/pope-framework/.gitignore (deleted)
Legend:
- Unmodified
- Added
- Removed
-
nextgen-gallery/trunk/assets/css/admin.css
r3003333 r3004370 1 .wp-core-ui .button.nextgen-button{border-radius:6px}.wp-core-ui .nextgen-primary-button{border-color:#000;color:#fff;background-color:#000;-webkit-transition:background-color 100ms linear;-ms-transition:background-color 100ms linear;transition:background-color 100ms linear;padding:6px 16px;font-weight:700}.wp-core-ui .nextgen-primary-button:focus,.wp-core-ui .nextgen-primary-button:hover{background:rgba(0,0,0,.8);border-color:rgba(0,0,0,.8);color:#fff;box-shadow:none}.wp-core-ui .nextgen-secondary-button{border:1px solid rgba(96,96,96,.3019607843);color:#282828;background-color:#fff;box-shadow:none;border-radius:4px;padding:6px 16px;font-weight:700;-webkit-transition:background-color 100ms linear;-ms-transition:background-color 100ms linear;transition:background-color 100ms linear}.wp-core-ui .nextgen-secondary-button:focus,.wp-core-ui .nextgen-secondary-button:hover{border-color:#ebebeb;color:#646464;background-color:#ebebeb;box-shadow:0 2px 5px rgba(0,0,0,.08)}.wp-core-ui .nextgen-green-button{border-color:#618e00;color:#fff;background-color:#618e00;border-radius:4px;-webkit-transition:background-color 100ms linear;-ms-transition:background-color 100ms linear;transition:background-color 100ms linear}.wp-core-ui .nextgen-green-button:focus,.wp-core-ui .nextgen-green-button:hover{background:#87a20e;border-color:#87a20e;color:#fff;box-shadow:none}.wp-core-ui .nextgen-button-blue{border-color:#3871ac;color:#fff;background-color:#3871ac;border-radius:4px;-webkit-transition:opacity 100ms linear;-ms-transition:opacity 100ms linear;transition:opacity 100ms linear}.wp-core-ui .nextgen-button-blue:focus,.wp-core-ui .nextgen-button-blue:hover{background-color:#3871ac;border-color:#3871ac;opacity:.75;color:#fff;box-shadow:none}#nextgen-header-temp{position:relative;display:none}#nextgen-top-notification{border-top:3px solid #87a20e;position:relative;background-color:#eee;text-align:center;color:rgba(60,67,74,.8);height:40px;vertical-align:middle;border-bottom:1px solid #ddd}#nextgen-top-notification.nextgen-pro-active{height:0}#nextgen-top-notification.nextgen-pro-active p{visibility:hidden}#nextgen-top-notification p{margin:0;padding:0;line-height:40px;font-size:13px}#nextgen-top-notification a{color:#87a20e;font-size:13px}#nextgen-top-notification .nextgen-dismiss{position:absolute;top:10px;right:10px}#nextgen-header{background-color:#fff;background-repeat:repeat;height:120px;display:flex;justify-content:space-between;align-items:center;box-shadow:0px 1px 2px 0px rgba(0,0,0,.0588235294)}@media(max-width: 599px){#nextgen-header{padding-top:46px}}#nextgen-header h1.nextgen-logo{margin:0;margin-left:20px}#nextgen-header h1.nextgen-logo img{max-width:339px}@media(min-width: 600px)and (max-width: 767px){#nextgen-header h1.nextgen-logo img{width:90%}}#nextgen-header .nextgen-right{padding-right:20px}#nextgen-header .nextgen-notifications-inbox{position:relative}#nextgen-header .nextgen-notifications-inbox[data-count]:after{background:#e02626;border-radius:50%;bottom:100%;color:#fff;content:attr(data-count);display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:700;height:16px;left:100%;line-height:18px;min-width:16px;position:absolute;text-align:center;transform:translate(-40%, 30%)}.nextgen-notifications-close:hover,.nextgen-notifications-inbox:hover{cursor:pointer}.nextgen-notifications-drawer{box-sizing:border-box;background:#fff;bottom:0;position:fixed;right:-400px;top:32px;transition:right 300ms ease 0s,visibility 0s ease 400ms;visibility:hidden;width:400px;z-index:1100;border:1px solid #ddd}.nextgen-notifications-open .nextgen-notifications-drawer{right:0;transition:right 300ms ease 0s,visibility 0s ease 0ms;visibility:visible}.nextgen-notifications-overlay{background-color:rgba(0,0,0,.3);bottom:0;display:none;left:0;opacity:.5;position:fixed;right:0;top:46px;transition:.5s;z-index:1052}.folded .nextgen-notifications-overlay{left:36px}.nextgen-notifications-open .nextgen-notifications-overlay{display:block}@media screen and (min-width: 783px){.nextgen-notifications-overlay{left:36px}.admin-bar .nextgen-notifications-overlay{top:32px}}@media screen and (min-width: 961px){.nextgen-notifications-overlay{left:160px}.folded .nextgen-notifications-overlay{left:36px}}.nextgen-notifications-header{background:#eee;border-bottom:1px solid #ddd;padding:18px 40px 18px 20px}.nextgen-notifications-header .nextgen-notifications-close{position:absolute;right:18px;top:22px}.nextgen-notifications-header .nextgen-notifications-close path{fill:#3c434a}.nextgen-notifications-header h3{color:#3c434a;display:inline-block;font-size:14px;font-weight:700;line-height:21px;margin:0 10px 0 0}.nextgen-notifications-list{height:calc(100% - 130px);overflow:auto}.nextgen-notifications-list ul{margin:0}.nextgen-notifications-list li{border-bottom:1px solid #ddd;display:flex;margin:0;padding:24px;font-size:14px;color:rgba(60,67,74,.6)}.nextgen-notifications-list li:first-child{border-top:none}.nextgen-notifications-list li h4{color:#3c4249;font-size:14px;font-weight:600;line-height:21px;margin:0}.nextgen-notifications-list p{color:rgba(60,67,74,.6);font-size:14px;margin:8px 0;margin-bottom:20px}.nextgen-notifications-list p.nextgen-start{font-size:12px}.nextgen-notifications-list .nextgen-button{padding:8px 14px;border-radius:4px;text-decoration:none;font-size:12px}.nextgen-notifications-list .nextgen-button.nextgen-button-primary{background-color:#37993b;color:#fff}.nextgen-notifications-list .nextgen-button.nextgen-button-secondary{border:1px solid #ddd}.nextgen-button-text{font-size:12px;color:rgba(60,67,74,.6980392157)}.nextgen-notification-actions .nextgen-button{margin-right:10px}.nextgen-notifications-footer{border-top:1px solid #ddd;padding:24px 27px;text-align:right}#nextgen-dismissed-title,#nextgen-notifications-show-active,.nextgen-notifications-dismissed{display:none}.show-dismissed #nextgen-notifications-show-dismissed,.show-dismissed .nextgen-notifications-active,.show-dismissed #nextgen-active-title{display:none}.show-dismissed #nextgen-notifications-show-active,.show-dismissed #nextgen-dismissed-title{display:inline-block}.show-dismissed .nextgen-notifications-dismissed{display:block}.nextgen-notifications-dismissed .nextgen-notification-dismiss{display:none}.nextgen-notification-icon{margin-right:10px}body.toplevel_page_nextgen-gallery #wpcontent,body[class*=" nextgen-gallery_page_"] #wpcontent,body[class*=" ngg-"] #wpcontent{padding-left:0}body.toplevel_page_nextgen-gallery #wpfooter,body[class*=" nextgen-gallery_page_"] #wpfooter,body[class*=" ngg-"] #wpfooter{margin-top:auto;position:relative;clear:both}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion{text-align:center;font-weight:400;font-size:13px;line-height:normal;color:#646970;padding:30px 0;margin-bottom:20px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links{margin:10px 0;color:#646970}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links span,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links span,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links span{color:#c3c4c7;padding:0 7px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{display:flex;justify-content:center;align-items:center}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{gap:10px;margin:0}.nextgen-nav-tab-wrapper{display:flex;flex-wrap:wrap;gap:0 30px;margin:0 0 20px 0;background-color:rgba(0,0,0,0);list-style:none;font-size:16px;font-weight:400;margin:30px 20px;border-bottom:1px solid rgba(96,96,96,.1490196078)}.nextgen-nav-tab-wrapper li{margin:0;padding:0}.nextgen-nav-tab-wrapper li a{display:block;padding:15px 0 12px 0;line-height:30px;border-bottom:3px solid #fff;box-shadow:none;color:#2c3338;text-decoration:none}.nextgen-nav-tab-wrapper .nextgen-nav-tab:hover,.nextgen-nav-tab-wrapper .nextgen-nav-tab-active{border-bottom:4px solid #618e00;font-weight:600}.nextgen-admin-content{position:relative}.nextgen-admin-content .nextgen-admin-modal *,.nextgen-admin-content .nextgen-admin-modal *::before,.nextgen-admin-content .nextgen-admin-modal *::after{-moz-box-sizing:border-box;box-sizing:border-box}.nextgen-admin-content .nextgen-admin-modal{text-align:center;width:730px;box-shadow:0 0 60px 30px rgba(0,0,0,.15);background-color:#fff;border-radius:6px;position:absolute;top:95px;left:50%;margin:0 auto 0 -365px;z-index:9999;overflow:hidden}.nextgen-admin-content .nextgen-admin-modal h2{font-size:20px;margin:0 0 16px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal p{font-size:16px;line-height:24px;color:#777;margin:0 0 30px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal ul{float:left;width:50%;margin:0;padding:0 0 0 30px;text-align:left}.nextgen-admin-content .nextgen-admin-modal li{color:#777;font-size:16px;line-height:28px;padding:6px 0;display:flex}.nextgen-admin-content .nextgen-admin-modal li svg{padding-right:10px}.nextgen-admin-content .nextgen-admin-modal-content{border-radius:3px 3px 0 0;padding:40px}.nextgen-admin-content .nextgen-admin-model-lists{width:100%}.nextgen-admin-content .nextgen-green-button{font-size:18px;text-align:center;padding:6px 16px;margin:30px 0}.nextgen-admin-content .nextgen-admin-modal-bonus{position:relative;padding:30px;background:#f5f5f5;text-align:center}.nextgen-admin-content .nextgen-admin-modal-bonus p{font-size:14px;margin:0px}.nextgen-admin-content .nextgen-admin-modal-bonus svg{position:absolute;border-radius:50%;top:-14px;background-color:#fff}.nextgen-admin-content .nextgen-admin-modal-text-link{display:block;margin:15px 0;font-size:14px;color:rgba(60,67,74,.6980392157)}.nextgen-admin-content .button.nextgen-button{font-size:21px;height:50px;line-height:48px;background-color:#618e00}.nextgen-admin-content .wrap{-webkit-filter:blur(3px);-moz-filter:blur(3px);-ms-filter:blur(3px);-o-filter:blur(3px);filter:blur(3px)}.nextgen-admin-content .wrap:hover>*{pointer-events:none !important}.nextgen-admin-content .nextgen-clear,.nextgen-admin-content .nextgen-clear::before,.nextgen-admin-content .nextgen-clear::after{content:" ";display:table}.nextgen-green{color:#87a20e}@media(max-height: 1300px){.nextgen-admin-content .nextgen-admin-modal{top:30px}}1 .wp-core-ui .button.nextgen-button{border-radius:6px}.wp-core-ui .nextgen-primary-button{border-color:#000;color:#fff;background-color:#000;-webkit-transition:background-color 100ms linear;-ms-transition:background-color 100ms linear;transition:background-color 100ms linear;padding:6px 16px;font-weight:700}.wp-core-ui .nextgen-primary-button:focus,.wp-core-ui .nextgen-primary-button:hover{background:rgba(0,0,0,.8);border-color:rgba(0,0,0,.8);color:#fff;box-shadow:none}.wp-core-ui .nextgen-secondary-button{border:1px solid rgba(96,96,96,.3019607843);color:#282828;background-color:#fff;box-shadow:none;border-radius:4px;padding:6px 16px;font-weight:700;-webkit-transition:background-color 100ms linear;-ms-transition:background-color 100ms linear;transition:background-color 100ms linear}.wp-core-ui .nextgen-secondary-button:focus,.wp-core-ui .nextgen-secondary-button:hover{border-color:#ebebeb;color:#646464;background-color:#ebebeb;box-shadow:0 2px 5px rgba(0,0,0,.08)}.wp-core-ui .nextgen-green-button{border-color:#618e00;color:#fff;background-color:#618e00;border-radius:4px;-webkit-transition:background-color 100ms linear;-ms-transition:background-color 100ms linear;transition:background-color 100ms linear}.wp-core-ui .nextgen-green-button:focus,.wp-core-ui .nextgen-green-button:hover{background:#87a20e;border-color:#87a20e;color:#fff;box-shadow:none}.wp-core-ui .nextgen-button-blue{border-color:#3871ac;color:#fff;background-color:#3871ac;border-radius:4px;-webkit-transition:opacity 100ms linear;-ms-transition:opacity 100ms linear;transition:opacity 100ms linear}.wp-core-ui .nextgen-button-blue:focus,.wp-core-ui .nextgen-button-blue:hover{background-color:#3871ac;border-color:#3871ac;opacity:.75;color:#fff;box-shadow:none}#nextgen-header-temp{position:relative;display:none}#nextgen-top-notification{border-top:3px solid #87a20e;position:relative;background-color:#eee;text-align:center;color:rgba(60,67,74,.8);height:40px;vertical-align:middle;border-bottom:1px solid #ddd}#nextgen-top-notification.nextgen-pro-active{height:0}#nextgen-top-notification.nextgen-pro-active p{visibility:hidden}#nextgen-top-notification p{margin:0;padding:0;line-height:40px;font-size:13px}#nextgen-top-notification a{color:#87a20e;font-size:13px}#nextgen-top-notification .nextgen-dismiss{position:absolute;top:10px;right:10px}#nextgen-header{background-color:#fff;background-repeat:repeat;height:120px;display:flex;justify-content:space-between;align-items:center;box-shadow:0px 1px 2px 0px rgba(0,0,0,.0588235294)}@media(max-width: 599px){#nextgen-header{padding-top:46px}}#nextgen-header h1.nextgen-logo{margin:0;margin-left:20px}#nextgen-header h1.nextgen-logo img{max-width:339px}@media(min-width: 600px)and (max-width: 767px){#nextgen-header h1.nextgen-logo img{width:90%}}#nextgen-header .nextgen-right{padding-right:20px}#nextgen-header .nextgen-notifications-inbox{position:relative}#nextgen-header .nextgen-notifications-inbox[data-count]:after{background:#e02626;border-radius:50%;bottom:100%;color:#fff;content:attr(data-count);display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:700;height:16px;left:100%;line-height:18px;min-width:16px;position:absolute;text-align:center;transform:translate(-40%, 30%)}.nextgen-notifications-close:hover,.nextgen-notifications-inbox:hover{cursor:pointer}.nextgen-notifications-drawer{box-sizing:border-box;background:#fff;bottom:0;position:fixed;right:-400px;top:32px;transition:right 300ms ease 0s,visibility 0s ease 400ms;visibility:hidden;width:400px;z-index:1100;border:1px solid #ddd}.nextgen-notifications-open .nextgen-notifications-drawer{right:0;transition:right 300ms ease 0s,visibility 0s ease 0ms;visibility:visible}.nextgen-notifications-overlay{background-color:rgba(0,0,0,.3);bottom:0;display:none;left:0;opacity:.5;position:fixed;right:0;top:46px;transition:.5s;z-index:1052}.folded .nextgen-notifications-overlay{left:36px}.nextgen-notifications-open .nextgen-notifications-overlay{display:block}@media screen and (min-width: 783px){.nextgen-notifications-overlay{left:36px}.admin-bar .nextgen-notifications-overlay{top:32px}}@media screen and (min-width: 961px){.nextgen-notifications-overlay{left:160px}.folded .nextgen-notifications-overlay{left:36px}}.nextgen-notifications-header{background:#eee;border-bottom:1px solid #ddd;padding:18px 40px 18px 20px}.nextgen-notifications-header .nextgen-notifications-close{position:absolute;right:18px;top:22px}.nextgen-notifications-header .nextgen-notifications-close path{fill:#3c434a}.nextgen-notifications-header h3{color:#3c434a;display:inline-block;font-size:14px;font-weight:700;line-height:21px;margin:0 10px 0 0}.nextgen-notifications-list{height:calc(100% - 130px);overflow:auto}.nextgen-notifications-list ul{margin:0}.nextgen-notifications-list li{border-bottom:1px solid #ddd;display:flex;margin:0;padding:24px;font-size:14px;color:rgba(60,67,74,.6)}.nextgen-notifications-list li:first-child{border-top:none}.nextgen-notifications-list li h4{color:#3c4249;font-size:14px;font-weight:600;line-height:21px;margin:0}.nextgen-notifications-list p{color:rgba(60,67,74,.6);font-size:14px;margin:8px 0;margin-bottom:20px}.nextgen-notifications-list p.nextgen-start{font-size:12px}.nextgen-notifications-list .nextgen-button{padding:8px 14px;border-radius:4px;text-decoration:none;font-size:12px}.nextgen-notifications-list .nextgen-button.nextgen-button-primary{background-color:#37993b;color:#fff}.nextgen-notifications-list .nextgen-button.nextgen-button-secondary{border:1px solid #ddd}.nextgen-button-text{font-size:12px;color:rgba(60,67,74,.6980392157)}.nextgen-notification-actions .nextgen-button{margin-right:10px}.nextgen-notifications-footer{border-top:1px solid #ddd;padding:24px 27px;text-align:right}#nextgen-dismissed-title,#nextgen-notifications-show-active,.nextgen-notifications-dismissed{display:none}.show-dismissed #nextgen-notifications-show-dismissed,.show-dismissed .nextgen-notifications-active,.show-dismissed #nextgen-active-title{display:none}.show-dismissed #nextgen-notifications-show-active,.show-dismissed #nextgen-dismissed-title{display:inline-block}.show-dismissed .nextgen-notifications-dismissed{display:block}.nextgen-notifications-dismissed .nextgen-notification-dismiss{display:none}.nextgen-notification-icon{margin-right:10px}body.toplevel_page_nextgen-gallery #wpcontent,body[class*=" nextgen-gallery_page_"] #wpcontent,body[class*=" ngg-"] #wpcontent{padding-left:0}body.toplevel_page_nextgen-gallery .ui-widget .ui-dialog-titlebar-close,body[class*=" nextgen-gallery_page_"] .ui-widget .ui-dialog-titlebar-close,body[class*=" ngg-"] .ui-widget .ui-dialog-titlebar-close{text-indent:-9999px;background:none;border:none;box-shadow:none}body.toplevel_page_nextgen-gallery #wpfooter,body[class*=" nextgen-gallery_page_"] #wpfooter,body[class*=" ngg-"] #wpfooter{margin-top:auto;position:relative;clear:both}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion{text-align:center;font-weight:400;font-size:13px;line-height:normal;color:#646970;padding:30px 0;margin-bottom:20px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links{margin:10px 0;color:#646970}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links span,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links span,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links span{color:#c3c4c7;padding:0 7px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{display:flex;justify-content:center;align-items:center}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{gap:10px;margin:0}.nextgen-nav-tab-wrapper{display:flex;flex-wrap:wrap;gap:0 30px;margin:0 0 20px 0;background-color:rgba(0,0,0,0);list-style:none;font-size:16px;font-weight:400;margin:30px 20px;border-bottom:1px solid rgba(96,96,96,.1490196078)}.nextgen-nav-tab-wrapper li{margin:0;padding:0}.nextgen-nav-tab-wrapper li a{display:block;padding:15px 0 12px 0;line-height:30px;border-bottom:3px solid #fff;box-shadow:none;color:#2c3338;text-decoration:none}.nextgen-nav-tab-wrapper .nextgen-nav-tab:hover,.nextgen-nav-tab-wrapper .nextgen-nav-tab-active{border-bottom:4px solid #618e00;font-weight:600}.nextgen-admin-content{position:relative}.nextgen-admin-content .nextgen-admin-modal *,.nextgen-admin-content .nextgen-admin-modal *::before,.nextgen-admin-content .nextgen-admin-modal *::after{-moz-box-sizing:border-box;box-sizing:border-box}.nextgen-admin-content .nextgen-admin-modal{text-align:center;width:730px;box-shadow:0 0 60px 30px rgba(0,0,0,.15);background-color:#fff;border-radius:6px;position:absolute;top:95px;left:50%;margin:0 auto 0 -365px;z-index:9999;overflow:hidden}.nextgen-admin-content .nextgen-admin-modal h2{font-size:20px;margin:0 0 16px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal p{font-size:16px;line-height:24px;color:#777;margin:0 0 30px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal ul{float:left;width:50%;margin:0;padding:0 0 0 30px;text-align:left}.nextgen-admin-content .nextgen-admin-modal li{color:#777;font-size:16px;line-height:28px;padding:6px 0;display:flex}.nextgen-admin-content .nextgen-admin-modal li svg{padding-right:10px}.nextgen-admin-content .nextgen-admin-modal-content{border-radius:3px 3px 0 0;padding:40px}.nextgen-admin-content .nextgen-admin-model-lists{width:100%}.nextgen-admin-content .nextgen-green-button{font-size:18px;text-align:center;padding:6px 16px;margin:30px 0}.nextgen-admin-content .nextgen-admin-modal-bonus{position:relative;padding:30px;background:#f5f5f5;text-align:center}.nextgen-admin-content .nextgen-admin-modal-bonus p{font-size:14px;margin:0px}.nextgen-admin-content .nextgen-admin-modal-bonus svg{position:absolute;border-radius:50%;top:-14px;background-color:#fff}.nextgen-admin-content .nextgen-admin-modal-text-link{display:block;margin:15px 0;font-size:14px;color:rgba(60,67,74,.6980392157)}.nextgen-admin-content .button.nextgen-button{font-size:21px;height:50px;line-height:48px;background-color:#618e00}.nextgen-admin-content .wrap{-webkit-filter:blur(3px);-moz-filter:blur(3px);-ms-filter:blur(3px);-o-filter:blur(3px);filter:blur(3px)}.nextgen-admin-content .wrap:hover>*{pointer-events:none !important}.nextgen-admin-content .nextgen-clear,.nextgen-admin-content .nextgen-clear::before,.nextgen-admin-content .nextgen-clear::after{content:" ";display:table}.nextgen-green{color:#87a20e}@media(max-height: 1300px){.nextgen-admin-content .nextgen-admin-modal{top:30px}} -
nextgen-gallery/trunk/assets/css/admin.min.css
r3003333 r3004370 1 .wp-core-ui .button.nextgen-button{border-radius:6px}.wp-core-ui .nextgen-primary-button{border-color:#000;color:#fff;background-color:#000;-webkit-transition:background-color .1s linear;-ms-transition:background-color .1s linear;transition:background-color .1s linear;padding:6px 16px;font-weight:700}.wp-core-ui .nextgen-primary-button:focus,.wp-core-ui .nextgen-primary-button:hover{background:rgba(0,0,0,.8);border-color:rgba(0,0,0,.8);color:#fff;box-shadow:none}.wp-core-ui .nextgen-secondary-button{border:1px solid rgba(96,96,96,.3019607843);color:#282828;background-color:#fff;box-shadow:none;border-radius:4px;padding:6px 16px;font-weight:700;-webkit-transition:background-color .1s linear;-ms-transition:background-color .1s linear;transition:background-color .1s linear}.wp-core-ui .nextgen-secondary-button:focus,.wp-core-ui .nextgen-secondary-button:hover{border-color:#ebebeb;color:#646464;background-color:#ebebeb;box-shadow:0 2px 5px rgba(0,0,0,.08)}.wp-core-ui .nextgen-green-button{border-color:#618e00;color:#fff;background-color:#618e00;border-radius:4px;-webkit-transition:background-color .1s linear;-ms-transition:background-color .1s linear;transition:background-color .1s linear}.wp-core-ui .nextgen-green-button:focus,.wp-core-ui .nextgen-green-button:hover{background:#87a20e;border-color:#87a20e;color:#fff;box-shadow:none}.wp-core-ui .nextgen-button-blue{border-color:#3871ac;color:#fff;background-color:#3871ac;border-radius:4px;-webkit-transition:opacity .1s linear;-ms-transition:opacity .1s linear;transition:opacity .1s linear}.wp-core-ui .nextgen-button-blue:focus,.wp-core-ui .nextgen-button-blue:hover{background-color:#3871ac;border-color:#3871ac;opacity:.75;color:#fff;box-shadow:none}#nextgen-header-temp{position:relative;display:none}#nextgen-top-notification{border-top:3px solid #87a20e;position:relative;background-color:#eee;text-align:center;color:rgba(60,67,74,.8);height:40px;vertical-align:middle;border-bottom:1px solid #ddd}#nextgen-top-notification.nextgen-pro-active{height:0}#nextgen-top-notification.nextgen-pro-active p{visibility:hidden}#nextgen-top-notification p{margin:0;padding:0;line-height:40px;font-size:13px}#nextgen-top-notification a{color:#87a20e;font-size:13px}#nextgen-top-notification .nextgen-dismiss{position:absolute;top:10px;right:10px}#nextgen-header{background-color:#fff;background-repeat:repeat;height:120px;display:flex;justify-content:space-between;align-items:center;box-shadow:0 1px 2px 0 rgba(0,0,0,.0588235294)}@media(max-width:599px){#nextgen-header{padding-top:46px}}#nextgen-header h1.nextgen-logo{margin:0;margin-left:20px}#nextgen-header h1.nextgen-logo img{max-width:339px}@media(min-width:600px)and (max-width:767px){#nextgen-header h1.nextgen-logo img{width:90%}}#nextgen-header .nextgen-right{padding-right:20px}#nextgen-header .nextgen-notifications-inbox{position:relative}#nextgen-header .nextgen-notifications-inbox[data-count]:after{background:#e02626;border-radius:50%;bottom:100%;color:#fff;content:attr(data-count);display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:700;height:16px;left:100%;line-height:18px;min-width:16px;position:absolute;text-align:center;transform:translate(-40%,30%)}.nextgen-notifications-close:hover,.nextgen-notifications-inbox:hover{cursor:pointer}.nextgen-notifications-drawer{box-sizing:border-box;background:#fff;bottom:0;position:fixed;right:-400px;top:32px;transition:right .3s ease 0s,visibility 0s ease .4s;visibility:hidden;width:400px;z-index:1100;border:1px solid #ddd}.nextgen-notifications-open .nextgen-notifications-drawer{right:0;transition:right .3s ease 0s,visibility 0s ease 0s;visibility:visible}.nextgen-notifications-overlay{background-color:rgba(0,0,0,.3);bottom:0;display:none;left:0;opacity:.5;position:fixed;right:0;top:46px;transition:.5s;z-index:1052}.folded .nextgen-notifications-overlay{left:36px}.nextgen-notifications-open .nextgen-notifications-overlay{display:block}@media screen and (min-width:783px){.nextgen-notifications-overlay{left:36px}.admin-bar .nextgen-notifications-overlay{top:32px}}@media screen and (min-width:961px){.nextgen-notifications-overlay{left:160px}.folded .nextgen-notifications-overlay{left:36px}}.nextgen-notifications-header{background:#eee;border-bottom:1px solid #ddd;padding:18px 40px 18px 20px}.nextgen-notifications-header .nextgen-notifications-close{position:absolute;right:18px;top:22px}.nextgen-notifications-header .nextgen-notifications-close path{fill:#3c434a}.nextgen-notifications-header h3{color:#3c434a;display:inline-block;font-size:14px;font-weight:700;line-height:21px;margin:0 10px 0 0}.nextgen-notifications-list{height:calc(100% - 130px);overflow:auto}.nextgen-notifications-list ul{margin:0}.nextgen-notifications-list li{border-bottom:1px solid #ddd;display:flex;margin:0;padding:24px;font-size:14px;color:rgba(60,67,74,.6)}.nextgen-notifications-list li:first-child{border-top:none}.nextgen-notifications-list li h4{color:#3c4249;font-size:14px;font-weight:600;line-height:21px;margin:0}.nextgen-notifications-list p{color:rgba(60,67,74,.6);font-size:14px;margin:8px 0;margin-bottom:20px}.nextgen-notifications-list p.nextgen-start{font-size:12px}.nextgen-notifications-list .nextgen-button{padding:8px 14px;border-radius:4px;text-decoration:none;font-size:12px}.nextgen-notifications-list .nextgen-button.nextgen-button-primary{background-color:#37993b;color:#fff}.nextgen-notifications-list .nextgen-button.nextgen-button-secondary{border:1px solid #ddd}.nextgen-button-text{font-size:12px;color:rgba(60,67,74,.6980392157)}.nextgen-notification-actions .nextgen-button{margin-right:10px}.nextgen-notifications-footer{border-top:1px solid #ddd;padding:24px 27px;text-align:right}#nextgen-dismissed-title,#nextgen-notifications-show-active,.nextgen-notifications-dismissed{display:none}.show-dismissed #nextgen-active-title,.show-dismissed #nextgen-notifications-show-dismissed,.show-dismissed .nextgen-notifications-active{display:none}.show-dismissed #nextgen-dismissed-title,.show-dismissed #nextgen-notifications-show-active{display:inline-block}.show-dismissed .nextgen-notifications-dismissed{display:block}.nextgen-notifications-dismissed .nextgen-notification-dismiss{display:none}.nextgen-notification-icon{margin-right:10px}body.toplevel_page_nextgen-gallery #wpcontent,body[class*=" nextgen-gallery_page_"] #wpcontent,body[class*=" ngg-"] #wpcontent{padding-left:0}body.toplevel_page_nextgen-gallery #wpfooter,body[class*=" nextgen-gallery_page_"] #wpfooter,body[class*=" ngg-"] #wpfooter{margin-top:auto;position:relative;clear:both}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion{text-align:center;font-weight:400;font-size:13px;line-height:normal;color:#646970;padding:30px 0;margin-bottom:20px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links{margin:10px 0;color:#646970}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links span,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links span,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links span{color:#c3c4c7;padding:0 7px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{display:flex;justify-content:center;align-items:center}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{gap:10px;margin:0}.nextgen-nav-tab-wrapper{display:flex;flex-wrap:wrap;gap:0 30px;margin:0 0 20px 0;background-color:rgba(0,0,0,0);list-style:none;font-size:16px;font-weight:400;margin:30px 20px;border-bottom:1px solid rgba(96,96,96,.1490196078)}.nextgen-nav-tab-wrapper li{margin:0;padding:0}.nextgen-nav-tab-wrapper li a{display:block;padding:15px 0 12px 0;line-height:30px;border-bottom:3px solid #fff;box-shadow:none;color:#2c3338;text-decoration:none}.nextgen-nav-tab-wrapper .nextgen-nav-tab-active,.nextgen-nav-tab-wrapper .nextgen-nav-tab:hover{border-bottom:4px solid #618e00;font-weight:600}.nextgen-admin-content{position:relative}.nextgen-admin-content .nextgen-admin-modal *,.nextgen-admin-content .nextgen-admin-modal ::after,.nextgen-admin-content .nextgen-admin-modal ::before{-moz-box-sizing:border-box;box-sizing:border-box}.nextgen-admin-content .nextgen-admin-modal{text-align:center;width:730px;box-shadow:0 0 60px 30px rgba(0,0,0,.15);background-color:#fff;border-radius:6px;position:absolute;top:95px;left:50%;margin:0 auto 0 -365px;z-index:9999;overflow:hidden}.nextgen-admin-content .nextgen-admin-modal h2{font-size:20px;margin:0 0 16px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal p{font-size:16px;line-height:24px;color:#777;margin:0 0 30px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal ul{float:left;width:50%;margin:0;padding:0 0 0 30px;text-align:left}.nextgen-admin-content .nextgen-admin-modal li{color:#777;font-size:16px;line-height:28px;padding:6px 0;display:flex}.nextgen-admin-content .nextgen-admin-modal li svg{padding-right:10px}.nextgen-admin-content .nextgen-admin-modal-content{border-radius:3px 3px 0 0;padding:40px}.nextgen-admin-content .nextgen-admin-model-lists{width:100%}.nextgen-admin-content .nextgen-green-button{font-size:18px;text-align:center;padding:6px 16px;margin:30px 0}.nextgen-admin-content .nextgen-admin-modal-bonus{position:relative;padding:30px;background:#f5f5f5;text-align:center}.nextgen-admin-content .nextgen-admin-modal-bonus p{font-size:14px;margin:0}.nextgen-admin-content .nextgen-admin-modal-bonus svg{position:absolute;border-radius:50%;top:-14px;background-color:#fff}.nextgen-admin-content .nextgen-admin-modal-text-link{display:block;margin:15px 0;font-size:14px;color:rgba(60,67,74,.6980392157)}.nextgen-admin-content .button.nextgen-button{font-size:21px;height:50px;line-height:48px;background-color:#618e00}.nextgen-admin-content .wrap{-webkit-filter:blur(3px);-moz-filter:blur(3px);-ms-filter:blur(3px);-o-filter:blur(3px);filter:blur(3px)}.nextgen-admin-content .wrap:hover>*{pointer-events:none!important}.nextgen-admin-content .nextgen-clear,.nextgen-admin-content .nextgen-clear::after,.nextgen-admin-content .nextgen-clear::before{content:" ";display:table}.nextgen-green{color:#87a20e}@media(max-height:1300px){.nextgen-admin-content .nextgen-admin-modal{top:30px}}1 .wp-core-ui .button.nextgen-button{border-radius:6px}.wp-core-ui .nextgen-primary-button{border-color:#000;color:#fff;background-color:#000;-webkit-transition:background-color .1s linear;-ms-transition:background-color .1s linear;transition:background-color .1s linear;padding:6px 16px;font-weight:700}.wp-core-ui .nextgen-primary-button:focus,.wp-core-ui .nextgen-primary-button:hover{background:rgba(0,0,0,.8);border-color:rgba(0,0,0,.8);color:#fff;box-shadow:none}.wp-core-ui .nextgen-secondary-button{border:1px solid rgba(96,96,96,.3019607843);color:#282828;background-color:#fff;box-shadow:none;border-radius:4px;padding:6px 16px;font-weight:700;-webkit-transition:background-color .1s linear;-ms-transition:background-color .1s linear;transition:background-color .1s linear}.wp-core-ui .nextgen-secondary-button:focus,.wp-core-ui .nextgen-secondary-button:hover{border-color:#ebebeb;color:#646464;background-color:#ebebeb;box-shadow:0 2px 5px rgba(0,0,0,.08)}.wp-core-ui .nextgen-green-button{border-color:#618e00;color:#fff;background-color:#618e00;border-radius:4px;-webkit-transition:background-color .1s linear;-ms-transition:background-color .1s linear;transition:background-color .1s linear}.wp-core-ui .nextgen-green-button:focus,.wp-core-ui .nextgen-green-button:hover{background:#87a20e;border-color:#87a20e;color:#fff;box-shadow:none}.wp-core-ui .nextgen-button-blue{border-color:#3871ac;color:#fff;background-color:#3871ac;border-radius:4px;-webkit-transition:opacity .1s linear;-ms-transition:opacity .1s linear;transition:opacity .1s linear}.wp-core-ui .nextgen-button-blue:focus,.wp-core-ui .nextgen-button-blue:hover{background-color:#3871ac;border-color:#3871ac;opacity:.75;color:#fff;box-shadow:none}#nextgen-header-temp{position:relative;display:none}#nextgen-top-notification{border-top:3px solid #87a20e;position:relative;background-color:#eee;text-align:center;color:rgba(60,67,74,.8);height:40px;vertical-align:middle;border-bottom:1px solid #ddd}#nextgen-top-notification.nextgen-pro-active{height:0}#nextgen-top-notification.nextgen-pro-active p{visibility:hidden}#nextgen-top-notification p{margin:0;padding:0;line-height:40px;font-size:13px}#nextgen-top-notification a{color:#87a20e;font-size:13px}#nextgen-top-notification .nextgen-dismiss{position:absolute;top:10px;right:10px}#nextgen-header{background-color:#fff;background-repeat:repeat;height:120px;display:flex;justify-content:space-between;align-items:center;box-shadow:0 1px 2px 0 rgba(0,0,0,.0588235294)}@media(max-width:599px){#nextgen-header{padding-top:46px}}#nextgen-header h1.nextgen-logo{margin:0;margin-left:20px}#nextgen-header h1.nextgen-logo img{max-width:339px}@media(min-width:600px)and (max-width:767px){#nextgen-header h1.nextgen-logo img{width:90%}}#nextgen-header .nextgen-right{padding-right:20px}#nextgen-header .nextgen-notifications-inbox{position:relative}#nextgen-header .nextgen-notifications-inbox[data-count]:after{background:#e02626;border-radius:50%;bottom:100%;color:#fff;content:attr(data-count);display:block;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:12px;font-weight:700;height:16px;left:100%;line-height:18px;min-width:16px;position:absolute;text-align:center;transform:translate(-40%,30%)}.nextgen-notifications-close:hover,.nextgen-notifications-inbox:hover{cursor:pointer}.nextgen-notifications-drawer{box-sizing:border-box;background:#fff;bottom:0;position:fixed;right:-400px;top:32px;transition:right .3s ease 0s,visibility 0s ease .4s;visibility:hidden;width:400px;z-index:1100;border:1px solid #ddd}.nextgen-notifications-open .nextgen-notifications-drawer{right:0;transition:right .3s ease 0s,visibility 0s ease 0s;visibility:visible}.nextgen-notifications-overlay{background-color:rgba(0,0,0,.3);bottom:0;display:none;left:0;opacity:.5;position:fixed;right:0;top:46px;transition:.5s;z-index:1052}.folded .nextgen-notifications-overlay{left:36px}.nextgen-notifications-open .nextgen-notifications-overlay{display:block}@media screen and (min-width:783px){.nextgen-notifications-overlay{left:36px}.admin-bar .nextgen-notifications-overlay{top:32px}}@media screen and (min-width:961px){.nextgen-notifications-overlay{left:160px}.folded .nextgen-notifications-overlay{left:36px}}.nextgen-notifications-header{background:#eee;border-bottom:1px solid #ddd;padding:18px 40px 18px 20px}.nextgen-notifications-header .nextgen-notifications-close{position:absolute;right:18px;top:22px}.nextgen-notifications-header .nextgen-notifications-close path{fill:#3c434a}.nextgen-notifications-header h3{color:#3c434a;display:inline-block;font-size:14px;font-weight:700;line-height:21px;margin:0 10px 0 0}.nextgen-notifications-list{height:calc(100% - 130px);overflow:auto}.nextgen-notifications-list ul{margin:0}.nextgen-notifications-list li{border-bottom:1px solid #ddd;display:flex;margin:0;padding:24px;font-size:14px;color:rgba(60,67,74,.6)}.nextgen-notifications-list li:first-child{border-top:none}.nextgen-notifications-list li h4{color:#3c4249;font-size:14px;font-weight:600;line-height:21px;margin:0}.nextgen-notifications-list p{color:rgba(60,67,74,.6);font-size:14px;margin:8px 0;margin-bottom:20px}.nextgen-notifications-list p.nextgen-start{font-size:12px}.nextgen-notifications-list .nextgen-button{padding:8px 14px;border-radius:4px;text-decoration:none;font-size:12px}.nextgen-notifications-list .nextgen-button.nextgen-button-primary{background-color:#37993b;color:#fff}.nextgen-notifications-list .nextgen-button.nextgen-button-secondary{border:1px solid #ddd}.nextgen-button-text{font-size:12px;color:rgba(60,67,74,.6980392157)}.nextgen-notification-actions .nextgen-button{margin-right:10px}.nextgen-notifications-footer{border-top:1px solid #ddd;padding:24px 27px;text-align:right}#nextgen-dismissed-title,#nextgen-notifications-show-active,.nextgen-notifications-dismissed{display:none}.show-dismissed #nextgen-active-title,.show-dismissed #nextgen-notifications-show-dismissed,.show-dismissed .nextgen-notifications-active{display:none}.show-dismissed #nextgen-dismissed-title,.show-dismissed #nextgen-notifications-show-active{display:inline-block}.show-dismissed .nextgen-notifications-dismissed{display:block}.nextgen-notifications-dismissed .nextgen-notification-dismiss{display:none}.nextgen-notification-icon{margin-right:10px}body.toplevel_page_nextgen-gallery #wpcontent,body[class*=" nextgen-gallery_page_"] #wpcontent,body[class*=" ngg-"] #wpcontent{padding-left:0}body.toplevel_page_nextgen-gallery .ui-widget .ui-dialog-titlebar-close,body[class*=" nextgen-gallery_page_"] .ui-widget .ui-dialog-titlebar-close,body[class*=" ngg-"] .ui-widget .ui-dialog-titlebar-close{text-indent:-9999px;background:0 0;border:none;box-shadow:none}body.toplevel_page_nextgen-gallery #wpfooter,body[class*=" nextgen-gallery_page_"] #wpfooter,body[class*=" ngg-"] #wpfooter{margin-top:auto;position:relative;clear:both}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion{text-align:center;font-weight:400;font-size:13px;line-height:normal;color:#646970;padding:30px 0;margin-bottom:20px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links{margin:10px 0;color:#646970}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links span,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links span,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links span{color:#c3c4c7;padding:0 7px}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-links,body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-links,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-links,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{display:flex;justify-content:center;align-items:center}body.toplevel_page_nextgen-gallery #wpfooter .nextgen-footer-promotion-social,body[class*=" nextgen-gallery_page_"] #wpfooter .nextgen-footer-promotion-social,body[class*=" ngg-"] #wpfooter .nextgen-footer-promotion-social{gap:10px;margin:0}.nextgen-nav-tab-wrapper{display:flex;flex-wrap:wrap;gap:0 30px;margin:0 0 20px 0;background-color:rgba(0,0,0,0);list-style:none;font-size:16px;font-weight:400;margin:30px 20px;border-bottom:1px solid rgba(96,96,96,.1490196078)}.nextgen-nav-tab-wrapper li{margin:0;padding:0}.nextgen-nav-tab-wrapper li a{display:block;padding:15px 0 12px 0;line-height:30px;border-bottom:3px solid #fff;box-shadow:none;color:#2c3338;text-decoration:none}.nextgen-nav-tab-wrapper .nextgen-nav-tab-active,.nextgen-nav-tab-wrapper .nextgen-nav-tab:hover{border-bottom:4px solid #618e00;font-weight:600}.nextgen-admin-content{position:relative}.nextgen-admin-content .nextgen-admin-modal *,.nextgen-admin-content .nextgen-admin-modal ::after,.nextgen-admin-content .nextgen-admin-modal ::before{-moz-box-sizing:border-box;box-sizing:border-box}.nextgen-admin-content .nextgen-admin-modal{text-align:center;width:730px;box-shadow:0 0 60px 30px rgba(0,0,0,.15);background-color:#fff;border-radius:6px;position:absolute;top:95px;left:50%;margin:0 auto 0 -365px;z-index:9999;overflow:hidden}.nextgen-admin-content .nextgen-admin-modal h2{font-size:20px;margin:0 0 16px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal p{font-size:16px;line-height:24px;color:#777;margin:0 0 30px 0;padding:0}.nextgen-admin-content .nextgen-admin-modal ul{float:left;width:50%;margin:0;padding:0 0 0 30px;text-align:left}.nextgen-admin-content .nextgen-admin-modal li{color:#777;font-size:16px;line-height:28px;padding:6px 0;display:flex}.nextgen-admin-content .nextgen-admin-modal li svg{padding-right:10px}.nextgen-admin-content .nextgen-admin-modal-content{border-radius:3px 3px 0 0;padding:40px}.nextgen-admin-content .nextgen-admin-model-lists{width:100%}.nextgen-admin-content .nextgen-green-button{font-size:18px;text-align:center;padding:6px 16px;margin:30px 0}.nextgen-admin-content .nextgen-admin-modal-bonus{position:relative;padding:30px;background:#f5f5f5;text-align:center}.nextgen-admin-content .nextgen-admin-modal-bonus p{font-size:14px;margin:0}.nextgen-admin-content .nextgen-admin-modal-bonus svg{position:absolute;border-radius:50%;top:-14px;background-color:#fff}.nextgen-admin-content .nextgen-admin-modal-text-link{display:block;margin:15px 0;font-size:14px;color:rgba(60,67,74,.6980392157)}.nextgen-admin-content .button.nextgen-button{font-size:21px;height:50px;line-height:48px;background-color:#618e00}.nextgen-admin-content .wrap{-webkit-filter:blur(3px);-moz-filter:blur(3px);-ms-filter:blur(3px);-o-filter:blur(3px);filter:blur(3px)}.nextgen-admin-content .wrap:hover>*{pointer-events:none!important}.nextgen-admin-content .nextgen-clear,.nextgen-admin-content .nextgen-clear::after,.nextgen-admin-content .nextgen-clear::before{content:" ";display:table}.nextgen-green{color:#87a20e}@media(max-height:1300px){.nextgen-admin-content .nextgen-admin-modal{top:30px}} -
nextgen-gallery/trunk/assets/scss/admin.scss
r3003333 r3004370 297 297 padding-left: 0; 298 298 } 299 .ui-widget { 300 301 .ui-dialog-titlebar-close { 302 text-indent: -9999px; 303 background: none; 304 border: none; 305 box-shadow: none; 306 } 307 } 299 308 #wpfooter { 300 309 margin-top: auto; … … 485 494 } 486 495 } 496 -
nextgen-gallery/trunk/changelog.txt
r3003964 r3004370 1 1 NextGEN Gallery 2 2 by Imagely 3 4 = V3.54 - 12.01.2023 = 5 * Fixed: Assorted possible PHP warnings and notices with PHP 8.0+. 6 * Fixed: Compatibility with some 3rd party extensions. 3 7 4 8 = V3.53 - 11.30.2023 = -
nextgen-gallery/trunk/composer.json
r3003333 r3004370 15 15 "require": { 16 16 "imagely/pope-framework": "v0.18", 17 "ezyang/htmlpurifier": "^4.1 3"17 "ezyang/htmlpurifier": "^4.17" 18 18 }, 19 19 "require-dev": { -
nextgen-gallery/trunk/composer.lock
r3003964 r3004370 5 5 "This file is @generated automatically" 6 6 ], 7 "content-hash": " 947270fe14b33b958df8910a24cbf812",7 "content-hash": "014ccdbc6a38f77f4cfcc66c7f01e693", 8 8 "packages": [ 9 9 { … … 575 575 { 576 576 "name": "phpstan/phpstan", 577 "version": "1.10.4 6",577 "version": "1.10.47", 578 578 "source": { 579 579 "type": "git", 580 580 "url": "https://github.com/phpstan/phpstan.git", 581 "reference": " 90d3d25c5b98b8068916bbf08ce42d5cb6c54e70"582 }, 583 "dist": { 584 "type": "zip", 585 "url": "https://api.github.com/repos/phpstan/phpstan/zipball/ 90d3d25c5b98b8068916bbf08ce42d5cb6c54e70",586 "reference": " 90d3d25c5b98b8068916bbf08ce42d5cb6c54e70",581 "reference": "84dbb33b520ea28b6cf5676a3941f4bae1c1ff39" 582 }, 583 "dist": { 584 "type": "zip", 585 "url": "https://api.github.com/repos/phpstan/phpstan/zipball/84dbb33b520ea28b6cf5676a3941f4bae1c1ff39", 586 "reference": "84dbb33b520ea28b6cf5676a3941f4bae1c1ff39", 587 587 "shasum": "" 588 588 }, … … 633 633 } 634 634 ], 635 "time": "2023-1 1-28T14:57:26+00:00"635 "time": "2023-12-01T15:19:17+00:00" 636 636 }, 637 637 { … … 907 907 "platform": [], 908 908 "platform-dev": [], 909 "plugin-api-version": "2. 6.0"909 "plugin-api-version": "2.3.0" 910 910 } -
nextgen-gallery/trunk/nggallery.php
r3003964 r3004370 3 3 * Plugin Name: NextGEN Gallery 4 4 * Description: The most popular gallery plugin for WordPress and one of the most popular plugins of all time with over 30 million downloads. 5 * Version: 3.5 35 * Version: 3.54 6 6 * Author: Imagely 7 7 * Plugin URI: https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/ … … 123 123 124 124 if ( defined( 'NGG_ENABLE_SHUTDOWN_EXCEPTION_HANDLER' ) && NGG_ENABLE_SHUTDOWN_EXCEPTION_HANDLER ) { 125 set_exception_handler( __CLASS__ . '::shutdown' ); 126 } 127 // NextGEN Pro still throws E_Clean_Exit rather than calling exit(), which must be handled by the shutdown handler. 128 elseif ( self::get_pro_api_version() < 4.0 && ( ! defined( 'NGG_DISABLE_SHUTDOWN_EXCEPTION_HANDLER' ) || ! NGG_DISABLE_SHUTDOWN_EXCEPTION_HANDLER ) ) { 125 129 set_exception_handler( __CLASS__ . '::shutdown' ); 126 130 } … … 259 263 class_alias( '\Imagely\NGG\DataMappers\Gallery', 'C_Gallery_Mapper' ); 260 264 class_alias( '\Imagely\NGG\DataMappers\Image', 'C_Image_Mapper' ); 261 class_alias( '\Imagely\NGG\DataStorage\Manager', 'C_Gallery_Storage' );262 265 class_alias( '\Imagely\NGG\DataStorage\MetaData', 'C_NextGen_Metadata' ); 263 266 class_alias( '\Imagely\NGG\DataTypes\LegacyImage', 'C_Image_Wrapper' ); … … 532 535 // Nonce verification is not necessary here. 533 536 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 534 if ( ! $force && empty( $_REQUEST['photocrati_ajax'] ) && ( self::get_pro_api_version() >= 4.0 && ! is_admin() ) || self::$pope_loaded ) { 537 if ( ! $force 538 && empty( $_REQUEST['photocrati_ajax'] ) 539 && ( self::get_pro_api_version() >= 4.0 && ! is_admin() ) 540 && ! defined( 'EWWW_IMAGE_OPTIMIZER_VERSION' ) // EWWW uses I_Gallery_Storage. 541 && ! defined( 'WP_SMUSH_VERSION' ) // WP_SMUSH_VERSION uses I_Gallery_Storage. 542 && ! defined( 'IMAGIFY_VERSION' ) // Imagify adds their own mixin to C_Gallery_Storage. 543 || self::$pope_loaded ) { 535 544 return; 536 545 } … … 921 930 define( 'NGG_MODULE_DIR', implode( DIRECTORY_SEPARATOR, [ rtrim( NGG_PRODUCT_DIR, '/\\' ), 'photocrati_nextgen', 'modules' ] ) ); 922 931 define( 'NGG_PLUGIN_STARTED_AT', microtime() ); 923 define( 'NGG_PLUGIN_VERSION', '3.5 3' );932 define( 'NGG_PLUGIN_VERSION', '3.54' ); 924 933 925 934 define( 'NGG_SCRIPT_VERSION', defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? (string) mt_rand( 0, mt_getrandmax() ) : NGG_PLUGIN_VERSION ); -
nextgen-gallery/trunk/products/photocrati_nextgen/modules/legacy_compat/module.legacy_compat.php
r3003333 r3004370 31 31 $registry->add_utility( 'I_Display_Type_Mapper', 'C_Display_Type_Mapper' ); 32 32 $registry->add_utility( 'I_Displayed_Gallery_Mapper', 'C_Displayed_Gallery_Mapper' ); 33 $registry->add_utility( 'I_Gallery_Storage', 'C_Gallery_Storage' ); 33 34 $registry->add_utility( 'I_Router', 'C_Router_Wrapper' ); 34 35 } … … 40 41 public function get_type_list() { 41 42 return [ 42 'A_Gallery_Display_Factory' => 'adapter.gallery_display_factory.php', 43 'C_Display_Type' => 'class.display_type.php', 44 'C_Display_Type_Controller' => 'class.display_type_controller.php', 45 'C_Display_Type_Mapper' => 'class.display_type_mapper.php', 46 'C_Displayed_Gallery' => 'class.displayed_gallery.php', 47 'C_Displayed_Gallery_Mapper' => 'class.displayed_gallery_mapper.php', 48 'C_Displayed_Gallery_Source_Manager' => 'class.displayed_gallery_source_manager.php', 49 'C_Displayed_Gallery_Trigger' => 'class.displayed_gallery_trigger.php', 50 'C_Router_Wrapper' => 'class.router_wrapper.php', 51 'Mixin_Validation' => 'mixin.validation.php', 43 'A_Gallery_Display_Factory' => 'adapter.gallery_display_factory.php', 44 'C_Display_Type' => 'class.display_type.php', 45 'C_Display_Type_Controller' => 'class.display_type_controller.php', 46 'C_Display_Type_Mapper' => 'class.display_type_mapper.php', 47 'C_Displayed_Gallery' => 'class.displayed_gallery.php', 48 'C_Displayed_Gallery_Mapper' => 'class.displayed_gallery_mapper.php', 49 'C_Displayed_Gallery_Source_Manager' => 'class.displayed_gallery_source_manager.php', 50 'C_Displayed_Gallery_Trigger' => 'class.displayed_gallery_trigger.php', 51 'C_Gallery_Storage' => 'class.gallery_storage.php', 52 'C_Router_Wrapper' => 'class.router_wrapper.php', 53 'Mixin_GalleryStorage_Base_Dynamic' => 'mixin.gallerystorage_base_dynamic.php', 54 'Mixin_GalleryStorage_Base_Getters' => 'mixin.gallerystorage_base_getters.php', 55 'Mixin_GalleryStorage_Base_Management' => 'mixin.gallerystorage_base_management.php', 56 'Mixin_GalleryStorage_Base_Upload' => 'mixin.gallerystorage_base_upload.php', 57 'Mixin_Validation' => 'mixin.validation.php', 52 58 ]; 53 59 } -
nextgen-gallery/trunk/products/photocrati_nextgen/modules/legacy_compat/package.module.legacy_compat.php
r3003333 r3004370 1242 1242 } 1243 1243 return $retval; 1244 } 1245 } 1246 /** 1247 * Class C_Displayed_Gallery_Mapper 1248 * 1249 * @mixin Mixin_Displayed_Gallery_Defaults 1250 */ 1251 class C_Displayed_Gallery_Mapper extends C_CustomPost_DataMapper_Driver 1252 { 1253 static $_instances = array(); 1254 public function define($context = false, $not_used = false) 1255 { 1256 parent::define('displayed_gallery', [$context, 'displayed_gallery', 'display_gallery']); 1257 $this->add_mixin('Mixin_Displayed_Gallery_Defaults'); 1258 $this->implement('I_Displayed_Gallery_Mapper'); 1259 $this->set_model_factory_method('displayed_gallery'); 1260 // $this->add_post_hook( 1261 // 'save', 1262 // 'Propagate thumbnail dimensions', 1263 // 'Hook_Propagate_Thumbnail_Dimensions_To_Settings' 1264 // ); 1265 } 1266 /** 1267 * Initializes the mapper 1268 */ 1269 public function initialize() 1270 { 1271 parent::initialize(); 1272 } 1273 /** 1274 * Gets a singleton of the mapper 1275 * 1276 * @param string|bool $context 1277 * @return C_Displayed_Gallery_Mapper 1278 */ 1279 public static function get_instance($context = false) 1280 { 1281 if (!isset(self::$_instances[$context])) { 1282 self::$_instances[$context] = new C_Displayed_Gallery_Mapper($context); 1283 } 1284 return self::$_instances[$context]; 1285 } 1286 /** 1287 * Gets a display type object for a particular entity 1288 * 1289 * @param stdClass|C_DataMapper_Model $entity 1290 * @return null|stdClass 1291 */ 1292 public function get_display_type($entity) 1293 { 1294 $mapper = C_Display_Type_Mapper::get_instance(); 1295 return $mapper->find_by_name($entity->display_type); 1296 } 1297 } 1298 /** 1299 * Adds default values for the displayed gallery 1300 */ 1301 class Mixin_Displayed_Gallery_Defaults extends Mixin 1302 { 1303 /** 1304 * Sets defaults needed for the entity 1305 * 1306 * @param object $entity 1307 */ 1308 public function set_defaults($entity) 1309 { 1310 // Ensure that we have a settings array. 1311 if (!isset($entity->display_settings)) { 1312 $entity->display_settings = []; 1313 } 1314 // If the display type is set, then get it's settings and apply them as 1315 // defaults to the "display_settings" of the displayed gallery. 1316 if (isset($entity->display_type)) { 1317 // Get display type mapper. 1318 if ($display_type = $this->object->get_display_type($entity)) { 1319 $entity->display_settings = $this->array_merge_assoc($display_type->settings, $entity->display_settings, true); 1320 } 1321 } 1322 // Default ordering. 1323 $settings = C_NextGen_Settings::get_instance(); 1324 $this->object->_set_default_value($entity, 'order_by', $settings->galSort); 1325 $this->object->_set_default_value($entity, 'order_direction', $settings->galSortDir); 1326 // Ensure we have an exclusions array. 1327 $this->object->_set_default_value($entity, 'exclusions', []); 1328 // Ensure other properties exist. 1329 $this->object->_set_default_value($entity, 'container_ids', []); 1330 $this->object->_set_default_value($entity, 'excluded_container_ids', []); 1331 $this->object->_set_default_value($entity, 'sortorder', []); 1332 $this->object->_set_default_value($entity, 'entity_ids', []); 1333 $this->object->_set_default_value($entity, 'returns', 'included'); 1334 // Set maximum_entity_count. 1335 $this->object->_set_default_value($entity, 'maximum_entity_count', $settings->maximum_entity_count); 1244 1336 } 1245 1337 } … … 1469 1561 } 1470 1562 } 1563 /** 1564 * @deprecated 1565 * @mixin Mixin_GalleryStorage_Base_Dynamic 1566 * @mixin Mixin_GalleryStorage_Base_Getters 1567 * @mixin Mixin_GalleryStorage_Base_Management 1568 * @mixin Mixin_GalleryStorage_Base_Upload 1569 */ 1570 class C_Gallery_Storage extends C_Component 1571 { 1572 public static $_instances = array(); 1573 static $gallery_abspath_cache = array(); 1574 /** @deprecated */ 1575 public $_image_mapper; 1576 /** @deprecated */ 1577 public $_gallery_mapper; 1578 function define($context = FALSE) 1579 { 1580 parent::define($context); 1581 $this->add_mixin('Mixin_GalleryStorage_Base_Dynamic'); 1582 $this->add_mixin('Mixin_GalleryStorage_Base_Getters'); 1583 $this->add_mixin('Mixin_GalleryStorage_Base_Management'); 1584 $this->add_mixin('Mixin_GalleryStorage_Base_Upload'); 1585 $this->implement('I_Gallery_Storage'); 1586 // TODO: remove this once Pro's API level is 4 or higher 1587 $this->implement('I_GalleryStorage_Driver'); 1588 // backwards compatibility 1589 } 1590 /** 1591 * Provides some aliases to defined methods; thanks to this a call to C_Gallery_Storage->get_thumb_url() is 1592 * translated to C_Gallery_Storage->get_image_url('thumb'). 1593 * TODO: Remove this 'magic' method so that our code is always understandable without needing deep context 1594 * @param string $method 1595 * @param array $args 1596 * @return mixed 1597 * @throws Exception 1598 */ 1599 function __call($method, $args) 1600 { 1601 if (preg_match("/^get_(\\w+)_(abspath|url|dimensions|html|size_params)\$/", $method, $match)) { 1602 if (isset($match[1]) && isset($match[2]) && !$this->has_method($method)) { 1603 $method = 'get_image_' . $match[2]; 1604 $args[] = $match[1]; 1605 return parent::__call($method, $args); 1606 } 1607 } 1608 return parent::__call($method, $args); 1609 } 1610 /** 1611 * For compatibility reasons, we include this method. This used to be used to get the underlying storage driver. 1612 * Necessary for Imagify integration 1613 */ 1614 function &get_wrapped_instance() 1615 { 1616 return $this; 1617 } 1618 function initialize() 1619 { 1620 parent::initialize(); 1621 $this->_gallery_mapper = C_Gallery_Mapper::get_instance(); 1622 $this->_image_mapper = C_Image_Mapper::get_instance(); 1623 } 1624 /** 1625 * @param bool|string $context 1626 * @return C_Gallery_Storage 1627 */ 1628 static function get_instance($context = False) 1629 { 1630 if (!isset(self::$_instances[$context])) { 1631 self::$_instances[$context] = new C_Gallery_Storage($context); 1632 } 1633 return self::$_instances[$context]; 1634 } 1635 /** 1636 * Gets the id of a gallery, regardless of whether an integer 1637 * or object was passed as an argument 1638 * @param mixed $gallery_obj_or_id 1639 * @return null|int 1640 */ 1641 function _get_gallery_id($gallery_obj_or_id) 1642 { 1643 $retval = NULL; 1644 $gallery_key = $this->object->_gallery_mapper->get_primary_key_column(); 1645 if (is_object($gallery_obj_or_id)) { 1646 if (isset($gallery_obj_or_id->{$gallery_key})) { 1647 $retval = $gallery_obj_or_id->{$gallery_key}; 1648 } 1649 } elseif (is_numeric($gallery_obj_or_id)) { 1650 $retval = $gallery_obj_or_id; 1651 } 1652 return $retval; 1653 } 1654 /** 1655 * Outputs/renders an image 1656 * @param int|stdClass|C_Image $image 1657 * @return bool 1658 */ 1659 function render_image($image, $size = FALSE) 1660 { 1661 $format_list = $this->object->get_image_format_list(); 1662 $abspath = $this->object->get_image_abspath($image, $size, true); 1663 if ($abspath == null) { 1664 $thumbnail = $this->object->generate_image_size($image, $size); 1665 if ($thumbnail != null) { 1666 $abspath = $thumbnail->fileName; 1667 $thumbnail->destruct(); 1668 } 1669 } 1670 if ($abspath != null) { 1671 $data = @getimagesize($abspath); 1672 $format = 'jpg'; 1673 if ($data != null && is_array($data) && isset($format_list[$data[2]])) { 1674 $format = $format_list[$data[2]]; 1675 } 1676 // Clear output 1677 while (ob_get_level() > 0) { 1678 ob_end_clean(); 1679 } 1680 $format = strtolower($format); 1681 // output image and headers 1682 header('Content-type: image/' . $format); 1683 readfile($abspath); 1684 return true; 1685 } 1686 return false; 1687 } 1688 /** 1689 * Sets a NGG image as a post thumbnail for the given post 1690 * 1691 * @param int $postId 1692 * @param int|C_Image|stdClass $image 1693 * @param bool $only_create_attachment 1694 * @return int 1695 */ 1696 function set_post_thumbnail($postId, $image, $only_create_attachment = FALSE) 1697 { 1698 $retval = FALSE; 1699 // Get the post ID 1700 if (is_object($postId)) { 1701 $post = $postId; 1702 $postId = isset($post->ID) ? $post->ID : $post->post_id; 1703 } 1704 // Get the image 1705 if (is_int($image)) { 1706 $imageId = $image; 1707 $mapper = C_Image_Mapper::get_instance(); 1708 $image = $mapper->find($imageId); 1709 } 1710 if ($image && $postId) { 1711 $attachment_id = $this->object->is_in_media_library($image->pid); 1712 if ($attachment_id === FALSE) { 1713 $attachment_id = $this->object->copy_to_media_library($image); 1714 } 1715 if ($attachment_id) { 1716 if (!$only_create_attachment) { 1717 set_post_thumbnail($postId, $attachment_id); 1718 } 1719 $retval = $attachment_id; 1720 } 1721 } 1722 return $retval; 1723 } 1724 function convert_slashes($path) 1725 { 1726 $search = array('/', "\\"); 1727 $replace = array(DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR); 1728 return str_replace($search, $replace, $path); 1729 } 1730 /** 1731 * Empties the gallery cache directory of content 1732 * @param object $gallery 1733 */ 1734 function flush_cache($gallery) 1735 { 1736 $cache = C_Cache::get_instance(); 1737 $cache->flush_directory($this->object->get_cache_abspath($gallery)); 1738 } 1739 /** 1740 * Sanitizes a directory path, replacing whitespace with dashes. 1741 * 1742 * Taken from WP' sanitize_file_name() and modified to not act on file extensions. 1743 * 1744 * Removes special characters that are illegal in filenames on certain 1745 * operating systems and special characters requiring special escaping 1746 * to manipulate at the command line. Replaces spaces and consecutive 1747 * dashes with a single dash. Trims period, dash and underscore from beginning 1748 * and end of filename. It is not guaranteed that this function will return a 1749 * filename that is allowed to be uploaded. 1750 * @param string $dirname The directory name to be sanitized 1751 * @return string The sanitized directory name 1752 */ 1753 public function sanitize_directory_name($dirname) 1754 { 1755 $dirname_raw = $dirname; 1756 $special_chars = array("?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "\$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}", "%", "+", chr(0)); 1757 $special_chars = apply_filters('sanitize_file_name_chars', $special_chars, $dirname_raw); 1758 $dirname = preg_replace("#\\x{00a0}#siu", ' ', $dirname); 1759 $dirname = str_replace($special_chars, '', $dirname); 1760 $dirname = str_replace(array('%20', '+'), '-', $dirname); 1761 $dirname = preg_replace('/[\\r\\n\\t -]+/', '-', $dirname); 1762 $dirname = trim($dirname, '.-_'); 1763 return $dirname; 1764 } 1765 /** 1766 * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated 1767 * @param object|int $image Image ID or an image object 1768 * @param string $size 1769 * @param array $params 1770 * @param bool $skip_defaults 1771 * @return bool|array 1772 */ 1773 function calculate_image_size_dimensions($image, $size, $params = null, $skip_defaults = false) 1774 { 1775 $retval = FALSE; 1776 // Get the image entity 1777 if (is_numeric($image)) { 1778 $image = $this->object->_image_mapper->find($image); 1779 } 1780 // Ensure we have a valid image 1781 if ($image) { 1782 $params = $this->object->get_image_size_params($image, $size, $params, $skip_defaults); 1783 // Get the image filename 1784 $image_path = $this->object->get_original_abspath($image, 'original'); 1785 $clone_path = $this->object->get_image_abspath($image, $size); 1786 $retval = $this->object->calculate_image_clone_dimensions($image_path, $clone_path, $params); 1787 } 1788 return $retval; 1789 } 1790 /** 1791 * Generates a "clone" for an existing image, the clone can be altered using the $params array 1792 * @param string $image_path 1793 * @param string $clone_path 1794 * @param array $params 1795 * @return null|object 1796 */ 1797 function generate_image_clone($image_path, $clone_path, $params) 1798 { 1799 $crop = isset($params['crop']) ? $params['crop'] : NULL; 1800 $watermark = isset($params['watermark']) ? $params['watermark'] : NULL; 1801 $reflection = isset($params['reflection']) ? $params['reflection'] : NULL; 1802 $rotation = isset($params['rotation']) ? $params['rotation'] : NULL; 1803 $flip = isset($params['flip']) ? $params['flip'] : ''; 1804 $destpath = NULL; 1805 $thumbnail = NULL; 1806 $result = $this->object->calculate_image_clone_result($image_path, $clone_path, $params); 1807 // XXX this should maybe be removed and extra settings go into $params? 1808 $settings = apply_filters('ngg_settings_during_image_generation', C_NextGen_Settings::get_instance()->to_array()); 1809 // Ensure we have a valid image 1810 if ($image_path && @file_exists($image_path) && $result != null && !isset($result['error'])) { 1811 $image_dir = dirname($image_path); 1812 $clone_path = $result['clone_path']; 1813 $clone_dir = $result['clone_directory']; 1814 $clone_format = $result['clone_format']; 1815 $format_list = $this->object->get_image_format_list(); 1816 // Ensure target directory exists, but only create 1 subdirectory 1817 if (!@file_exists($clone_dir)) { 1818 if (strtolower(realpath($image_dir)) != strtolower(realpath($clone_dir))) { 1819 if (strtolower(realpath($image_dir)) == strtolower(realpath(dirname($clone_dir)))) { 1820 wp_mkdir_p($clone_dir); 1821 } 1822 } 1823 } 1824 $method = $result['method']; 1825 $width = $result['width']; 1826 $height = $result['height']; 1827 $quality = $result['quality']; 1828 if ($quality == null) { 1829 $quality = 100; 1830 } 1831 if ($method == 'wordpress') { 1832 $original = wp_get_image_editor($image_path); 1833 $destpath = $clone_path; 1834 if (!is_wp_error($original)) { 1835 $original->resize($width, $height, $crop); 1836 $original->set_quality($quality); 1837 $original->save($clone_path); 1838 } 1839 } else { 1840 if ($method == 'nextgen') { 1841 $destpath = $clone_path; 1842 $thumbnail = new C_NggLegacy_Thumbnail($image_path, true); 1843 if (!$thumbnail->error) { 1844 if ($crop) { 1845 $crop_area = $result['crop_area']; 1846 $crop_x = $crop_area['x']; 1847 $crop_y = $crop_area['y']; 1848 $crop_width = $crop_area['width']; 1849 $crop_height = $crop_area['height']; 1850 $thumbnail->crop($crop_x, $crop_y, $crop_width, $crop_height); 1851 } 1852 $thumbnail->resize($width, $height); 1853 } else { 1854 $thumbnail = NULL; 1855 } 1856 } 1857 } 1858 // We successfully generated the thumbnail 1859 if (is_string($destpath) && (@file_exists($destpath) || $thumbnail != null)) { 1860 if ($clone_format != null) { 1861 if (isset($format_list[$clone_format])) { 1862 $clone_format_extension = $format_list[$clone_format]; 1863 $clone_format_extension_str = null; 1864 if ($clone_format_extension != null) { 1865 $clone_format_extension_str = '.' . $clone_format_extension; 1866 } 1867 $destpath_info = M_I18n::mb_pathinfo($destpath); 1868 $destpath_extension = $destpath_info['extension']; 1869 if (strtolower($destpath_extension) != strtolower($clone_format_extension)) { 1870 $destpath_dir = $destpath_info['dirname']; 1871 $destpath_basename = $destpath_info['filename']; 1872 $destpath_new = $destpath_dir . DIRECTORY_SEPARATOR . $destpath_basename . $clone_format_extension_str; 1873 if (@file_exists($destpath) && rename($destpath, $destpath_new) || $thumbnail != null) { 1874 $destpath = $destpath_new; 1875 } 1876 } 1877 } 1878 } 1879 if (is_null($thumbnail)) { 1880 $thumbnail = new C_NggLegacy_Thumbnail($destpath, true); 1881 if ($thumbnail->error) { 1882 $thumbnail = null; 1883 return null; 1884 } 1885 } else { 1886 $thumbnail->fileName = $destpath; 1887 } 1888 // This is quite odd, when watermark equals int(0) it seems all statements below ($watermark == 'image') and ($watermark == 'text') both evaluate as true 1889 // so we set it at null if it evaluates to any null-like value 1890 if ($watermark == null) { 1891 $watermark = null; 1892 } 1893 if ($watermark == 1 || $watermark === true) { 1894 $watermark_setting_keys = array('wmFont', 'wmType', 'wmPos', 'wmXpos', 'wmYpos', 'wmPath', 'wmText', 'wmOpaque', 'wmFont', 'wmSize', 'wmColor'); 1895 foreach ($watermark_setting_keys as $watermark_key) { 1896 if (!isset($params[$watermark_key])) { 1897 $params[$watermark_key] = $settings[$watermark_key]; 1898 } 1899 } 1900 if (in_array(strval($params['wmType']), array('image', 'text'))) { 1901 $watermark = $params['wmType']; 1902 } else { 1903 $watermark = 'text'; 1904 } 1905 } 1906 $watermark = strval($watermark); 1907 if ($watermark == 'image') { 1908 $thumbnail->watermarkImgPath = $params['wmPath']; 1909 $thumbnail->watermarkImage($params['wmPos'], $params['wmXpos'], $params['wmYpos']); 1910 } else { 1911 if ($watermark == 'text') { 1912 $thumbnail->watermarkText = $params['wmText']; 1913 $thumbnail->watermarkCreateText($params['wmColor'], $params['wmFont'], $params['wmSize'], $params['wmOpaque']); 1914 $thumbnail->watermarkImage($params['wmPos'], $params['wmXpos'], $params['wmYpos']); 1915 } 1916 } 1917 if ($rotation && in_array(abs($rotation), array(90, 180, 270))) { 1918 $thumbnail->rotateImageAngle($rotation); 1919 } 1920 $flip = strtolower($flip); 1921 if ($flip && in_array($flip, array('h', 'v', 'hv'))) { 1922 $flip_h = in_array($flip, array('h', 'hv')); 1923 $flip_v = in_array($flip, array('v', 'hv')); 1924 $thumbnail->flipImage($flip_h, $flip_v); 1925 } 1926 if ($reflection) { 1927 $thumbnail->createReflection(40, 40, 50, FALSE, '#a4a4a4'); 1928 } 1929 // Force format 1930 if ($clone_format != null && isset($format_list[$clone_format])) { 1931 $thumbnail->format = strtoupper($format_list[$clone_format]); 1932 } 1933 $thumbnail = apply_filters('ngg_before_save_thumbnail', $thumbnail); 1934 // Always retrieve metadata from the backup when possible 1935 $backup_path = $image_path . '_backup'; 1936 $exif_abspath = @file_exists($backup_path) ? $backup_path : $image_path; 1937 $exif_iptc = @C_Exif_Writer::read_metadata($exif_abspath); 1938 $thumbnail->save($destpath, $quality); 1939 @C_Exif_Writer::write_metadata($destpath, $exif_iptc); 1940 } 1941 } 1942 return $thumbnail; 1943 } 1944 /** 1945 * Returns an array of dimensional properties (width, height, real_width, real_height) of a resulting clone image if and when generated 1946 * @param string $image_path 1947 * @param string $clone_path 1948 * @param array $params 1949 * @return null|array 1950 */ 1951 function calculate_image_clone_dimensions($image_path, $clone_path, $params) 1952 { 1953 $retval = null; 1954 $result = $this->object->calculate_image_clone_result($image_path, $clone_path, $params); 1955 if ($result != null) { 1956 $retval = array('width' => $result['width'], 'height' => $result['height'], 'real_width' => $result['real_width'], 'real_height' => $result['real_height']); 1957 } 1958 return $retval; 1959 } 1960 /** 1961 * Returns an array of properties of a resulting clone image if and when generated 1962 * @param string $image_path 1963 * @param string $clone_path 1964 * @param array $params 1965 * @return null|array 1966 */ 1967 function calculate_image_clone_result($image_path, $clone_path, $params) 1968 { 1969 $width = isset($params['width']) ? $params['width'] : NULL; 1970 $height = isset($params['height']) ? $params['height'] : NULL; 1971 $quality = isset($params['quality']) ? $params['quality'] : NULL; 1972 $type = isset($params['type']) ? $params['type'] : NULL; 1973 $crop = isset($params['crop']) ? $params['crop'] : NULL; 1974 $watermark = isset($params['watermark']) ? $params['watermark'] : NULL; 1975 $rotation = isset($params['rotation']) ? $params['rotation'] : NULL; 1976 $reflection = isset($params['reflection']) ? $params['reflection'] : NULL; 1977 $crop_frame = isset($params['crop_frame']) ? $params['crop_frame'] : NULL; 1978 $result = NULL; 1979 // Ensure we have a valid image 1980 if ($image_path && @file_exists($image_path)) { 1981 // Ensure target directory exists, but only create 1 subdirectory 1982 $image_dir = dirname($image_path); 1983 $clone_dir = dirname($clone_path); 1984 $image_extension = M_I18n::mb_pathinfo($image_path, PATHINFO_EXTENSION); 1985 $image_extension_str = null; 1986 $clone_extension = M_I18n::mb_pathinfo($clone_path, PATHINFO_EXTENSION); 1987 $clone_extension_str = null; 1988 if ($image_extension != null) { 1989 $image_extension_str = '.' . $image_extension; 1990 } 1991 if ($clone_extension != null) { 1992 $clone_extension_str = '.' . $clone_extension; 1993 } 1994 $image_basename = M_I18n::mb_basename($image_path); 1995 $clone_basename = M_I18n::mb_basename($clone_path); 1996 // We use a default suffix as passing in null as the suffix will make WordPress use a default 1997 $clone_suffix = null; 1998 $format_list = $this->object->get_image_format_list(); 1999 $clone_format = null; 2000 // format is determined below and based on $type otherwise left to null 2001 // suffix is only used to reconstruct paths for image_resize function 2002 if (strpos($clone_basename, $image_basename) === 0) { 2003 $clone_suffix = substr($clone_basename, strlen($image_basename)); 2004 } 2005 if ($clone_suffix != null && $clone_suffix[0] == '-') { 2006 // WordPress adds '-' on its own 2007 $clone_suffix = substr($clone_suffix, 1); 2008 } 2009 // Get original image dimensions 2010 $dimensions = getimagesize($image_path); 2011 if ($width == null && $height == null) { 2012 if ($dimensions != null) { 2013 if ($width == null) { 2014 $width = $dimensions[0]; 2015 } 2016 if ($height == null) { 2017 $height = $dimensions[1]; 2018 } 2019 } else { 2020 // XXX Don't think there's any other option here but to fail miserably...use some hard-coded defaults maybe? 2021 return null; 2022 } 2023 } 2024 if ($dimensions != null) { 2025 $dimensions_ratio = $dimensions[0] / $dimensions[1]; 2026 if ($width == null) { 2027 $width = (int) round($height * $dimensions_ratio); 2028 if ($width == $dimensions[0] - 1) { 2029 $width = $dimensions[0]; 2030 } 2031 } else { 2032 if ($height == null) { 2033 $height = (int) round($width / $dimensions_ratio); 2034 if ($height == $dimensions[1] - 1) { 2035 $height = $dimensions[1]; 2036 } 2037 } 2038 } 2039 if ($width > $dimensions[0]) { 2040 $width = $dimensions[0]; 2041 } 2042 if ($height > $dimensions[1]) { 2043 $height = $dimensions[1]; 2044 } 2045 $image_format = $dimensions[2]; 2046 if ($type != null) { 2047 if (is_string($type)) { 2048 $type = strtolower($type); 2049 // Indexes in the $format_list array correspond to IMAGETYPE_XXX values appropriately 2050 if (($index = array_search($type, $format_list)) !== false) { 2051 $type = $index; 2052 if ($type != $image_format) { 2053 // Note: this only changes the FORMAT of the image but not the extension 2054 $clone_format = $type; 2055 } 2056 } 2057 } 2058 } 2059 } 2060 if ($width == null || $height == null) { 2061 // Something went wrong... 2062 return null; 2063 } 2064 // We now need to estimate the 'quality' or level of compression applied to the original JPEG: *IF* the 2065 // original image has a quality lower than the $quality parameter we will end up generating a new image 2066 // that is MUCH larger than the original. 'Quality' as an EXIF or IPTC property is quite unreliable 2067 // and not all software honors or treats it the same way. This calculation is simple: just compare the size 2068 // that our image could become to what it currently is. '3' is important here as JPEG uses 3 bytes per pixel. 2069 // 2070 // First we attempt to use ImageMagick if we can; it has a more robust method of calculation. 2071 if (!empty($dimensions['mime']) && $dimensions['mime'] == 'image/jpeg') { 2072 $possible_quality = NULL; 2073 $try_image_magick = TRUE; 2074 if (defined('NGG_DISABLE_IMAGICK') && NGG_DISABLE_IMAGICK || function_exists('is_wpe') && ($dimensions[0] >= 8000 || $dimensions[1] >= 8000)) { 2075 $try_image_magick = FALSE; 2076 } 2077 if ($try_image_magick && extension_loaded('imagick') && class_exists('Imagick')) { 2078 $img = new Imagick($image_path); 2079 if (method_exists($img, 'getImageCompressionQuality')) { 2080 $possible_quality = $img->getImageCompressionQuality(); 2081 } 2082 } 2083 // ImageMagick wasn't available so we guess it from the dimensions and filesize 2084 if ($possible_quality === NULL) { 2085 $filesize = filesize($image_path); 2086 $possible_quality = 101 - $width * $height * 3 / $filesize; 2087 } 2088 if ($possible_quality !== NULL && $possible_quality < $quality) { 2089 $quality = $possible_quality; 2090 } 2091 } 2092 $result['clone_path'] = $clone_path; 2093 $result['clone_directory'] = $clone_dir; 2094 $result['clone_suffix'] = $clone_suffix; 2095 $result['clone_format'] = $clone_format; 2096 $result['base_width'] = $dimensions[0]; 2097 $result['base_height'] = $dimensions[1]; 2098 // image_resize() has limitations: 2099 // - no easy crop frame support 2100 // - fails if the dimensions are unchanged 2101 // - doesn't support filename prefix, only suffix so names like thumbs_original_name.jpg for $clone_path are not supported 2102 // also suffix cannot be null as that will make WordPress use a default suffix...we could use an object that returns empty string from __toString() but for now just fallback to ngg generator 2103 if (FALSE) { 2104 // disabling the WordPress method for Iteration #6 2105 // if (($crop_frame == null || !$crop) && ($dimensions[0] != $width && $dimensions[1] != $height) && $clone_suffix != null) 2106 $result['method'] = 'wordpress'; 2107 $new_dims = image_resize_dimensions($dimensions[0], $dimensions[1], $width, $height, $crop); 2108 if ($new_dims) { 2109 list($dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h) = $new_dims; 2110 $width = $dst_w; 2111 $height = $dst_h; 2112 } else { 2113 $result['error'] = new WP_Error('error_getting_dimensions', __('Could not calculate resized image dimensions')); 2114 } 2115 } else { 2116 $result['method'] = 'nextgen'; 2117 $original_width = $dimensions[0]; 2118 $original_height = $dimensions[1]; 2119 $aspect_ratio = $width / $height; 2120 $orig_ratio_x = $original_width / $width; 2121 $orig_ratio_y = $original_height / $height; 2122 if ($crop) { 2123 $algo = 'shrink'; 2124 // either 'adapt' or 'shrink' 2125 if ($crop_frame != null) { 2126 $crop_x = (int) round($crop_frame['x']); 2127 $crop_y = (int) round($crop_frame['y']); 2128 $crop_width = (int) round($crop_frame['width']); 2129 $crop_height = (int) round($crop_frame['height']); 2130 $crop_final_width = (int) round($crop_frame['final_width']); 2131 $crop_final_height = (int) round($crop_frame['final_height']); 2132 $crop_width_orig = $crop_width; 2133 $crop_height_orig = $crop_height; 2134 $crop_factor_x = $crop_width / $crop_final_width; 2135 $crop_factor_y = $crop_height / $crop_final_height; 2136 $crop_ratio_x = $crop_width / $width; 2137 $crop_ratio_y = $crop_height / $height; 2138 if ($algo == 'adapt') { 2139 // XXX not sure about this...don't use for now 2140 # $crop_width = (int) round($width * $crop_factor_x); 2141 # $crop_height = (int) round($height * $crop_factor_y); 2142 } else { 2143 if ($algo == 'shrink') { 2144 if ($crop_ratio_x < $crop_ratio_y) { 2145 $crop_width = max($crop_width, $width); 2146 $crop_height = (int) round($crop_width / $aspect_ratio); 2147 } else { 2148 $crop_height = max($crop_height, $height); 2149 $crop_width = (int) round($crop_height * $aspect_ratio); 2150 } 2151 if ($crop_width == $crop_width_orig - 1) { 2152 $crop_width = $crop_width_orig; 2153 } 2154 if ($crop_height == $crop_height_orig - 1) { 2155 $crop_height = $crop_height_orig; 2156 } 2157 } 2158 } 2159 $crop_diff_x = (int) round(($crop_width_orig - $crop_width) / 2); 2160 $crop_diff_y = (int) round(($crop_height_orig - $crop_height) / 2); 2161 $crop_x += $crop_diff_x; 2162 $crop_y += $crop_diff_y; 2163 $crop_max_x = $crop_x + $crop_width; 2164 $crop_max_y = $crop_y + $crop_height; 2165 // Check if we're overflowing borders 2166 // 2167 if ($crop_x < 0) { 2168 $crop_x = 0; 2169 } else { 2170 if ($crop_max_x > $original_width) { 2171 $crop_x -= $crop_max_x - $original_width; 2172 } 2173 } 2174 if ($crop_y < 0) { 2175 $crop_y = 0; 2176 } else { 2177 if ($crop_max_y > $original_height) { 2178 $crop_y -= $crop_max_y - $original_height; 2179 } 2180 } 2181 } else { 2182 if ($orig_ratio_x < $orig_ratio_y) { 2183 $crop_width = $original_width; 2184 $crop_height = (int) round($height * $orig_ratio_x); 2185 } else { 2186 $crop_height = $original_height; 2187 $crop_width = (int) round($width * $orig_ratio_y); 2188 } 2189 if ($crop_width == $width - 1) { 2190 $crop_width = $width; 2191 } 2192 if ($crop_height == $height - 1) { 2193 $crop_height = $height; 2194 } 2195 $crop_x = (int) round(($original_width - $crop_width) / 2); 2196 $crop_y = (int) round(($original_height - $crop_height) / 2); 2197 } 2198 $result['crop_area'] = array('x' => $crop_x, 'y' => $crop_y, 'width' => $crop_width, 'height' => $crop_height); 2199 } else { 2200 // Just constraint dimensions to ensure there's no stretching or deformations 2201 list($width, $height) = wp_constrain_dimensions($original_width, $original_height, $width, $height); 2202 } 2203 } 2204 $result['width'] = $width; 2205 $result['height'] = $height; 2206 $result['quality'] = $quality; 2207 $real_width = $width; 2208 $real_height = $height; 2209 if ($rotation && in_array(abs($rotation), array(90, 270))) { 2210 $real_width = $height; 2211 $real_height = $width; 2212 } 2213 if ($reflection) { 2214 // default for nextgen was 40%, this is used in generate_image_clone as well 2215 $reflection_amount = 40; 2216 // Note, round() would probably be best here but using the same code that C_NggLegacy_Thumbnail uses for compatibility 2217 $reflection_height = intval($real_height * ($reflection_amount / 100)); 2218 $real_height = $real_height + $reflection_height; 2219 } 2220 $result['real_width'] = $real_width; 2221 $result['real_height'] = $real_height; 2222 } 2223 return $result; 2224 } 2225 function generate_resized_image($image, $save = TRUE) 2226 { 2227 $image_abspath = $this->object->get_image_abspath($image, 'full'); 2228 $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full')); 2229 if ($generated && $save) { 2230 $this->object->update_image_dimension_metadata($image, $image_abspath); 2231 } 2232 if ($generated) { 2233 $generated->destruct(); 2234 } 2235 } 2236 public function update_image_dimension_metadata($image, $image_abspath) 2237 { 2238 // Ensure that fullsize dimensions are added to metadata array 2239 $dimensions = getimagesize($image_abspath); 2240 $full_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'md5' => $this->object->get_image_checksum($image, 'full')); 2241 if (!isset($image->meta_data) or is_string($image->meta_data) && strlen($image->meta_data) == 0 or is_bool($image->meta_data)) { 2242 $image->meta_data = array(); 2243 } 2244 $image->meta_data = array_merge($image->meta_data, $full_meta); 2245 $image->meta_data['full'] = $full_meta; 2246 // Don't forget to append the 'full' entry in meta_data in the db 2247 $this->object->_image_mapper->save($image); 2248 } 2249 /** 2250 * Most major browsers do not honor the Orientation meta found in EXIF. To prevent display issues we inspect 2251 * the EXIF data and rotate the image so that the EXIF field is not necessary to display the image correctly. 2252 * Note: generate_image_clone() will handle the removal of the Orientation tag inside the image EXIF. 2253 * Note: This only handles single-dimension rotation; at the time this method was written there are no known 2254 * camera manufacturers that both rotate and flip images. 2255 * @param $image 2256 * @param bool $save 2257 */ 2258 public function correct_exif_rotation($image, $save = TRUE) 2259 { 2260 $image_abspath = $this->object->get_image_abspath($image, 'full'); 2261 // This method is necessary 2262 if (!function_exists('exif_read_data')) { 2263 return; 2264 } 2265 // We only need to continue if the Orientation tag is set 2266 $exif = @exif_read_data($image_abspath, 'exif'); 2267 if (empty($exif['Orientation']) || $exif['Orientation'] == 1) { 2268 return; 2269 } 2270 $degree = 0; 2271 if ($exif['Orientation'] == 3) { 2272 $degree = 180; 2273 } 2274 if ($exif['Orientation'] == 6) { 2275 $degree = 90; 2276 } 2277 if ($exif['Orientation'] == 8) { 2278 $degree = 270; 2279 } 2280 $parameters = array('rotation' => $degree); 2281 $generated = $this->object->generate_image_clone($image_abspath, $image_abspath, $this->object->get_image_size_params($image, 'full', $parameters), $parameters); 2282 if ($generated && $save) { 2283 $this->object->update_image_dimension_metadata($image, $image_abspath); 2284 } 2285 if ($generated) { 2286 $generated->destruct(); 2287 } 2288 } 2289 /** 2290 * Flushes the cache we use for path/url calculation for galleries 2291 */ 2292 function flush_gallery_path_cache($gallery) 2293 { 2294 $gallery = is_numeric($gallery) ? $gallery : $gallery->gid; 2295 unset(self::$gallery_abspath_cache[$gallery]); 2296 } 2297 /** 2298 * Gets the id of an image, regardless of whether an integer 2299 * or object was passed as an argument 2300 * @param object|int $image_obj_or_id 2301 * @return null|int 2302 */ 2303 function _get_image_id($image_obj_or_id) 2304 { 2305 $retval = NULL; 2306 $image_key = $this->object->_image_mapper->get_primary_key_column(); 2307 if (is_object($image_obj_or_id)) { 2308 if (isset($image_obj_or_id->{$image_key})) { 2309 $retval = $image_obj_or_id->{$image_key}; 2310 } 2311 } elseif (is_numeric($image_obj_or_id)) { 2312 $retval = $image_obj_or_id; 2313 } 2314 return $retval; 2315 } 2316 /** 2317 * Returns the absolute path to the cache directory of a gallery. 2318 * 2319 * Without the gallery parameter the legacy (pre 2.0) shared directory is returned. 2320 * 2321 * @param int|object|false|C_Gallery $gallery (optional) 2322 * @return string Absolute path to cache directory 2323 */ 2324 function get_cache_abspath($gallery = FALSE) 2325 { 2326 return path_join($this->object->get_gallery_abspath($gallery), 'cache'); 2327 } 2328 /** 2329 * Gets the absolute path where the full-sized image is stored 2330 * @param int|object $image 2331 * @return null|string 2332 */ 2333 function get_full_abspath($image) 2334 { 2335 return $this->object->get_image_abspath($image, 'full'); 2336 } 2337 /** 2338 * Alias to get_image_dimensions() 2339 * @param int|object $image 2340 * @return array 2341 */ 2342 function get_full_dimensions($image) 2343 { 2344 return $this->object->get_image_dimensions($image, 'full'); 2345 } 2346 /** 2347 * Alias to get_image_html() 2348 * @param int|object $image 2349 * @return string 2350 */ 2351 function get_full_html($image) 2352 { 2353 return $this->object->get_image_html($image, 'full'); 2354 } 2355 /** 2356 * Alias for get_original_url() 2357 * 2358 * @param int|stdClass|C_Image $image 2359 * @return string 2360 */ 2361 function get_full_url($image) 2362 { 2363 return $this->object->get_image_url($image, 'full'); 2364 } 2365 function get_gallery_root() 2366 { 2367 return wp_normalize_path(C_Fs::get_instance()->get_document_root('galleries')); 2368 } 2369 function _get_computed_gallery_abspath($gallery) 2370 { 2371 $retval = NULL; 2372 $gallery_root = $this->get_gallery_root(); 2373 // Get the gallery entity from the database 2374 if ($gallery) { 2375 if (is_numeric($gallery)) { 2376 $gallery = $this->object->_gallery_mapper->find($gallery); 2377 } 2378 } 2379 // It just doesn't exist 2380 if (!$gallery) { 2381 return $retval; 2382 } 2383 // We we have a gallery, determine it's path 2384 if ($gallery) { 2385 if (isset($gallery->path)) { 2386 $retval = $gallery->path; 2387 } elseif (isset($gallery->slug)) { 2388 $basepath = wp_normalize_path(C_NextGen_Settings::get_instance()->gallerypath); 2389 $retval = path_join($basepath, $this->object->sanitize_directory_name(sanitize_title($gallery->slug))); 2390 } 2391 // Normalize the gallery path. If the gallery path starts with /wp-content, and 2392 // NGG_GALLERY_ROOT_TYPE is set to 'content', then we need to strip out the /wp-content 2393 // from the start of the gallery path 2394 if (NGG_GALLERY_ROOT_TYPE === 'content') { 2395 $retval = preg_replace("#^/?wp-content#", "", $retval); 2396 } 2397 // Ensure that the path is absolute 2398 if (strpos($retval, $gallery_root) !== 0) { 2399 // path_join() behaves funny - if the second argument starts with a slash, 2400 // it won't join the two paths together 2401 $retval = preg_replace("#^/#", "", $retval); 2402 $retval = path_join($gallery_root, $retval); 2403 } 2404 $retval = wp_normalize_path($retval); 2405 } 2406 return $retval; 2407 } 2408 /** 2409 * Get the abspath to the gallery folder for the given gallery 2410 * The gallery may or may not already be persisted 2411 * @param int|object|C_Gallery $gallery 2412 * @return string 2413 */ 2414 function get_gallery_abspath($gallery) 2415 { 2416 $gallery_id = is_numeric($gallery) ? $gallery : (is_object($gallery) && isset($gallery->gid) ? $gallery->gid : NULL); 2417 if (!$gallery_id || !isset(self::$gallery_abspath_cache[$gallery_id])) { 2418 self::$gallery_abspath_cache[$gallery_id] = $this->object->_get_computed_gallery_abspath($gallery); 2419 } 2420 return self::$gallery_abspath_cache[$gallery_id]; 2421 } 2422 function get_gallery_relpath($gallery) 2423 { 2424 // Special hack for home.pl: their document root is just '/' 2425 $root = $this->object->get_gallery_root(); 2426 if ($root === '/') { 2427 return $this->get_gallery_abspath($gallery); 2428 } 2429 return str_replace($this->object->get_gallery_root(), '', $this->get_gallery_abspath($gallery)); 2430 } 2431 /** 2432 * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image. 2433 * @param int|object $image 2434 * @param string $size (optional) Default = full 2435 * @return string 2436 */ 2437 function _get_computed_image_abspath($image, $size = 'full', $check_existance = FALSE) 2438 { 2439 $retval = NULL; 2440 // If we have the id, get the actual image entity 2441 if (is_numeric($image)) { 2442 $image = $this->object->_image_mapper->find($image); 2443 } 2444 // Ensure we have the image entity - user could have passed in an incorrect id 2445 if (is_object($image)) { 2446 if ($gallery_path = $this->object->get_gallery_abspath($image->galleryid)) { 2447 $folder = $prefix = $size; 2448 switch ($size) { 2449 # Images are stored in the associated gallery folder 2450 case 'full': 2451 $retval = path_join($gallery_path, $image->filename); 2452 break; 2453 case 'backup': 2454 $retval = path_join($gallery_path, $image->filename . '_backup'); 2455 if (!@file_exists($retval)) { 2456 $retval = path_join($gallery_path, $image->filename); 2457 } 2458 break; 2459 case 'thumbnail': 2460 $size = 'thumbnail'; 2461 $folder = 'thumbs'; 2462 $prefix = 'thumbs'; 2463 // deliberately no break here 2464 default: 2465 // NGG 2.0 stores relative filenames in the meta data of 2466 // an image. It does this because it uses filenames 2467 // that follow conventional WordPress naming scheme. 2468 $image_path = NULL; 2469 $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance(); 2470 if (isset($image->meta_data) && isset($image->meta_data[$size]) && isset($image->meta_data[$size]['filename'])) { 2471 if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) { 2472 $image_path = path_join($this->object->get_cache_abspath($image->galleryid), $image->meta_data[$size]['filename']); 2473 } else { 2474 $image_path = path_join($gallery_path, $folder); 2475 $image_path = path_join($image_path, $image->meta_data[$size]['filename']); 2476 } 2477 } else { 2478 if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) { 2479 $params = $dynthumbs->get_params_from_name($size, true); 2480 $image_path = path_join($this->object->get_cache_abspath($image->galleryid), $dynthumbs->get_image_name($image, $params)); 2481 // Filename is not found in meta, nor dynamic 2482 } else { 2483 $settings = C_NextGen_Settings::get_instance(); 2484 // This next bit is annoying but necessary for legacy reasons. NextGEN until 3.19 stored thumbnails 2485 // with a filename of "thumbs_(whatever.jpg)" which Google indexes as "thumbswhatever.jpg" which is 2486 // not good for SEO. From 3.19 on the default setting is "thumbs-" but we must account for legacy 2487 // sites. 2488 $image_path = path_join($gallery_path, $folder); 2489 $new_thumb_path = path_join($image_path, "{$prefix}-{$image->filename}"); 2490 $old_thumb_path = path_join($image_path, "{$prefix}_{$image->filename}"); 2491 if ($settings->get('dynamic_image_filename_separator_use_dash', FALSE)) { 2492 // Check for thumbs- first 2493 if (file_exists($new_thumb_path)) { 2494 $image_path = $new_thumb_path; 2495 } elseif (file_exists($old_thumb_path)) { 2496 // Check for thumbs_ as a fallback 2497 $image_path = $old_thumb_path; 2498 } else { 2499 // The thumbnail file does not exist, default to thumbs- 2500 $image_path = $new_thumb_path; 2501 } 2502 } else { 2503 // Reversed: the option is disabled so check for thumbs_ 2504 if (file_exists($old_thumb_path)) { 2505 $image_path = $old_thumb_path; 2506 } elseif (file_exists($new_thumb_path)) { 2507 // In case the user has switched back and forth, check for thumbs- 2508 $image_path = $new_thumb_path; 2509 } else { 2510 // Default to thumbs_ per the site setting 2511 $image_path = $old_thumb_path; 2512 } 2513 } 2514 } 2515 } 2516 $retval = $image_path; 2517 break; 2518 } 2519 } 2520 } 2521 if ($retval && $check_existance && !@file_exists($retval)) { 2522 $retval = NULL; 2523 } 2524 return $retval; 2525 } 2526 function get_image_checksum($image, $size = 'full') 2527 { 2528 $retval = NULL; 2529 if ($image_abspath = $this->get_image_abspath($image, $size, TRUE)) { 2530 $retval = md5_file($image_abspath); 2531 } 2532 return $retval; 2533 } 2534 /** 2535 * Gets the dimensions for a particular-sized image 2536 * 2537 * @param int|object $image 2538 * @param string $size 2539 * @return null|array 2540 */ 2541 function get_image_dimensions($image, $size = 'full') 2542 { 2543 $retval = NULL; 2544 // If an image id was provided, get the entity 2545 if (is_numeric($image)) { 2546 $image = $this->object->_image_mapper->find($image); 2547 } 2548 // Ensure we have a valid image 2549 if ($image) { 2550 $size = $this->normalize_image_size_name($size); 2551 if (!$size) { 2552 $size = 'full'; 2553 } 2554 // Image dimensions are stored in the $image->meta_data 2555 // property for all implementations 2556 if (isset($image->meta_data) && isset($image->meta_data[$size])) { 2557 $retval = $image->meta_data[$size]; 2558 } else { 2559 $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance(); 2560 $abspath = $this->object->get_image_abspath($image, $size, TRUE); 2561 if ($abspath) { 2562 $dims = @getimagesize($abspath); 2563 if ($dims) { 2564 $retval['width'] = $dims[0]; 2565 $retval['height'] = $dims[1]; 2566 } 2567 } elseif ($size == 'backup') { 2568 $retval = $this->object->get_image_dimensions($image, 'full'); 2569 } 2570 if (!$retval && $dynthumbs && $dynthumbs->is_size_dynamic($size)) { 2571 $new_dims = $this->object->calculate_image_size_dimensions($image, $size); 2572 $retval = array('width' => $new_dims['real_width'], 'height' => $new_dims['real_height']); 2573 } 2574 } 2575 } 2576 return $retval; 2577 } 2578 function get_image_format_list() 2579 { 2580 $format_list = [IMAGETYPE_GIF => 'gif', IMAGETYPE_JPEG => 'jpg', IMAGETYPE_PNG => 'png', IMAGETYPE_WEBP => 'webp']; 2581 return $format_list; 2582 } 2583 /** 2584 * Gets the HTML for an image 2585 * @param int|object $image 2586 * @param string $size 2587 * @param array $attributes (optional) 2588 * @return string 2589 */ 2590 function get_image_html($image, $size = 'full', $attributes = array()) 2591 { 2592 $retval = ""; 2593 if (is_numeric($image)) { 2594 $image = $this->object->_image_mapper->find($image); 2595 } 2596 if ($image) { 2597 // Set alt text if not already specified 2598 if (!isset($attributes['alttext'])) { 2599 $attributes['alt'] = esc_attr($image->alttext); 2600 } 2601 // Set the title if not already set 2602 if (!isset($attributes['title'])) { 2603 $attributes['title'] = esc_attr($image->alttext); 2604 } 2605 // Set the dimensions if not set already 2606 if (!isset($attributes['width']) or !isset($attributes['height'])) { 2607 $dimensions = $this->object->get_image_dimensions($image, $size); 2608 if (!isset($attributes['width'])) { 2609 $attributes['width'] = $dimensions['width']; 2610 } 2611 if (!isset($attributes['height'])) { 2612 $attributes['height'] = $dimensions['height']; 2613 } 2614 } 2615 // Set the url if not already specified 2616 if (!isset($attributes['src'])) { 2617 $attributes['src'] = $this->object->get_image_url($image, $size); 2618 } 2619 // Format attributes 2620 $attribs = array(); 2621 foreach ($attributes as $attrib => $value) { 2622 $attribs[] = "{$attrib}=\"{$value}\""; 2623 } 2624 $attribs = implode(" ", $attribs); 2625 // Return HTML string 2626 $retval = "<img {$attribs} />"; 2627 } 2628 return $retval; 2629 } 2630 function _get_computed_image_url($image, $size = 'full') 2631 { 2632 $retval = NULL; 2633 $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance(); 2634 // Get the image abspath 2635 $image_abspath = $this->object->get_image_abspath($image, $size); 2636 if ($dynthumbs->is_size_dynamic($size) && !file_exists($image_abspath)) { 2637 if (defined('NGG_DISABLE_DYNAMIC_IMG_URLS') && constant('NGG_DISABLE_DYNAMIC_IMG_URLS')) { 2638 $params = array('watermark' => false, 'reflection' => false, 'crop' => true); 2639 $result = $this->generate_image_size($image, $size, $params); 2640 if ($result) { 2641 $image_abspath = $this->object->get_image_abspath($image, $size); 2642 } 2643 } else { 2644 return NULL; 2645 } 2646 } 2647 // Assuming we have an abspath, we can translate that to a url 2648 if ($image_abspath) { 2649 // Replace the gallery root with the proper url segment 2650 $gallery_root = preg_quote($this->get_gallery_root(), '#'); 2651 $image_uri = preg_replace("#^{$gallery_root}#", "", $image_abspath); 2652 // Url encode each uri segment 2653 $segments = explode("/", $image_uri); 2654 $segments = array_map('rawurlencode', $segments); 2655 $image_uri = preg_replace("#^/#", "", implode("/", $segments)); 2656 // Join gallery root and image uri 2657 $gallery_root = trailingslashit(NGG_GALLERY_ROOT_TYPE == 'site' ? site_url() : WP_CONTENT_URL); 2658 $gallery_root = is_ssl() ? str_replace('http:', 'https:', $gallery_root) : $gallery_root; 2659 $retval = $gallery_root . $image_uri; 2660 } 2661 return $retval; 2662 } 2663 function normalize_image_size_name($size = 'full') 2664 { 2665 switch ($size) { 2666 case 'full': 2667 case 'original': 2668 case 'image': 2669 case 'orig': 2670 case 'resized': 2671 $size = 'full'; 2672 break; 2673 case 'thumbnails': 2674 case 'thumbnail': 2675 case 'thumb': 2676 case 'thumbs': 2677 $size = 'thumbnail'; 2678 break; 2679 } 2680 return $size; 2681 } 2682 /** 2683 * Returns the named sizes available for images 2684 * @return array 2685 */ 2686 function get_image_sizes($image = FALSE) 2687 { 2688 $retval = array('full', 'thumbnail'); 2689 if (is_numeric($image)) { 2690 $image = C_Image_Mapper::get_instance()->find($image); 2691 } 2692 if ($image) { 2693 if ($image->meta_data) { 2694 $meta_data = is_object($image->meta_data) ? get_object_vars($image->meta_data) : $image->meta_data; 2695 foreach ($meta_data as $key => $value) { 2696 if (is_array($value) && isset($value['width']) && !in_array($key, $retval)) { 2697 $retval[] = $key; 2698 } 2699 } 2700 } 2701 } 2702 return $retval; 2703 } 2704 function get_image_size_params($image, $size, $params = array(), $skip_defaults = false) 2705 { 2706 // Get the image entity 2707 if (is_numeric($image)) { 2708 $image = $this->object->_image_mapper->find($image); 2709 } 2710 $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance(); 2711 if ($dynthumbs && $dynthumbs->is_size_dynamic($size)) { 2712 $named_params = $dynthumbs->get_params_from_name($size, true); 2713 if (!$params) { 2714 $params = array(); 2715 } 2716 $params = array_merge($params, $named_params); 2717 } 2718 $params = apply_filters('ngg_get_image_size_params', $params, $size, $image); 2719 // Ensure we have a valid image 2720 if ($image) { 2721 $settings = C_NextGen_Settings::get_instance(); 2722 if (!$skip_defaults) { 2723 // Get default settings 2724 if ($size == 'full') { 2725 if (!isset($params['quality'])) { 2726 $params['quality'] = $settings->imgQuality; 2727 } 2728 } else { 2729 if (!isset($params['crop'])) { 2730 $params['crop'] = $settings->thumbfix; 2731 } 2732 if (!isset($params['quality'])) { 2733 $params['quality'] = $settings->thumbquality; 2734 } 2735 } 2736 } 2737 // width and height when omitted make generate_image_clone create a clone with original size, so try find defaults regardless of $skip_defaults 2738 if (!isset($params['width']) || !isset($params['height'])) { 2739 // First test if this is a "known" image size, i.e. if we store these sizes somewhere when users re-generate these sizes from the UI...this is required to be compatible with legacy 2740 // try the 2 default built-in sizes, first thumbnail... 2741 if ($size == 'thumbnail') { 2742 if (!isset($params['width'])) { 2743 $params['width'] = $settings->thumbwidth; 2744 } 2745 if (!isset($params['height'])) { 2746 $params['height'] = $settings->thumbheight; 2747 } 2748 } else { 2749 if ($size == 'full') { 2750 if (!isset($params['width'])) { 2751 if ($settings->imgAutoResize) { 2752 $params['width'] = $settings->imgWidth; 2753 } 2754 } 2755 if (!isset($params['height'])) { 2756 if ($settings->imgAutoResize) { 2757 $params['height'] = $settings->imgHeight; 2758 } 2759 } 2760 } else { 2761 if (isset($image->meta_data) && isset($image->meta_data[$size])) { 2762 $dimensions = $image->meta_data[$size]; 2763 if (!isset($params['width'])) { 2764 $params['width'] = $dimensions['width']; 2765 } 2766 if (!isset($params['height'])) { 2767 $params['height'] = $dimensions['height']; 2768 } 2769 } 2770 } 2771 } 2772 } 2773 if (!isset($params['crop_frame'])) { 2774 $crop_frame_size_name = 'thumbnail'; 2775 if (isset($image->meta_data[$size]['crop_frame'])) { 2776 $crop_frame_size_name = $size; 2777 } 2778 if (isset($image->meta_data[$crop_frame_size_name]['crop_frame'])) { 2779 $params['crop_frame'] = $image->meta_data[$crop_frame_size_name]['crop_frame']; 2780 if (!isset($params['crop_frame']['final_width'])) { 2781 $params['crop_frame']['final_width'] = $image->meta_data[$crop_frame_size_name]['width']; 2782 } 2783 if (!isset($params['crop_frame']['final_height'])) { 2784 $params['crop_frame']['final_height'] = $image->meta_data[$crop_frame_size_name]['height']; 2785 } 2786 } 2787 } else { 2788 if (!isset($params['crop_frame']['final_width'])) { 2789 $params['crop_frame']['final_width'] = $params['width']; 2790 } 2791 if (!isset($params['crop_frame']['final_height'])) { 2792 $params['crop_frame']['final_height'] = $params['height']; 2793 } 2794 } 2795 } 2796 return $params; 2797 } 2798 /** 2799 * Alias to get_image_dimensions() 2800 * @param int|object $image 2801 * @return array 2802 */ 2803 function get_original_dimensions($image) 2804 { 2805 return $this->object->get_image_dimensions($image, 'full'); 2806 } 2807 /** 2808 * Alias to get_image_html() 2809 * @param int|object $image 2810 * @return string 2811 */ 2812 function get_original_html($image) 2813 { 2814 return $this->object->get_image_html($image, 'full'); 2815 } 2816 /** 2817 * Gets the url to the original-sized image 2818 * @param int|stdClass|C_Image $image 2819 * @param bool $check_existance (optional) 2820 * @return string 2821 */ 2822 function get_original_url($image, $check_existance = FALSE) 2823 { 2824 return $this->object->get_image_url($image, 'full', $check_existance); 2825 } 2826 /** 2827 * @param object|bool $gallery (optional) 2828 * @return string 2829 */ 2830 function get_upload_abspath($gallery = FALSE) 2831 { 2832 // Base upload path 2833 $retval = C_NextGen_Settings::get_instance()->gallerypath; 2834 $fs = C_Fs::get_instance(); 2835 // If a gallery has been specified, then we'll 2836 // append the slug 2837 if ($gallery) { 2838 $retval = $this->get_gallery_abspath($gallery); 2839 } 2840 // We need to make this an absolute path 2841 if (strpos($retval, $fs->get_document_root('gallery')) !== 0) { 2842 $retval = rtrim($fs->join_paths($fs->get_document_root('gallery'), $retval), "/\\"); 2843 } 2844 // Convert slashes 2845 return wp_normalize_path($retval); 2846 } 2847 /** 2848 * Gets the upload path, optionally for a particular gallery 2849 * @param int|C_Gallery|object|false $gallery (optional) 2850 * @return string 2851 */ 2852 function get_upload_relpath($gallery = FALSE) 2853 { 2854 $fs = C_Fs::get_instance(); 2855 $retval = str_replace($fs->get_document_root('gallery'), '', $this->object->get_upload_abspath($gallery)); 2856 return '/' . wp_normalize_path(ltrim($retval, "/")); 2857 } 2858 /** 2859 * Set correct file permissions (taken from wp core). Should be called 2860 * after writing any file 2861 * 2862 * @class nggAdmin 2863 * @param string $filename 2864 * @return bool $result 2865 */ 2866 function _chmod($filename = '') 2867 { 2868 $stat = @stat(dirname($filename)); 2869 $perms = $stat['mode'] & 0666; 2870 // Remove execute bits for files 2871 if (@chmod($filename, $perms)) { 2872 return TRUE; 2873 } 2874 return FALSE; 2875 } 2876 function _delete_gallery_directory($abspath) 2877 { 2878 // Remove all image files and purge all empty directories left over 2879 $iterator = new DirectoryIterator($abspath); 2880 // Only delete image files! Other files may be stored incorrectly but it's not our place to delete them 2881 $removable_extensions = apply_filters('ngg_allowed_file_types', NGG_DEFAULT_ALLOWED_FILE_TYPES); 2882 foreach ($removable_extensions as $extension) { 2883 $removable_extensions[] = $extension . '_backup'; 2884 } 2885 foreach ($iterator as $file) { 2886 if (in_array($file->getBasename(), array('.', '..'))) { 2887 continue; 2888 } elseif ($file->isFile() || $file->isLink()) { 2889 $extension = strtolower(pathinfo($file->getPathname(), PATHINFO_EXTENSION)); 2890 if (in_array($extension, $removable_extensions, TRUE)) { 2891 @unlink($file->getPathname()); 2892 } 2893 } elseif ($file->isDir()) { 2894 $this->object->_delete_gallery_directory($file->getPathname()); 2895 } 2896 } 2897 // DO NOT remove directories that still have files in them. Note: '.' and '..' are included with getSize() 2898 $empty = TRUE; 2899 foreach ($iterator as $file) { 2900 if (in_array($file->getBasename(), array('.', '..'))) { 2901 continue; 2902 } 2903 $empty = FALSE; 2904 } 2905 if ($empty) { 2906 @rmdir($iterator->getPath()); 2907 } 2908 } 2909 /** 2910 * @param C_Image[]|int[] $images 2911 * @param C_Gallery|int $dst_gallery 2912 * @return int[] 2913 */ 2914 function copy_images($images, $dst_gallery) 2915 { 2916 $retval = array(); 2917 // Ensure that the image ids we have are valid 2918 $image_mapper = C_Image_Mapper::get_instance(); 2919 foreach ($images as $image) { 2920 if (is_numeric($image)) { 2921 $image = $image_mapper->find($image); 2922 } 2923 $image_abspath = $this->object->get_image_abspath($image, 'backup') ?: $this->object->get_image_abspath($image); 2924 if ($image_abspath) { 2925 // Import the image; this will copy the main file 2926 $new_image_id = $this->object->import_image_file($dst_gallery, $image_abspath, $image->filename); 2927 if ($new_image_id) { 2928 // Copy the properties of the old image 2929 $new_image = $image_mapper->find($new_image_id); 2930 foreach (get_object_vars($image) as $key => $value) { 2931 if (in_array($key, array('pid', 'galleryid', 'meta_data', 'filename', 'sortorder', 'extras_post_id'))) { 2932 continue; 2933 } 2934 $new_image->{$key} = $value; 2935 } 2936 $image_mapper->save($new_image); 2937 // Copy tags 2938 $tags = wp_get_object_terms($image->pid, 'ngg_tag', 'fields=ids'); 2939 $tags = array_map('intval', $tags); 2940 wp_set_object_terms($new_image_id, $tags, 'ngg_tag', true); 2941 // Copy all of the generated versions (resized versions, watermarks, etc) 2942 foreach ($this->object->get_image_sizes($image) as $named_size) { 2943 if (in_array($named_size, array('full', 'thumbnail'))) { 2944 continue; 2945 } 2946 $old_abspath = $this->object->get_image_abspath($image, $named_size); 2947 $new_abspath = $this->object->get_image_abspath($new_image, $named_size); 2948 if (is_array(@stat($old_abspath))) { 2949 $new_dir = dirname($new_abspath); 2950 // Ensure the target directory exists 2951 if (@stat($new_dir) === FALSE) { 2952 wp_mkdir_p($new_dir); 2953 } 2954 @copy($old_abspath, $new_abspath); 2955 } 2956 } 2957 // Mark as done 2958 $retval[] = $new_image_id; 2959 } 2960 } 2961 } 2962 return $retval; 2963 } 2964 /** 2965 * Moves images from to another gallery 2966 * @param array $images 2967 * @param int|object $gallery 2968 * @return int[] 2969 */ 2970 function move_images($images, $gallery) 2971 { 2972 $retval = $this->object->copy_images($images, $gallery); 2973 if ($images) { 2974 foreach ($images as $image_id) { 2975 $this->object->delete_image($image_id); 2976 } 2977 } 2978 return $retval; 2979 } 2980 /** 2981 * @param string $abspath 2982 * @return bool 2983 */ 2984 function delete_directory($abspath) 2985 { 2986 $retval = FALSE; 2987 if (@file_exists($abspath)) { 2988 $files = scandir($abspath); 2989 array_shift($files); 2990 array_shift($files); 2991 foreach ($files as $file) { 2992 $file_abspath = implode(DIRECTORY_SEPARATOR, array(rtrim($abspath, "/\\"), $file)); 2993 if (is_dir($file_abspath)) { 2994 $this->object->delete_directory($file_abspath); 2995 } else { 2996 unlink($file_abspath); 2997 } 2998 } 2999 rmdir($abspath); 3000 $retval = @file_exists($abspath); 3001 } 3002 return $retval; 3003 } 3004 function delete_gallery($gallery) 3005 { 3006 $fs = C_Fs::get_instance(); 3007 $safe_dirs = array(DIRECTORY_SEPARATOR, $fs->get_document_root('plugins'), $fs->get_document_root('plugins_mu'), $fs->get_document_root('templates'), $fs->get_document_root('stylesheets'), $fs->get_document_root('content'), $fs->get_document_root('galleries'), $fs->get_document_root()); 3008 $abspath = $this->object->get_gallery_abspath($gallery); 3009 if ($abspath && file_exists($abspath) && !in_array(stripslashes($abspath), $safe_dirs)) { 3010 $this->object->_delete_gallery_directory($abspath); 3011 } 3012 } 3013 /** 3014 * @param int|C_Image $image 3015 * @param string|FALSE $size 3016 * @return bool 3017 */ 3018 function delete_image($image, $size = FALSE) 3019 { 3020 $retval = FALSE; 3021 // Ensure that we have the image entity 3022 if (is_numeric($image)) { 3023 $image = $this->object->_image_mapper->find($image); 3024 } 3025 if ($image) { 3026 $image_id = $image->{$image->id_field}; 3027 do_action('ngg_delete_image', $image_id, $size); 3028 // Delete only a particular image size 3029 if ($size) { 3030 $abspath = $this->object->get_image_abspath($image, $size); 3031 if ($abspath && @file_exists($abspath)) { 3032 @unlink($abspath); 3033 } 3034 if (isset($image->meta_data) && isset($image->meta_data[$size])) { 3035 unset($image->meta_data[$size]); 3036 $this->object->_image_mapper->save($image); 3037 } 3038 } else { 3039 foreach ($this->object->get_image_sizes($image) as $named_size) { 3040 $image_abspath = $this->object->get_image_abspath($image, $named_size); 3041 @unlink($image_abspath); 3042 } 3043 // Delete the entity 3044 $this->object->_image_mapper->destroy($image); 3045 } 3046 $retval = TRUE; 3047 } 3048 return $retval; 3049 } 3050 /** 3051 * Recover image from backup copy and reprocess it 3052 * 3053 * @param int|stdClass|C_Image $image 3054 * @return bool|string result code 3055 */ 3056 function recover_image($image) 3057 { 3058 $retval = FALSE; 3059 if (is_numeric($image)) { 3060 $image = $this->object->_image_mapper->find($image); 3061 } 3062 if ($image) { 3063 $full_abspath = $this->object->get_image_abspath($image); 3064 $backup_abspath = $this->object->get_image_abspath($image, 'backup'); 3065 if ($backup_abspath != $full_abspath && @file_exists($backup_abspath)) { 3066 if (is_writable($full_abspath) && is_writable(dirname($full_abspath))) { 3067 // Copy the backup 3068 if (@copy($backup_abspath, $full_abspath)) { 3069 // Backup images are not altered at all; we must re-correct the EXIF/Orientation tag 3070 $this->object->correct_exif_rotation($image, TRUE); 3071 // Re-create non-fullsize image sizes 3072 foreach ($this->object->get_image_sizes($image) as $named_size) { 3073 if (in_array($named_size, array('full', 'backup'))) { 3074 continue; 3075 } 3076 // Reset thumbnail cropping set by 'Edit thumb' dialog 3077 if ($named_size === 'thumbnail') { 3078 unset($image->meta_data[$named_size]['crop_frame']); 3079 } 3080 $thumbnail = $this->object->generate_image_clone($full_abspath, $this->object->get_image_abspath($image, $named_size), $this->object->get_image_size_params($image, $named_size)); 3081 if ($thumbnail) { 3082 $thumbnail->destruct(); 3083 } 3084 } 3085 do_action('ngg_recovered_image', $image); 3086 // Reimport all metadata 3087 $retval = $this->object->_image_mapper->reimport_metadata($image); 3088 } 3089 } 3090 } 3091 } 3092 return $retval; 3093 } 3094 /** 3095 * Copies a NGG image to the media library and returns the attachment_id 3096 * 3097 * @param C_Image|int|stdClass $image 3098 * @return FALSE|int attachment_id 3099 */ 3100 function copy_to_media_library($image) 3101 { 3102 $retval = FALSE; 3103 // Get the image 3104 if (is_int($image)) { 3105 $imageId = $image; 3106 $mapper = C_Image_Mapper::get_instance(); 3107 $image = $mapper->find($imageId); 3108 } 3109 if ($image) { 3110 $subdir = apply_filters('ngg_import_to_media_library_subdir', 'nggallery_import'); 3111 $wordpress_upload_dir = wp_upload_dir(); 3112 $path = $wordpress_upload_dir['path'] . DIRECTORY_SEPARATOR . $subdir; 3113 if (!file_exists($path)) { 3114 wp_mkdir_p($path); 3115 } 3116 $image_abspath = C_Gallery_Storage::get_instance()->get_image_abspath($image, "full"); 3117 $new_file_path = $path . DIRECTORY_SEPARATOR . $image->filename; 3118 $image_data = getimagesize($image_abspath); 3119 $new_file_mime = $image_data['mime']; 3120 $i = 1; 3121 while (file_exists($new_file_path)) { 3122 $i++; 3123 $new_file_path = $path . DIRECTORY_SEPARATOR . $i . '-' . $image->filename; 3124 } 3125 if (@copy($image_abspath, $new_file_path)) { 3126 $upload_id = wp_insert_attachment(['guid' => $new_file_path, 'post_mime_type' => $new_file_mime, 'post_title' => preg_replace('/\\.[^.]+$/', '', $image->alttext), 'post_content' => '', 'post_status' => 'inherit'], $new_file_path); 3127 update_post_meta($upload_id, '_ngg_image_id', intval($image->pid)); 3128 // wp_generate_attachment_metadata() comes from this file 3129 require_once ABSPATH . 'wp-admin/includes/image.php'; 3130 $image_meta = wp_generate_attachment_metadata($upload_id, $new_file_path); 3131 // Generate and save the attachment metas into the database 3132 wp_update_attachment_metadata($upload_id, $image_meta); 3133 $retval = $upload_id; 3134 } 3135 } 3136 return $retval; 3137 } 3138 /** 3139 * Delete the given NGG image from the media library 3140 * 3141 * @var int|stdClass $imageId 3142 */ 3143 function delete_from_media_library($imageId) 3144 { 3145 // Get the image 3146 if (!is_int($imageId)) { 3147 $image = $imageId; 3148 $imageId = $image->pid; 3149 } 3150 if ($postId = $this->object->is_in_media_library($imageId)) { 3151 wp_delete_post($postId); 3152 } 3153 } 3154 /** 3155 * Determines if the given NGG image id has been uploaded to the media library 3156 * 3157 * @param integer $imageId 3158 * @return FALSE|int attachment_id 3159 */ 3160 function is_in_media_library($imageId) 3161 { 3162 $retval = FALSE; 3163 // Get the image 3164 if (is_object($imageId)) { 3165 $image = $imageId; 3166 $imageId = $image->pid; 3167 } 3168 // Try to find an attachment for the given image_id 3169 if ($imageId) { 3170 $query = new WP_Query(array('post_type' => 'attachment', 'meta_key' => '_ngg_image_id', 'meta_value_num' => $imageId)); 3171 foreach ($query->get_posts() as $post) { 3172 $retval = $post->ID; 3173 } 3174 } 3175 return $retval; 3176 } 3177 /** 3178 * @param string $filename 3179 * @return bool 3180 */ 3181 public function is_allowed_image_extension($filename) 3182 { 3183 $extension = pathinfo($filename, PATHINFO_EXTENSION); 3184 $extension = strtolower($extension); 3185 $allowed_extensions = apply_filters('ngg_allowed_file_types', NGG_DEFAULT_ALLOWED_FILE_TYPES); 3186 foreach ($allowed_extensions as $extension) { 3187 $allowed_extensions[] = $extension . '_backup'; 3188 } 3189 return in_array($extension, $allowed_extensions); 3190 } 3191 function is_current_user_over_quota() 3192 { 3193 $retval = FALSE; 3194 $settings = C_NextGen_Settings::get_instance(); 3195 if (is_multisite() && $settings->get('wpmuQuotaCheck')) { 3196 require_once ABSPATH . 'wp-admin/includes/ms.php'; 3197 $retval = upload_is_user_over_quota(FALSE); 3198 } 3199 return $retval; 3200 } 3201 /** 3202 * @param string? $filename 3203 * @return bool 3204 */ 3205 function is_image_file($filename = NULL) 3206 { 3207 $retval = FALSE; 3208 if (!$filename && isset($_FILES['file']) && $_FILES['file']['error'] == 0) { 3209 $filename = $_FILES['file']['tmp_name']; 3210 } 3211 $allowed_mime = apply_filters('ngg_allowed_mime_types', NGG_DEFAULT_ALLOWED_MIME_TYPES); 3212 // If we can, we'll verify the mime type 3213 if (function_exists('exif_imagetype')) { 3214 if (($image_type = @exif_imagetype($filename)) !== FALSE) { 3215 $retval = in_array(image_type_to_mime_type($image_type), $allowed_mime); 3216 } 3217 } else { 3218 $file_info = @getimagesize($filename); 3219 if (isset($file_info[2])) { 3220 $retval = in_array(image_type_to_mime_type($file_info[2]), $allowed_mime); 3221 } 3222 } 3223 return $retval; 3224 } 3225 function is_zip() 3226 { 3227 $retval = FALSE; 3228 if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { 3229 $file_info = $_FILES['file']; 3230 if (isset($file_info['type'])) { 3231 $type = $file_info['type']; 3232 $type_parts = explode('/', $type); 3233 if (strtolower($type_parts[0]) == 'application') { 3234 $spec = $type_parts[1]; 3235 $spec_parts = explode('-', $spec); 3236 $spec_parts = array_map('strtolower', $spec_parts); 3237 if (in_array($spec, array('zip', 'octet-stream')) || in_array('zip', $spec_parts)) { 3238 $retval = true; 3239 } 3240 } 3241 } 3242 } 3243 return $retval; 3244 } 3245 function maybe_base64_decode($data) 3246 { 3247 $decoded = base64_decode($data); 3248 if ($decoded === FALSE) { 3249 return $data; 3250 } else { 3251 if (base64_encode($decoded) == $data) { 3252 return base64_decode($data); 3253 } 3254 } 3255 return $data; 3256 } 3257 function get_unique_abspath($file_abspath) 3258 { 3259 $filename = basename($file_abspath); 3260 $dir_abspath = dirname($file_abspath); 3261 $num = 1; 3262 $pattern = path_join($dir_abspath, "*_{$filename}"); 3263 if ($found = glob($pattern)) { 3264 natsort($found); 3265 $last = array_pop($found); 3266 $last = basename($last); 3267 if (preg_match("/^(\\d+)_/", $last, $match)) { 3268 $num = intval($match[1]) + 1; 3269 } 3270 } 3271 return path_join($dir_abspath, "{$num}_{$filename}"); 3272 } 3273 function sanitize_filename_for_db($filename = NULL) 3274 { 3275 $filename = $filename ? $filename : uniqid('nextgen-gallery'); 3276 $filename = preg_replace("#^/#", "", $filename); 3277 $filename = sanitize_file_name($filename); 3278 if (preg_match("/\\-(png|jpg|gif|jpeg|jpg_backup)\$/i", $filename, $match)) { 3279 $filename = str_replace($match[0], '.' . $match[1], $filename); 3280 } 3281 return $filename; 3282 } 3283 /** 3284 * Determines whether a WebP image is animated which GD does not support. 3285 * 3286 * @see https://developers.google.com/speed/webp/docs/riff_container 3287 * @param string $filename 3288 * @return bool 3289 */ 3290 public function is_animated_webp($filename) 3291 { 3292 $retval = FALSE; 3293 $handle = fopen($filename, 'rb'); 3294 fseek($handle, 12); 3295 if (fread($handle, 4) === 'VP8X') { 3296 fseek($handle, 20); 3297 $flag = fread($handle, 1); 3298 $retval = (bool) (ord($flag) >> 1 & 1); 3299 } 3300 fclose($handle); 3301 return $retval; 3302 } 3303 function import_image_file($dst_gallery, $image_abspath, $filename = NULL, $image = FALSE, $override = FALSE, $move = FALSE) 3304 { 3305 $image_abspath = wp_normalize_path($image_abspath); 3306 if ($this->object->is_current_user_over_quota()) { 3307 $message = sprintf(__('Sorry, you have used your space allocation. Please delete some files to upload more files.', 'nggallery')); 3308 throw new E_NoSpaceAvailableException($message); 3309 } 3310 // Do we have a gallery to import to? 3311 if ($dst_gallery) { 3312 // Get the gallery abspath. This is where we will put the image files 3313 $gallery_abspath = $this->object->get_gallery_abspath($dst_gallery); 3314 // If we can't write to the directory, then there's no point in continuing 3315 if (!@file_exists($gallery_abspath)) { 3316 @wp_mkdir_p($gallery_abspath); 3317 } 3318 if (!is_writable($gallery_abspath)) { 3319 throw new E_InsufficientWriteAccessException(FALSE, $gallery_abspath, FALSE); 3320 } 3321 // Sanitize the filename for storing in the DB 3322 $filename = $this->sanitize_filename_for_db($filename); 3323 // Ensure that the filename is valid 3324 $extensions = apply_filters('ngg_allowed_file_types', NGG_DEFAULT_ALLOWED_FILE_TYPES); 3325 $extensions[] = '_backup'; 3326 $ext_list = implode('|', $extensions); 3327 if (!preg_match("/({$ext_list})\$/i", $filename)) { 3328 throw new E_UploadException(__('Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery')); 3329 } 3330 // GD does not support animated WebP and will generate a fatal error when we try to create thumbnails or resize 3331 if ($this->is_animated_webp($image_abspath)) { 3332 throw new E_UploadException(__('Animated WebP images are not supported.', 'nggallery')); 3333 } 3334 // Compute the destination folder 3335 $new_image_abspath = path_join($gallery_abspath, $filename); 3336 // Are the src and dst the same? If so, we don't have to copy or move files 3337 if ($image_abspath != $new_image_abspath) { 3338 // If we're not to override, ensure that the filename is unique 3339 if (!$override && @file_exists($new_image_abspath)) { 3340 $new_image_abspath = $this->object->get_unique_abspath($new_image_abspath); 3341 $filename = $this->sanitize_filename_for_db(basename($new_image_abspath)); 3342 } 3343 // Try storing the file 3344 $copied = copy($image_abspath, $new_image_abspath); 3345 if ($copied && $move) { 3346 unlink($image_abspath); 3347 } 3348 // Ensure that we're not vulerable to CVE-2017-2416 exploit 3349 if (($dimensions = getimagesize($new_image_abspath)) !== FALSE) { 3350 if (isset($dimensions[0]) && intval($dimensions[0]) > 30000 || isset($dimensions[1]) && intval($dimensions[1]) > 30000) { 3351 unlink($new_image_abspath); 3352 throw new E_UploadException(__('Image file too large. Maximum image dimensions supported are 30k x 30k.')); 3353 } 3354 } 3355 } 3356 // Save the image in the DB 3357 $image_mapper = C_Image_Mapper::get_instance(); 3358 $image_mapper->_use_cache = FALSE; 3359 if ($image) { 3360 if (is_numeric($image)) { 3361 $image = $image_mapper->find($image); 3362 } 3363 } 3364 if (!$image) { 3365 $image = $image_mapper->create(); 3366 } 3367 $image->alttext = preg_replace("#\\.\\w{2,4}\$#", "", $filename); 3368 $image->galleryid = is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid; 3369 $image->filename = $filename; 3370 $image->image_slug = nggdb::get_unique_slug(sanitize_title_with_dashes($image->alttext), 'image'); 3371 $image_id = $image_mapper->save($image); 3372 if (!$image_id) { 3373 $exception = ''; 3374 foreach ($image->get_errors() as $field => $errors) { 3375 foreach ($errors as $error) { 3376 if (!empty($exception)) { 3377 $exception .= "<br/>"; 3378 } 3379 $exception .= __(sprintf("Error while uploading %s: %s", $filename, $error), 'nextgen-gallery'); 3380 } 3381 } 3382 throw new E_UploadException($exception); 3383 } 3384 // Important: do not remove this line. The image mapper's save() routine imports metadata 3385 // meaning we must re-acquire a new $image object after saving it above; if we do not our 3386 // existing $image object will lose any metadata retrieved during said save() method. 3387 $image = $image_mapper->find($image_id); 3388 $image_mapper->_use_cache = TRUE; 3389 $settings = C_NextGen_Settings::get_instance(); 3390 // Backup the image 3391 if ($settings->get('imgBackup', FALSE)) { 3392 $this->object->backup_image($image, TRUE); 3393 } 3394 // Most browsers do not honor EXIF's Orientation header: rotate the image to prevent display issues 3395 $this->object->correct_exif_rotation($image, TRUE); 3396 // Create resized version of image 3397 if ($settings->get('imgAutoResize', FALSE)) { 3398 $this->object->generate_resized_image($image, TRUE); 3399 } 3400 // Generate a thumbnail for the image 3401 $this->object->generate_thumbnail($image); 3402 // Set gallery preview image if missing 3403 C_Gallery_Mapper::get_instance()->set_preview_image($dst_gallery, $image_id, TRUE); 3404 // Automatically watermark the main image if requested 3405 if ($settings->get('watermark_automatically_at_upload', 0)) { 3406 $image_abspath = $this->object->get_image_abspath($image, 'full'); 3407 $this->object->generate_image_clone($image_abspath, $image_abspath, array('watermark' => TRUE)); 3408 } 3409 // Notify other plugins that an image has been added 3410 do_action('ngg_added_new_image', $image); 3411 // delete dirsize after adding new images 3412 delete_transient('dirsize_cache'); 3413 // Seems redundant to above hook. Maintaining for legacy purposes 3414 do_action('ngg_after_new_images_added', is_numeric($dst_gallery) ? $dst_gallery : $dst_gallery->gid, array($image_id)); 3415 return $image_id; 3416 } else { 3417 throw new E_EntityNotFoundException(); 3418 } 3419 return NULL; 3420 } 3421 /** 3422 * Uploads base64 file to a gallery 3423 * 3424 * @param int|stdClass|C_Gallery $gallery 3425 * @param string $data base64-encoded string of data representing the image 3426 * @param string|false (optional) $filename specifies the name of the file 3427 * @param int|false $image_id (optional) 3428 * @param bool $override (optional) 3429 * @return bool|int 3430 */ 3431 function upload_base64_image($gallery, $data, $filename = FALSE, $image_id = FALSE, $override = FALSE, $move = FALSE) 3432 { 3433 try { 3434 $temp_abspath = tempnam(sys_get_temp_dir(), ''); 3435 // Try writing the image 3436 $fp = fopen($temp_abspath, 'wb'); 3437 fwrite($fp, $this->maybe_base64_decode($data)); 3438 fclose($fp); 3439 } catch (E_UploadException $ex) { 3440 throw $ex; 3441 } 3442 return $this->object->import_image_file($gallery, $temp_abspath, $filename, $image_id, $override, $move); 3443 } 3444 /** 3445 * Uploads an image for a particular gallery 3446 * @param int|object|C_Gallery $gallery 3447 * @param string|bool $filename (optional) Specifies the name of the file 3448 * @param string|bool $data (optional) If specified, expects base64 encoded string of data 3449 * @return C_Image 3450 */ 3451 function upload_image($gallery, $filename = FALSE, $data = FALSE) 3452 { 3453 $retval = NULL; 3454 // Ensure that we have the data present that we require 3455 if (isset($_FILES['file']) && $_FILES['file']['error'] == 0) { 3456 // $_FILES = Array( 3457 // [file] => Array ( 3458 // [name] => Canada_landscape4.jpg 3459 // [type] => image/jpeg 3460 // [tmp_name] => /private/var/tmp/php6KO7Dc 3461 // [error] => 0 3462 // [size] => 64975 3463 // ) 3464 // 3465 $file = $_FILES['file']; 3466 if ($this->object->is_zip()) { 3467 $retval = $this->object->upload_zip($gallery); 3468 } else { 3469 if ($this->is_image_file()) { 3470 $retval = $this->object->import_image_file($gallery, $file['tmp_name'], $filename ? $filename : (isset($file['name']) ? $file['name'] : FALSE), FALSE, FALSE, TRUE); 3471 } else { 3472 // Remove the non-valid (and potentially insecure) file from the PHP upload directory 3473 if (isset($_FILES['file']['tmp_name'])) { 3474 $filename = $_FILES['file']['tmp_name']; 3475 @unlink($filename); 3476 } 3477 throw new E_UploadException(__('Invalid image file. Acceptable formats: JPG, GIF, and PNG.', 'nggallery')); 3478 } 3479 } 3480 } elseif ($data) { 3481 $retval = $this->object->upload_base64_image($gallery, $data, $filename); 3482 } else { 3483 throw new E_UploadException(); 3484 } 3485 return $retval; 3486 } 3487 /** 3488 * @param int $gallery_id 3489 * @return array|bool 3490 */ 3491 function upload_zip($gallery_id) 3492 { 3493 if (!$this->object->is_zip()) { 3494 return FALSE; 3495 } 3496 $retval = FALSE; 3497 $memory_limit = intval(ini_get('memory_limit')); 3498 if (!extension_loaded('suhosin') && $memory_limit < 256) { 3499 @ini_set('memory_limit', '256M'); 3500 } 3501 $fs = C_Fs::get_instance(); 3502 // Uses the WordPress ZIP abstraction API 3503 include_once $fs->join_paths(ABSPATH, 'wp-admin', 'includes', 'file.php'); 3504 WP_Filesystem(FALSE, get_temp_dir(), TRUE); 3505 // Ensure that we truly have the gallery id 3506 $gallery_id = $this->object->_get_gallery_id($gallery_id); 3507 $zipfile = $_FILES['file']['tmp_name']; 3508 $dest_path = implode(DIRECTORY_SEPARATOR, array(rtrim(get_temp_dir(), "/\\"), 'unpacked-' . M_I18n::mb_basename($zipfile))); 3509 // Attempt to extract the zip file into the normal system directory 3510 $extracted = $this->object->extract_zip($zipfile, $dest_path); 3511 // Now verify it worked. get_temp_dir() will check each of the following directories to ensure they are 3512 // a directory and against wp_is_writable(). Should ALL of those options fail we will fallback to wp_upload_dir(). 3513 // 3514 // WP_TEMP_DIR 3515 // sys_get_temp_dir() 3516 // ini/upload_tmp_dir 3517 // WP_CONTENT_DIR 3518 // /tmp 3519 $size = 0; 3520 $files = glob($dest_path . DIRECTORY_SEPARATOR . '*'); 3521 foreach ($files as $file) { 3522 if (is_array(stat($file))) { 3523 $size += filesize($file); 3524 } 3525 } 3526 // Extraction failed; attempt again with wp_upload_dir() 3527 if ($size == 0) { 3528 // Remove the empty directory we may have possibly created but could not write to 3529 $this->object->delete_directory($dest_path); 3530 $destination = wp_upload_dir(); 3531 $destination_path = $destination['basedir']; 3532 $dest_path = implode(DIRECTORY_SEPARATOR, array(rtrim($destination_path, "/\\"), rand(), 'unpacked-' . M_I18n::mb_basename($zipfile))); 3533 $extracted = $this->object->extract_zip($zipfile, $dest_path); 3534 } 3535 if ($extracted) { 3536 $retval = $this->object->import_gallery_from_fs($dest_path, $gallery_id); 3537 } 3538 $this->object->delete_directory($dest_path); 3539 if (!extension_loaded('suhosin')) { 3540 @ini_set('memory_limit', $memory_limit . 'M'); 3541 } 3542 return $retval; 3543 } 3544 /** 3545 * @param string $zipfile 3546 * @param string $dest_path 3547 * @return bool FALSE on failure 3548 */ 3549 public function extract_zip($zipfile, $dest_path) 3550 { 3551 wp_mkdir_p($dest_path); 3552 if (class_exists('ZipArchive', FALSE) && apply_filters('unzip_file_use_ziparchive', TRUE)) { 3553 $zipObj = new ZipArchive(); 3554 if ($zipObj->open($zipfile) === FALSE) { 3555 return FALSE; 3556 } 3557 for ($i = 0; $i < $zipObj->numFiles; $i++) { 3558 $filename = $zipObj->getNameIndex($i); 3559 if (!$this->object->is_allowed_image_extension($filename)) { 3560 continue; 3561 } 3562 $zipObj->extractTo($dest_path, array($zipObj->getNameIndex($i))); 3563 } 3564 } else { 3565 require_once ABSPATH . 'wp-admin/includes/class-pclzip.php'; 3566 $zipObj = new PclZip($zipfile); 3567 $zipContent = $zipObj->listContent(); 3568 $indexesToExtract = array(); 3569 foreach ($zipContent as $zipItem) { 3570 if ($zipItem['folder']) { 3571 continue; 3572 } 3573 if (!$this->object->is_allowed_image_extension($zipItem['stored_filename'])) { 3574 continue; 3575 } 3576 $indexesToExtract[] = $zipItem['index']; 3577 } 3578 if (!$zipObj->extractByIndex(implode(',', $indexesToExtract), $dest_path)) { 3579 return FALSE; 3580 } 3581 } 3582 return TRUE; 3583 } 3584 } 1471 3585 class C_Router_Wrapper extends Mixin 1472 3586 { … … 1487 3601 } 1488 3602 return self::$instances[$context]; 3603 } 3604 } 3605 /** 3606 * Provides methods to C_Gallery_Storage related to dynamic images, thumbnails, clones, etc 3607 * @property C_Gallery_Storage $object 3608 */ 3609 class Mixin_GalleryStorage_Base_Dynamic extends Mixin 3610 { 3611 /** 3612 * Generates a specific size for an image 3613 * @param int|object|C_Image $image 3614 * @param string $size 3615 * @param array|null $params (optional) 3616 * @param bool $skip_defaults (optional) 3617 * @return bool|object 3618 */ 3619 function generate_image_size($image, $size, $params = null, $skip_defaults = false) 3620 { 3621 $retval = FALSE; 3622 // Get the image entity 3623 if (is_numeric($image)) { 3624 $image = $this->object->_image_mapper->find($image); 3625 } 3626 // Ensure we have a valid image 3627 if ($image) { 3628 $params = $this->object->get_image_size_params($image, $size, $params, $skip_defaults); 3629 $settings = C_NextGen_Settings::get_instance(); 3630 // Get the image filename 3631 $filename = $this->object->get_image_abspath($image, 'original'); 3632 $thumbnail = null; 3633 if ($size == 'full' && $settings->imgBackup == 1) { 3634 // XXX change this? 'full' should be the resized path and 'original' the _backup path 3635 $backup_path = $this->object->get_backup_abspath($image); 3636 if (!@file_exists($backup_path)) { 3637 @copy($filename, $backup_path); 3638 } 3639 } 3640 // Generate the thumbnail using WordPress 3641 $existing_image_abpath = $this->object->get_image_abspath($image, $size); 3642 $existing_image_dir = dirname($existing_image_abpath); 3643 wp_mkdir_p($existing_image_dir); 3644 $clone_path = $existing_image_abpath; 3645 $thumbnail = $this->object->generate_image_clone($filename, $clone_path, $params); 3646 // We successfully generated the thumbnail 3647 if ($thumbnail != null) { 3648 $clone_path = $thumbnail->fileName; 3649 if (function_exists('getimagesize')) { 3650 $dimensions = getimagesize($clone_path); 3651 } else { 3652 $dimensions = array($params['width'], $params['height']); 3653 } 3654 if (!isset($image->meta_data)) { 3655 $image->meta_data = array(); 3656 } 3657 $size_meta = array('width' => $dimensions[0], 'height' => $dimensions[1], 'filename' => M_I18n::mb_basename($clone_path), 'generated' => microtime()); 3658 if (isset($params['crop_frame'])) { 3659 $size_meta['crop_frame'] = $params['crop_frame']; 3660 } 3661 $image->meta_data[$size] = $size_meta; 3662 if ($size == 'full') { 3663 $image->meta_data['width'] = $size_meta['width']; 3664 $image->meta_data['height'] = $size_meta['height']; 3665 } 3666 $retval = $this->object->_image_mapper->save($image); 3667 do_action('ngg_generated_image', $image, $size, $params); 3668 if ($retval == 0) { 3669 $retval = false; 3670 } 3671 if ($retval) { 3672 $retval = $thumbnail; 3673 } 3674 } else { 3675 // Something went wrong. Thumbnail generation failed! 3676 } 3677 } 3678 return $retval; 3679 } 3680 /** 3681 * Generates a thumbnail for an image 3682 * @param int|stdClass|C_Image $image 3683 * @return bool 3684 */ 3685 function generate_thumbnail($image, $params = null, $skip_defaults = false) 3686 { 3687 $sized_image = $this->object->generate_image_size($image, 'thumbnail', $params, $skip_defaults); 3688 $retval = false; 3689 if ($sized_image != null) { 3690 $retval = true; 3691 $sized_image->destruct(); 3692 } 3693 return $retval; 3694 } 3695 } 3696 /** 3697 * Provides getter methods to C_Gallery_Storage for determining absolute paths, URL, etc 3698 * @property C_Gallery_Storage $object 3699 */ 3700 class Mixin_GalleryStorage_Base_Getters extends Mixin 3701 { 3702 static $image_abspath_cache = array(); 3703 static $image_url_cache = array(); 3704 /** 3705 * Gets the absolute path of the backup of an original image 3706 * @param string $image 3707 * @return null|string 3708 */ 3709 function get_backup_abspath($image) 3710 { 3711 $retval = null; 3712 if ($image_path = $this->object->get_image_abspath($image)) { 3713 $retval = $image_path . '_backup'; 3714 } 3715 return $retval; 3716 } 3717 function get_backup_dimensions($image) 3718 { 3719 return $this->object->get_image_dimensions($image, 'backup'); 3720 } 3721 function get_backup_url($image) 3722 { 3723 return $this->object->get_image_url($image, 'backup'); 3724 } 3725 /** 3726 * Gets the absolute path where the image is stored. Can optionally return the path for a particular sized image. 3727 * @param int|object $image 3728 * @param string $size (optional) Default = full 3729 * @param bool $check_existance (optional) Default = false 3730 * @return string 3731 */ 3732 function get_image_abspath($image, $size = 'full', $check_existance = FALSE) 3733 { 3734 $image_id = is_numeric($image) ? $image : $image->pid; 3735 $size = $this->object->normalize_image_size_name($size); 3736 $key = strval($image_id) . $size; 3737 if ($check_existance || !isset(self::$image_abspath_cache[$key])) { 3738 $retval = $this->object->_get_computed_image_abspath($image, $size, $check_existance); 3739 self::$image_abspath_cache[$key] = $retval; 3740 } 3741 $retval = self::$image_abspath_cache[$key]; 3742 return $retval; 3743 } 3744 /** 3745 * Gets the url of a particular-sized image 3746 * @param int|object $image 3747 * @param string $size 3748 * @return string 3749 */ 3750 function get_image_url($image, $size = 'full') 3751 { 3752 $retval = NULL; 3753 $image_id = is_numeric($image) ? $image : $image->pid; 3754 $key = strval($image_id) . $size; 3755 $success = TRUE; 3756 if (!isset(self::$image_url_cache[$key])) { 3757 $url = $this->object->_get_computed_image_url($image, $size); 3758 if ($url) { 3759 self::$image_url_cache[$key] = $url; 3760 $success = TRUE; 3761 } else { 3762 $success = FALSE; 3763 } 3764 } 3765 if ($success) { 3766 $retval = self::$image_url_cache[$key]; 3767 } else { 3768 $dynthumbs = C_Dynamic_Thumbnails_Manager::get_instance(); 3769 if ($dynthumbs->is_size_dynamic($size)) { 3770 $params = $dynthumbs->get_params_from_name($size); 3771 $retval = \Imagely\NGG\Util\Router::get_instance()->get_url($dynthumbs->get_image_uri($image, $params), FALSE, 'root'); 3772 } 3773 } 3774 return apply_filters('ngg_get_image_url', $retval, $image, $size); 3775 } 3776 /** 3777 * An alias for get_full_abspath() 3778 * @param int|object $image 3779 * @param bool $check_existance 3780 * @return null|string 3781 */ 3782 function get_original_abspath($image, $check_existance = FALSE) 3783 { 3784 return $this->object->get_image_abspath($image, 'full', $check_existance); 3785 } 3786 /** 3787 * Flushes the cache we use for path/url calculation for images 3788 */ 3789 function flush_image_path_cache($image, $size) 3790 { 3791 $image = is_numeric($image) ? $image : $image->pid; 3792 $key = strval($image) . $size; 3793 unset(self::$image_abspath_cache[$key]); 3794 unset(self::$image_url_cache[$key]); 3795 } 3796 } 3797 /** 3798 * Provides the basic methods of gallery management to C_Gallery_Storage 3799 * @property C_Gallery_Storage $object 3800 */ 3801 class Mixin_GalleryStorage_Base_Management extends Mixin 3802 { 3803 /** 3804 * Backs up an image file 3805 * 3806 * @param int|object $image 3807 * @param bool $save 3808 * @return bool 3809 */ 3810 function backup_image($image, $save = TRUE) 3811 { 3812 $retval = FALSE; 3813 $image_path = $this->object->get_image_abspath($image); 3814 if ($image_path && @file_exists($image_path)) { 3815 $retval = copy($image_path, $this->object->get_backup_abspath($image)); 3816 // Store the dimensions of the image 3817 if (function_exists('getimagesize')) { 3818 $mapper = C_Image_Mapper::get_instance(); 3819 if (!is_object($image)) { 3820 $image = $mapper->find($image); 3821 } 3822 if ($image) { 3823 if (empty($image->meta_data) || !is_array($image->meta_data)) { 3824 $image->meta_data = array(); 3825 } 3826 $dimensions = getimagesize($image_path); 3827 $image->meta_data['backup'] = array('filename' => basename($image_path), 'width' => $dimensions[0], 'height' => $dimensions[1], 'generated' => microtime()); 3828 if ($save) { 3829 $mapper->save($image); 3830 } 3831 } 3832 } 3833 } 3834 return $retval; 3835 } 3836 } 3837 /** 3838 * Provides upload-related methods used by C_Gallery_Storage 3839 * @property C_Gallery_Storage $object 3840 */ 3841 class Mixin_GalleryStorage_Base_Upload extends Mixin 3842 { 3843 /** 3844 * @param string $abspath 3845 * @param int $gallery_id 3846 * @param bool $create_new_gallerypath 3847 * @param null|string $gallery_title 3848 * @param array[string] $filenames 3849 * @return array|bool FALSE on failure 3850 */ 3851 function import_gallery_from_fs($abspath, $gallery_id = NULL, $create_new_gallerypath = TRUE, $gallery_title = NULL, $filenames = array()) 3852 { 3853 if (@(!file_exists($abspath))) { 3854 return FALSE; 3855 } 3856 $fs = C_Fs::get_instance(); 3857 $retval = array('image_ids' => array()); 3858 // Ensure that this folder has images 3859 $files = array(); 3860 $directories = array(); 3861 foreach (scandir($abspath) as $file) { 3862 if ($file == '.' || $file == '..' || strtoupper($file) == '__MACOSX') { 3863 continue; 3864 } 3865 $file_abspath = $fs->join_paths($abspath, $file); 3866 // Omit 'hidden' directories prefixed with a period 3867 if (is_dir($file_abspath) && strpos($file, '.') !== 0) { 3868 $directories[] = $file_abspath; 3869 } elseif ($this->is_image_file($file_abspath)) { 3870 if ($filenames && array_search($file_abspath, $filenames) !== FALSE) { 3871 $files[] = $file_abspath; 3872 } else { 3873 if (!$filenames) { 3874 $files[] = $file_abspath; 3875 } 3876 } 3877 } 3878 } 3879 if (empty($files) && empty($directories)) { 3880 return FALSE; 3881 } 3882 // Get needed utilities 3883 $gallery_mapper = C_Gallery_Mapper::get_instance(); 3884 // Recurse through the directory and pull in all of the valid images we find 3885 if (!empty($directories)) { 3886 foreach ($directories as $dir) { 3887 $subImport = $this->object->import_gallery_from_fs($dir, $gallery_id, $create_new_gallerypath, $gallery_title, $filenames); 3888 if ($subImport) { 3889 $retval['image_ids'] = array_merge($retval['image_ids'], $subImport['image_ids']); 3890 } 3891 } 3892 } 3893 // If no gallery has been specified, then use the directory name as the gallery name 3894 if (!$gallery_id) { 3895 // Create the gallery 3896 $gallery = $gallery_mapper->create(array('title' => $gallery_title ? $gallery_title : M_I18n::mb_basename($abspath))); 3897 if (!$create_new_gallerypath) { 3898 $gallery_root = $fs->get_document_root('gallery'); 3899 $gallery->path = str_ireplace($gallery_root, '', $abspath); 3900 } 3901 // Save the gallery 3902 if ($gallery->save()) { 3903 $gallery_id = $gallery->id(); 3904 } 3905 } 3906 // Ensure that we have a gallery id 3907 if (!$gallery_id) { 3908 return FALSE; 3909 } else { 3910 $retval['gallery_id'] = $gallery_id; 3911 } 3912 // Remove full sized image if backup is included 3913 $files_to_import = []; 3914 foreach ($files as $file_abspath) { 3915 if (preg_match("#_backup\$#", $file_abspath)) { 3916 $files_to_import[] = $file_abspath; 3917 continue; 3918 } elseif (in_array([$file_abspath . "_backup", 'thumbs_' . $file_abspath, 'thumbs-' . $file_abspath], $files)) { 3919 continue; 3920 } 3921 $files_to_import[] = $file_abspath; 3922 } 3923 foreach ($files_to_import as $file_abspath) { 3924 $basename = preg_replace('#_backup$#', '', pathinfo($file_abspath, PATHINFO_BASENAME)); 3925 if ($this->is_image_file($file_abspath)) { 3926 if ($image_id = $this->import_image_file($gallery_id, $file_abspath, $basename, FALSE, FALSE, FALSE)) { 3927 $retval['image_ids'][] = $image_id; 3928 } 3929 } 3930 } 3931 // Add the gallery name to the result 3932 if (!isset($gallery)) { 3933 $gallery = $gallery_mapper->find($gallery_id); 3934 } 3935 $retval['gallery_name'] = $gallery->title; 3936 return $retval; 1489 3937 } 1490 3938 } -
nextgen-gallery/trunk/products/photocrati_nextgen/modules/marketing/module.marketing.php
r3003333 r3004370 405 405 $url = 'https://wordpress.org/plugins/nextgen-gallery/reviews/?filter=5#new-post'; 406 406 /* translators: %s: url */ 407 $text = sprintf( __( 'Please rate <strong>Nextgen Gallery by Imagely</strong> <a href="%1$s" target="_blank">★★★★★</a> on <a href="%2$s" target="_blank">WordPress.org</a> to help us spread the word. Thank you from the EnviraGallery team!', 'nggallery' ), $url, $url );407 $text = sprintf( __( 'Please rate <strong>Nextgen Gallery by Imagely</strong> <a href="%1$s" target="_blank">★★★★★</a> on <a href="%2$s" target="_blank">WordPress.org</a> to help us spread the word. Thank you from the NextGEN Gallery team!', 'nggallery' ), $url, $url ); 408 408 } 409 409 return $text; -
nextgen-gallery/trunk/products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php
r3003333 r3004370 1 1 <?php 2 /**3 * Class C_Displayed_Gallery_Mapper4 *5 * @mixin Mixin_Displayed_Gallery_Defaults6 */7 class C_Displayed_Gallery_Mapper extends C_CustomPost_DataMapper_Driver8 {9 static $_instances = array();10 public function define($context = false, $not_used = false)11 {12 parent::define('displayed_gallery', [$context, 'displayed_gallery', 'display_gallery']);13 $this->add_mixin('Mixin_Displayed_Gallery_Defaults');14 $this->implement('I_Displayed_Gallery_Mapper');15 $this->set_model_factory_method('displayed_gallery');16 // $this->add_post_hook(17 // 'save',18 // 'Propagate thumbnail dimensions',19 // 'Hook_Propagate_Thumbnail_Dimensions_To_Settings'20 // );21 }22 /**23 * Initializes the mapper24 */25 public function initialize()26 {27 parent::initialize();28 }29 /**30 * Gets a singleton of the mapper31 *32 * @param string|bool $context33 * @return C_Displayed_Gallery_Mapper34 */35 public static function get_instance($context = false)36 {37 if (!isset(self::$_instances[$context])) {38 self::$_instances[$context] = new C_Displayed_Gallery_Mapper($context);39 }40 return self::$_instances[$context];41 }42 /**43 * Gets a display type object for a particular entity44 *45 * @param stdClass|C_DataMapper_Model $entity46 * @return null|stdClass47 */48 public function get_display_type($entity)49 {50 $mapper = C_Display_Type_Mapper::get_instance();51 return $mapper->find_by_name($entity->display_type);52 }53 }54 /**55 * Adds default values for the displayed gallery56 */57 class Mixin_Displayed_Gallery_Defaults extends Mixin58 {59 /**60 * Sets defaults needed for the entity61 *62 * @param object $entity63 */64 public function set_defaults($entity)65 {66 // Ensure that we have a settings array.67 if (!isset($entity->display_settings)) {68 $entity->display_settings = [];69 }70 // If the display type is set, then get it's settings and apply them as71 // defaults to the "display_settings" of the displayed gallery.72 if (isset($entity->display_type)) {73 // Get display type mapper.74 if ($display_type = $this->object->get_display_type($entity)) {75 $entity->display_settings = $this->array_merge_assoc($display_type->settings, $entity->display_settings, true);76 }77 }78 // Default ordering.79 $settings = C_NextGen_Settings::get_instance();80 $this->object->_set_default_value($entity, 'order_by', $settings->galSort);81 $this->object->_set_default_value($entity, 'order_direction', $settings->galSortDir);82 // Ensure we have an exclusions array.83 $this->object->_set_default_value($entity, 'exclusions', []);84 // Ensure other properties exist.85 $this->object->_set_default_value($entity, 'container_ids', []);86 $this->object->_set_default_value($entity, 'excluded_container_ids', []);87 $this->object->_set_default_value($entity, 'sortorder', []);88 $this->object->_set_default_value($entity, 'entity_ids', []);89 $this->object->_set_default_value($entity, 'returns', 'included');90 // Set maximum_entity_count.91 $this->object->_set_default_value($entity, 'maximum_entity_count', $settings->maximum_entity_count);92 }93 } -
nextgen-gallery/trunk/readme.txt
r3003964 r3004370 3 3 Tags: wordpress gallery plugin, gallery, nextgen, nextgen gallery, photo gallery, image gallery, photography, slideshow, images, photo, photo album, watermark 4 4 Requires at least: 5.5.4 5 Stable tag: 3.5 35 Stable tag: 3.54 6 6 Tested up to: 6.4.1 7 7 License: GPLv3 … … 179 179 180 180 == Changelog == 181 182 = V3.54 - 12.01.2023 = 183 * Fixed: Assorted possible PHP warnings and notices with PHP 8.0+. 184 * Fixed: Compatibility with some 3rd party extensions. 181 185 182 186 = V3.53 - 11.30.2023 = -
nextgen-gallery/trunk/src/DataStorage/Manager.php
r3003892 r3004370 19 19 protected $image_mapper; 20 20 21 /** 22 * Deprecated 23 */ 21 /** @deprecated */ 24 22 public $_image_mapper; 23 24 /** @deprecated */ 25 public $object; 25 26 26 27 protected static $gallery_abspath_cache = []; … … 33 34 34 35 /** 35 * Deprecated 36 * 37 * !!! TODO remove in a later release - imagify fix 38 */ 36 * @TODO Remove in a later release - this fixes an issue with Imagify at the time of 3.50's release. 37 */ 39 38 $this->object = $this; 40 39 $this->_image_mapper = $this->image_mapper; … … 1156 1155 if ( ! $retval && $dynthumbs && $dynthumbs->is_size_dynamic( $size ) ) { 1157 1156 $new_dims = $this->calculate_image_size_dimensions( $image, $size ); 1158 $retval = [ 1159 'width' => $new_dims['real_width'], 1160 'height' => $new_dims['real_height'], 1161 ]; 1157 // Prevent a possible PHP warning if the sizes weren't calculated. 1158 if ( isset ( $new_dims['real_width'] ) && isset ( $new_dims['real_height'] ) ) { 1159 $retval = [ 1160 'width' => $new_dims['real_width'], 1161 'height' => $new_dims['real_height'], 1162 ]; 1163 } 1162 1164 } 1163 1165 } … … 2847 2849 return $order_by; 2848 2850 } 2851 2852 2853 /** 2854 * Gets the id of an image, regardless of whether an integer or object was passed as an argument. 2855 * 2856 * This method is, as of 3.50's release, used by EWWW and WP-SmushIt 2857 * 2858 * @param object|int $image_obj_or_id 2859 * @return null|int 2860 * @deprecated 2861 */ 2862 function _get_image_id($image_obj_or_id) 2863 { 2864 $retval = NULL; 2865 2866 $image_key = $this->_image_mapper->get_primary_key_column(); 2867 if (is_object($image_obj_or_id)) { 2868 if (isset($image_obj_or_id->$image_key)) { 2869 $retval = $image_obj_or_id->$image_key; 2870 } 2871 } 2872 elseif (is_numeric($image_obj_or_id)) { 2873 $retval = $image_obj_or_id; 2874 } 2875 2876 return $retval; 2877 } 2849 2878 } -
nextgen-gallery/trunk/src/DataTypes/Image.php
r3003333 r3004370 22 22 public $post_id; 23 23 public $sortorder; 24 public $tags; 24 25 public $updated_at; 25 26 -
nextgen-gallery/trunk/src/Display/DisplayManager.php
r3003892 r3004370 462 462 463 463 if ( empty( $dirs['default'] ) ) { 464 $dirs['default'] = \C_NextGEN_Bootstrap::get_legacy_module_directory( $display_type->name ) . DIRECTORY_SEPARATOR . 'templates'; 464 // In case the module path cannot be determined, we must intervene here if the resulting string is just '/templates' 465 // which is a place where template files should not be stored. 466 $directory = \C_NextGEN_Bootstrap::get_legacy_module_directory( $display_type->name ) . DIRECTORY_SEPARATOR . 'templates'; 467 if ( '/templates' !== $directory ) { 468 $dirs['default'] = $directory; 469 } 465 470 } 466 471 -
nextgen-gallery/trunk/src/Display/StaticAssets.php
r3003333 r3004370 68 68 } 69 69 70 if ( ! is_null( $retval ) ) {70 if ( is_string ( $retval ) ) { 71 71 // Adjust for windows paths. 72 72 return \wp_normalize_path( $retval ); -
nextgen-gallery/trunk/src/DisplayType/LegacyTemplateLocator.php
r3003333 r3004370 106 106 $template_abspath = false; 107 107 108 // Legacy templates may be an absolute path to a file that was moved in NextGEN 3.50. Here we remap the legacy 109 // path to the current one. 110 if ( false !== strpos( $template_name, 'nextgen-gallery/products/photocrati_nextgen/modules/ngglegacy' ) ) { 111 $template_name = str_replace( 112 'nextgen-gallery/products/photocrati_nextgen/modules/ngglegacy', 113 'nextgen-gallery/src/Legacy', 114 $template_name 115 ); 116 } 117 108 118 // hook into the render feature to allow other plugins to include templates. 109 119 $custom_template = apply_filters( 'ngg_render_template', false, $template_name ); -
nextgen-gallery/trunk/src/IGW/ATPManager.php
r3003333 r3004370 273 273 NGG_SCRIPT_VERSION 274 274 ); 275 \wp_enqueue_style( 'nextgen_addgallery_page' ); 276 \wp_enqueue_style( 'ngg_marketing_blocks_style' ); 277 \wp_enqueue_style( 'uppy' ); 275 278 \wp_enqueue_script( 'nextgen_admin_js' ); 276 279 \wp_enqueue_style( 'nextgen_admin_css' ); -
nextgen-gallery/trunk/src/Legacy/admin/manage-galleries.php
r3003892 r3004370 445 445 accept-charset="utf-8"> 446 446 447 <?php wp_nonce_field( 'ngg_ addgallery' ); ?>447 <?php wp_nonce_field( 'ngg_bulkgallery' ); ?> 448 448 449 449 <input type="hidden" -
nextgen-gallery/trunk/src/Legacy/admin/manage.php
r3003892 r3004370 612 612 if ( isset( $_POST['addgallery'] ) && isset( $_POST['galleryname'] ) ) { 613 613 614 check_admin_referer( 'ngg_ addgallery' );614 check_admin_referer( 'ngg_bulkgallery' ); 615 615 616 616 if ( ! nggGallery::current_user_can( 'NextGEN Add new gallery' ) ) { -
nextgen-gallery/trunk/vendor/autoload.php
r3003964 r3004370 23 23 require_once __DIR__ . '/composer/autoload_real.php'; 24 24 25 return ComposerAutoloaderInit 947270fe14b33b958df8910a24cbf812::getLoader();25 return ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211::getLoader(); -
nextgen-gallery/trunk/vendor/composer/ClassLoader.php
r3003964 r3004370 43 43 class ClassLoader 44 44 { 45 /** @var \Closure(string):void */ 46 private static $includeFile; 47 48 /** @var string|null */ 45 /** @var ?string */ 49 46 private $vendorDir; 50 47 51 48 // PSR-4 52 49 /** 53 * @var array<string, array<string, int>> 50 * @var array[] 51 * @psalm-var array<string, array<string, int>> 54 52 */ 55 53 private $prefixLengthsPsr4 = array(); 56 54 /** 57 * @var array<string, list<string>> 55 * @var array[] 56 * @psalm-var array<string, array<int, string>> 58 57 */ 59 58 private $prefixDirsPsr4 = array(); 60 59 /** 61 * @var list<string> 60 * @var array[] 61 * @psalm-var array<string, string> 62 62 */ 63 63 private $fallbackDirsPsr4 = array(); … … 65 65 // PSR-0 66 66 /** 67 * List of PSR-0 prefixes 68 * 69 * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) 70 * 71 * @var array<string, array<string, list<string>>> 67 * @var array[] 68 * @psalm-var array<string, array<string, string[]>> 72 69 */ 73 70 private $prefixesPsr0 = array(); 74 71 /** 75 * @var list<string> 72 * @var array[] 73 * @psalm-var array<string, string> 76 74 */ 77 75 private $fallbackDirsPsr0 = array(); … … 81 79 82 80 /** 83 * @var array<string, string> 81 * @var string[] 82 * @psalm-var array<string, string> 84 83 */ 85 84 private $classMap = array(); … … 89 88 90 89 /** 91 * @var array<string, bool> 90 * @var bool[] 91 * @psalm-var array<string, bool> 92 92 */ 93 93 private $missingClasses = array(); 94 94 95 /** @var string|null*/95 /** @var ?string */ 96 96 private $apcuPrefix; 97 97 98 98 /** 99 * @var array<string, self>99 * @var self[] 100 100 */ 101 101 private static $registeredLoaders = array(); 102 102 103 103 /** 104 * @param string|null$vendorDir104 * @param ?string $vendorDir 105 105 */ 106 106 public function __construct($vendorDir = null) 107 107 { 108 108 $this->vendorDir = $vendorDir; 109 self::initializeIncludeClosure(); 110 } 111 112 /** 113 * @return array<string, list<string>> 109 } 110 111 /** 112 * @return string[] 114 113 */ 115 114 public function getPrefixes() … … 123 122 124 123 /** 125 * @return array<string, list<string>> 124 * @return array[] 125 * @psalm-return array<string, array<int, string>> 126 126 */ 127 127 public function getPrefixesPsr4() … … 131 131 132 132 /** 133 * @return list<string> 133 * @return array[] 134 * @psalm-return array<string, string> 134 135 */ 135 136 public function getFallbackDirs() … … 139 140 140 141 /** 141 * @return list<string> 142 * @return array[] 143 * @psalm-return array<string, string> 142 144 */ 143 145 public function getFallbackDirsPsr4() … … 147 149 148 150 /** 149 * @return array<string, string> Array of classname => path 151 * @return string[] Array of classname => path 152 * @psalm-return array<string, string> 150 153 */ 151 154 public function getClassMap() … … 155 158 156 159 /** 157 * @param array<string, string> $classMap Class to filename map 160 * @param string[] $classMap Class to filename map 161 * @psalm-param array<string, string> $classMap 158 162 * 159 163 * @return void … … 172 176 * appending or prepending to the ones previously set for this prefix. 173 177 * 174 * @param string $prefix The prefix175 * @param list<string>|string $paths The PSR-0 root directories176 * @param bool $prepend Whether to prepend the directories178 * @param string $prefix The prefix 179 * @param string[]|string $paths The PSR-0 root directories 180 * @param bool $prepend Whether to prepend the directories 177 181 * 178 182 * @return void … … 180 184 public function add($prefix, $paths, $prepend = false) 181 185 { 182 $paths = (array) $paths;183 186 if (!$prefix) { 184 187 if ($prepend) { 185 188 $this->fallbackDirsPsr0 = array_merge( 186 $paths,189 (array) $paths, 187 190 $this->fallbackDirsPsr0 188 191 ); … … 190 193 $this->fallbackDirsPsr0 = array_merge( 191 194 $this->fallbackDirsPsr0, 192 $paths195 (array) $paths 193 196 ); 194 197 } … … 199 202 $first = $prefix[0]; 200 203 if (!isset($this->prefixesPsr0[$first][$prefix])) { 201 $this->prefixesPsr0[$first][$prefix] = $paths;204 $this->prefixesPsr0[$first][$prefix] = (array) $paths; 202 205 203 206 return; … … 205 208 if ($prepend) { 206 209 $this->prefixesPsr0[$first][$prefix] = array_merge( 207 $paths,210 (array) $paths, 208 211 $this->prefixesPsr0[$first][$prefix] 209 212 ); … … 211 214 $this->prefixesPsr0[$first][$prefix] = array_merge( 212 215 $this->prefixesPsr0[$first][$prefix], 213 $paths216 (array) $paths 214 217 ); 215 218 } … … 220 223 * appending or prepending to the ones previously set for this namespace. 221 224 * 222 * @param string $prefix The prefix/namespace, with trailing '\\'223 * @param list<string>|string $paths The PSR-4 base directories224 * @param bool $prepend Whether to prepend the directories225 * @param string $prefix The prefix/namespace, with trailing '\\' 226 * @param string[]|string $paths The PSR-4 base directories 227 * @param bool $prepend Whether to prepend the directories 225 228 * 226 229 * @throws \InvalidArgumentException … … 230 233 public function addPsr4($prefix, $paths, $prepend = false) 231 234 { 232 $paths = (array) $paths;233 235 if (!$prefix) { 234 236 // Register directories for the root namespace. 235 237 if ($prepend) { 236 238 $this->fallbackDirsPsr4 = array_merge( 237 $paths,239 (array) $paths, 238 240 $this->fallbackDirsPsr4 239 241 ); … … 241 243 $this->fallbackDirsPsr4 = array_merge( 242 244 $this->fallbackDirsPsr4, 243 $paths245 (array) $paths 244 246 ); 245 247 } … … 251 253 } 252 254 $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 253 $this->prefixDirsPsr4[$prefix] = $paths;255 $this->prefixDirsPsr4[$prefix] = (array) $paths; 254 256 } elseif ($prepend) { 255 257 // Prepend directories for an already registered namespace. 256 258 $this->prefixDirsPsr4[$prefix] = array_merge( 257 $paths,259 (array) $paths, 258 260 $this->prefixDirsPsr4[$prefix] 259 261 ); … … 262 264 $this->prefixDirsPsr4[$prefix] = array_merge( 263 265 $this->prefixDirsPsr4[$prefix], 264 $paths266 (array) $paths 265 267 ); 266 268 } … … 271 273 * replacing any others previously set for this prefix. 272 274 * 273 * @param string $prefix The prefix274 * @param list<string>|string $paths The PSR-0 base directories275 * @param string $prefix The prefix 276 * @param string[]|string $paths The PSR-0 base directories 275 277 * 276 278 * @return void … … 289 291 * replacing any others previously set for this namespace. 290 292 * 291 * @param string $prefix The prefix/namespace, with trailing '\\'292 * @param list<string>|string $paths The PSR-4 base directories293 * @param string $prefix The prefix/namespace, with trailing '\\' 294 * @param string[]|string $paths The PSR-4 base directories 293 295 * 294 296 * @throws \InvalidArgumentException … … 424 426 { 425 427 if ($file = $this->findFile($class)) { 426 $includeFile = self::$includeFile; 427 $includeFile($file); 428 includeFile($file); 428 429 429 430 return true; … … 476 477 477 478 /** 478 * Returns the currently registered loaders keyed by their corresponding vendor directories.479 * 480 * @return array<string, self>479 * Returns the currently registered loaders indexed by their corresponding vendor directories. 480 * 481 * @return self[] 481 482 */ 482 483 public static function getRegisteredLoaders() … … 555 556 return false; 556 557 } 557 558 /**559 * @return void560 */561 private static function initializeIncludeClosure()562 {563 if (self::$includeFile !== null) {564 return;565 }566 567 /**568 * Scope isolated include.569 *570 * Prevents access to $this/self from included files.571 *572 * @param string $file573 * @return void574 */575 self::$includeFile = \Closure::bind(static function($file) {576 include $file;577 }, null, null);578 }579 558 } 559 560 /** 561 * Scope isolated include. 562 * 563 * Prevents access to $this/self from included files. 564 * 565 * @param string $file 566 * @return void 567 * @private 568 */ 569 function includeFile($file) 570 { 571 include $file; 572 } -
nextgen-gallery/trunk/vendor/composer/InstalledVersions.php
r3003964 r3004370 99 99 foreach (self::getInstalled() as $installed) { 100 100 if (isset($installed['versions'][$packageName])) { 101 return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false;101 return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); 102 102 } 103 103 } … … 120 120 public static function satisfies(VersionParser $parser, $packageName, $constraint) 121 121 { 122 $constraint = $parser->parseConstraints( (string)$constraint);122 $constraint = $parser->parseConstraints($constraint); 123 123 $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); 124 124 … … 329 329 $installed[] = self::$installedByVendor[$vendorDir]; 330 330 } elseif (is_file($vendorDir.'/composer/installed.php')) { 331 /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ 332 $required = require $vendorDir.'/composer/installed.php'; 333 $installed[] = self::$installedByVendor[$vendorDir] = $required; 331 $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; 334 332 if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { 335 333 self::$installed = $installed[count($installed) - 1]; … … 343 341 // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 344 342 if (substr(__DIR__, -8, 1) !== 'C') { 345 /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ 346 $required = require __DIR__ . '/installed.php'; 347 self::$installed = $required; 343 self::$installed = require __DIR__ . '/installed.php'; 348 344 } else { 349 345 self::$installed = array(); 350 346 } 351 347 } 352 353 if (self::$installed !== array()) { 354 $installed[] = self::$installed; 355 } 348 $installed[] = self::$installed; 356 349 357 350 return $installed; -
nextgen-gallery/trunk/vendor/composer/autoload_real.php
r3003964 r3004370 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 947270fe14b33b958df8910a24cbf8125 class ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 947270fe14b33b958df8910a24cbf812', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 947270fe14b33b958df8910a24cbf812', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 947270fe14b33b958df8910a24cbf812::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit865a398218c279eb1f33c4f1d4258211::getInitializer($loader)); 33 33 34 34 $loader->register(true); 35 35 36 $filesToLoad = \Composer\Autoload\ComposerStaticInit947270fe14b33b958df8910a24cbf812::$files; 37 $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { 38 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 39 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 40 41 require $file; 42 } 43 }, null, null); 44 foreach ($filesToLoad as $fileIdentifier => $file) { 45 $requireFile($fileIdentifier, $file); 36 $includeFiles = \Composer\Autoload\ComposerStaticInit865a398218c279eb1f33c4f1d4258211::$files; 37 foreach ($includeFiles as $fileIdentifier => $file) { 38 composerRequire865a398218c279eb1f33c4f1d4258211($fileIdentifier, $file); 46 39 } 47 40 … … 49 42 } 50 43 } 44 45 /** 46 * @param string $fileIdentifier 47 * @param string $file 48 * @return void 49 */ 50 function composerRequire865a398218c279eb1f33c4f1d4258211($fileIdentifier, $file) 51 { 52 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 53 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 54 55 require $file; 56 } 57 } -
nextgen-gallery/trunk/vendor/composer/autoload_static.php
r3003964 r3004370 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 947270fe14b33b958df8910a24cbf8127 class ComposerStaticInit865a398218c279eb1f33c4f1d4258211 8 8 { 9 9 public static $files = array ( … … 29 29 { 30 30 return \Closure::bind(function () use ($loader) { 31 $loader->prefixesPsr0 = ComposerStaticInit 947270fe14b33b958df8910a24cbf812::$prefixesPsr0;32 $loader->classMap = ComposerStaticInit 947270fe14b33b958df8910a24cbf812::$classMap;31 $loader->prefixesPsr0 = ComposerStaticInit865a398218c279eb1f33c4f1d4258211::$prefixesPsr0; 32 $loader->classMap = ComposerStaticInit865a398218c279eb1f33c4f1d4258211::$classMap; 33 33 34 34 }, null, ClassLoader::class); -
nextgen-gallery/trunk/vendor/composer/installed.json
r3003964 r3004370 82 82 "time": "2023-11-10T13:42:01+00:00", 83 83 "type": "library", 84 "installation-source": " source",84 "installation-source": "dist", 85 85 "autoload": { 86 86 "files": [
Note: See TracChangeset
for help on using the changeset viewer.