Plugin Directory

Changeset 3004370


Ignore:
Timestamp:
12/01/2023 05:46:36 PM (2 years ago)
Author:
photocrati
Message:

Released 3.54

Location:
nextgen-gallery/trunk
Files:
2 deleted
26 edited

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  
    297297        padding-left: 0;
    298298    }
     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    }
    299308    #wpfooter {
    300309        margin-top: auto;
     
    485494    }
    486495}
     496
  • nextgen-gallery/trunk/changelog.txt

    r3003964 r3004370  
    11NextGEN Gallery
    22by 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.
    37
    48= V3.53  - 11.30.2023 =
  • nextgen-gallery/trunk/composer.json

    r3003333 r3004370  
    1515    "require": {
    1616        "imagely/pope-framework": "v0.18",
    17         "ezyang/htmlpurifier": "^4.13"
     17        "ezyang/htmlpurifier": "^4.17"
    1818    },
    1919    "require-dev": {
  • nextgen-gallery/trunk/composer.lock

    r3003964 r3004370  
    55        "This file is @generated automatically"
    66    ],
    7     "content-hash": "947270fe14b33b958df8910a24cbf812",
     7    "content-hash": "014ccdbc6a38f77f4cfcc66c7f01e693",
    88    "packages": [
    99        {
     
    575575        {
    576576            "name": "phpstan/phpstan",
    577             "version": "1.10.46",
     577            "version": "1.10.47",
    578578            "source": {
    579579                "type": "git",
    580580                "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",
    587587                "shasum": ""
    588588            },
     
    633633                }
    634634            ],
    635             "time": "2023-11-28T14:57:26+00:00"
     635            "time": "2023-12-01T15:19:17+00:00"
    636636        },
    637637        {
     
    907907    "platform": [],
    908908    "platform-dev": [],
    909     "plugin-api-version": "2.6.0"
     909    "plugin-api-version": "2.3.0"
    910910}
  • nextgen-gallery/trunk/nggallery.php

    r3003964 r3004370  
    33 * Plugin Name: NextGEN Gallery
    44 * 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.53
     5 * Version: 3.54
    66 * Author: Imagely
    77 * Plugin URI: https://www.imagely.com/wordpress-gallery-plugin/nextgen-gallery/
     
    123123
    124124        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 ) ) {
    125129            set_exception_handler( __CLASS__ . '::shutdown' );
    126130        }
     
    259263        class_alias( '\Imagely\NGG\DataMappers\Gallery', 'C_Gallery_Mapper' );
    260264        class_alias( '\Imagely\NGG\DataMappers\Image', 'C_Image_Mapper' );
    261         class_alias( '\Imagely\NGG\DataStorage\Manager', 'C_Gallery_Storage' );
    262265        class_alias( '\Imagely\NGG\DataStorage\MetaData', 'C_NextGen_Metadata' );
    263266        class_alias( '\Imagely\NGG\DataTypes\LegacyImage', 'C_Image_Wrapper' );
     
    532535        // Nonce verification is not necessary here.
    533536        // 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 ) {
    535544            return;
    536545        }
     
    921930        define( 'NGG_MODULE_DIR', implode( DIRECTORY_SEPARATOR, [ rtrim( NGG_PRODUCT_DIR, '/\\' ), 'photocrati_nextgen', 'modules' ] ) );
    922931        define( 'NGG_PLUGIN_STARTED_AT', microtime() );
    923         define( 'NGG_PLUGIN_VERSION', '3.53' );
     932        define( 'NGG_PLUGIN_VERSION', '3.54' );
    924933
    925934        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  
    3131        $registry->add_utility( 'I_Display_Type_Mapper', 'C_Display_Type_Mapper' );
    3232        $registry->add_utility( 'I_Displayed_Gallery_Mapper', 'C_Displayed_Gallery_Mapper' );
     33        $registry->add_utility( 'I_Gallery_Storage', 'C_Gallery_Storage' );
    3334        $registry->add_utility( 'I_Router', 'C_Router_Wrapper' );
    3435    }
     
    4041    public function get_type_list() {
    4142        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',
    5258        ];
    5359    }
  • nextgen-gallery/trunk/products/photocrati_nextgen/modules/legacy_compat/package.module.legacy_compat.php

    r3003333 r3004370  
    12421242        }
    12431243        return $retval;
     1244    }
     1245}
     1246/**
     1247 * Class C_Displayed_Gallery_Mapper
     1248 *
     1249 * @mixin Mixin_Displayed_Gallery_Defaults
     1250 */
     1251class 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 */
     1301class 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);
    12441336    }
    12451337}
     
    14691561    }
    14701562}
     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 */
     1570class 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}
    14713585class C_Router_Wrapper extends Mixin
    14723586{
     
    14873601        }
    14883602        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 */
     3609class 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 */
     3700class 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 */
     3801class 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 */
     3841class 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;
    14893937    }
    14903938}
  • nextgen-gallery/trunk/products/photocrati_nextgen/modules/marketing/module.marketing.php

    r3003333 r3004370  
    405405            $url = 'https://wordpress.org/plugins/nextgen-gallery/reviews/?filter=5#new-post';
    406406            /* translators: %s: url */
    407             $text = sprintf( __( 'Please rate <strong>Nextgen Gallery by Imagely</strong> <a href="%1$s" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</a> on <a href="%2$s" target="_blank">WordPress.org</a> to help us spread the word. Thank you from the Envira Gallery team!', 'nggallery' ), $url, $url );
     407            $text = sprintf( __( 'Please rate <strong>Nextgen Gallery by Imagely</strong> <a href="%1$s" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</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 );
    408408        }
    409409        return $text;
  • nextgen-gallery/trunk/products/photocrati_nextgen/modules/nextgen_gallery_display/package.module.nextgen_gallery_display.php

    r3003333 r3004370  
    11<?php
    2 /**
    3  * Class C_Displayed_Gallery_Mapper
    4  *
    5  * @mixin Mixin_Displayed_Gallery_Defaults
    6  */
    7 class C_Displayed_Gallery_Mapper extends C_CustomPost_DataMapper_Driver
    8 {
    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 mapper
    24      */
    25     public function initialize()
    26     {
    27         parent::initialize();
    28     }
    29     /**
    30      * Gets a singleton of the mapper
    31      *
    32      * @param string|bool $context
    33      * @return C_Displayed_Gallery_Mapper
    34      */
    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 entity
    44      *
    45      * @param stdClass|C_DataMapper_Model $entity
    46      * @return null|stdClass
    47      */
    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 gallery
    56  */
    57 class Mixin_Displayed_Gallery_Defaults extends Mixin
    58 {
    59     /**
    60      * Sets defaults needed for the entity
    61      *
    62      * @param object $entity
    63      */
    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 as
    71         // 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  
    33Tags: wordpress gallery plugin, gallery, nextgen, nextgen gallery, photo gallery, image gallery, photography, slideshow, images, photo, photo album, watermark
    44Requires at least: 5.5.4
    5 Stable tag: 3.53
     5Stable tag: 3.54
    66Tested up to: 6.4.1
    77License: GPLv3
     
    179179
    180180== 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.
    181185
    182186= V3.53  - 11.30.2023 =
  • nextgen-gallery/trunk/src/DataStorage/Manager.php

    r3003892 r3004370  
    1919    protected $image_mapper;
    2020
    21     /**
    22      * Deprecated
    23      */
     21    /** @deprecated */
    2422    public $_image_mapper;
     23
     24    /** @deprecated */
     25    public $object;
    2526
    2627    protected static $gallery_abspath_cache = [];
     
    3334
    3435        /**
    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         */
    3938        $this->object = $this;
    4039        $this->_image_mapper   = $this->image_mapper;
     
    11561155                if ( ! $retval && $dynthumbs && $dynthumbs->is_size_dynamic( $size ) ) {
    11571156                    $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                    }
    11621164                }
    11631165            }
     
    28472849        return $order_by;
    28482850    }
     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    }
    28492878}
  • nextgen-gallery/trunk/src/DataTypes/Image.php

    r3003333 r3004370  
    2222    public $post_id;
    2323    public $sortorder;
     24    public $tags;
    2425    public $updated_at;
    2526
  • nextgen-gallery/trunk/src/Display/DisplayManager.php

    r3003892 r3004370  
    462462
    463463        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            }
    465470        }
    466471
  • nextgen-gallery/trunk/src/Display/StaticAssets.php

    r3003333 r3004370  
    6868        }
    6969
    70         if ( ! is_null ( $retval ) ) {
     70        if ( is_string ( $retval ) ) {
    7171            // Adjust for windows paths.
    7272            return \wp_normalize_path( $retval );
  • nextgen-gallery/trunk/src/DisplayType/LegacyTemplateLocator.php

    r3003333 r3004370  
    106106        $template_abspath = false;
    107107
     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
    108118        // hook into the render feature to allow other plugins to include templates.
    109119        $custom_template = apply_filters( 'ngg_render_template', false, $template_name );
  • nextgen-gallery/trunk/src/IGW/ATPManager.php

    r3003333 r3004370  
    273273                NGG_SCRIPT_VERSION
    274274            );
     275            \wp_enqueue_style( 'nextgen_addgallery_page' );
     276            \wp_enqueue_style( 'ngg_marketing_blocks_style' );
     277            \wp_enqueue_style( 'uppy' );
    275278            \wp_enqueue_script( 'nextgen_admin_js' );
    276279            \wp_enqueue_style( 'nextgen_admin_css' );
  • nextgen-gallery/trunk/src/Legacy/admin/manage-galleries.php

    r3003892 r3004370  
    445445                accept-charset="utf-8">
    446446
    447             <?php wp_nonce_field( 'ngg_addgallery' ); ?>
     447            <?php wp_nonce_field( 'ngg_bulkgallery' ); ?>
    448448
    449449            <input type="hidden"
  • nextgen-gallery/trunk/src/Legacy/admin/manage.php

    r3003892 r3004370  
    612612        if ( isset( $_POST['addgallery'] ) && isset( $_POST['galleryname'] ) ) {
    613613
    614             check_admin_referer( 'ngg_addgallery' );
     614            check_admin_referer( 'ngg_bulkgallery' );
    615615
    616616            if ( ! nggGallery::current_user_can( 'NextGEN Add new gallery' ) ) {
  • nextgen-gallery/trunk/vendor/autoload.php

    r3003964 r3004370  
    2323require_once __DIR__ . '/composer/autoload_real.php';
    2424
    25 return ComposerAutoloaderInit947270fe14b33b958df8910a24cbf812::getLoader();
     25return ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211::getLoader();
  • nextgen-gallery/trunk/vendor/composer/ClassLoader.php

    r3003964 r3004370  
    4343class ClassLoader
    4444{
    45     /** @var \Closure(string):void */
    46     private static $includeFile;
    47 
    48     /** @var string|null */
     45    /** @var ?string */
    4946    private $vendorDir;
    5047
    5148    // PSR-4
    5249    /**
    53      * @var array<string, array<string, int>>
     50     * @var array[]
     51     * @psalm-var array<string, array<string, int>>
    5452     */
    5553    private $prefixLengthsPsr4 = array();
    5654    /**
    57      * @var array<string, list<string>>
     55     * @var array[]
     56     * @psalm-var array<string, array<int, string>>
    5857     */
    5958    private $prefixDirsPsr4 = array();
    6059    /**
    61      * @var list<string>
     60     * @var array[]
     61     * @psalm-var array<string, string>
    6262     */
    6363    private $fallbackDirsPsr4 = array();
     
    6565    // PSR-0
    6666    /**
    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[]>>
    7269     */
    7370    private $prefixesPsr0 = array();
    7471    /**
    75      * @var list<string>
     72     * @var array[]
     73     * @psalm-var array<string, string>
    7674     */
    7775    private $fallbackDirsPsr0 = array();
     
    8179
    8280    /**
    83      * @var array<string, string>
     81     * @var string[]
     82     * @psalm-var array<string, string>
    8483     */
    8584    private $classMap = array();
     
    8988
    9089    /**
    91      * @var array<string, bool>
     90     * @var bool[]
     91     * @psalm-var array<string, bool>
    9292     */
    9393    private $missingClasses = array();
    9494
    95     /** @var string|null */
     95    /** @var ?string */
    9696    private $apcuPrefix;
    9797
    9898    /**
    99      * @var array<string, self>
     99     * @var self[]
    100100     */
    101101    private static $registeredLoaders = array();
    102102
    103103    /**
    104      * @param string|null $vendorDir
     104     * @param ?string $vendorDir
    105105     */
    106106    public function __construct($vendorDir = null)
    107107    {
    108108        $this->vendorDir = $vendorDir;
    109         self::initializeIncludeClosure();
    110     }
    111 
    112     /**
    113      * @return array<string, list<string>>
     109    }
     110
     111    /**
     112     * @return string[]
    114113     */
    115114    public function getPrefixes()
     
    123122
    124123    /**
    125      * @return array<string, list<string>>
     124     * @return array[]
     125     * @psalm-return array<string, array<int, string>>
    126126     */
    127127    public function getPrefixesPsr4()
     
    131131
    132132    /**
    133      * @return list<string>
     133     * @return array[]
     134     * @psalm-return array<string, string>
    134135     */
    135136    public function getFallbackDirs()
     
    139140
    140141    /**
    141      * @return list<string>
     142     * @return array[]
     143     * @psalm-return array<string, string>
    142144     */
    143145    public function getFallbackDirsPsr4()
     
    147149
    148150    /**
    149      * @return array<string, string> Array of classname => path
     151     * @return string[] Array of classname => path
     152     * @psalm-return array<string, string>
    150153     */
    151154    public function getClassMap()
     
    155158
    156159    /**
    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
    158162     *
    159163     * @return void
     
    172176     * appending or prepending to the ones previously set for this prefix.
    173177     *
    174      * @param string              $prefix  The prefix
    175      * @param list<string>|string $paths   The PSR-0 root directories
    176      * @param bool                $prepend Whether to prepend the directories
     178     * @param string          $prefix  The prefix
     179     * @param string[]|string $paths   The PSR-0 root directories
     180     * @param bool            $prepend Whether to prepend the directories
    177181     *
    178182     * @return void
     
    180184    public function add($prefix, $paths, $prepend = false)
    181185    {
    182         $paths = (array) $paths;
    183186        if (!$prefix) {
    184187            if ($prepend) {
    185188                $this->fallbackDirsPsr0 = array_merge(
    186                     $paths,
     189                    (array) $paths,
    187190                    $this->fallbackDirsPsr0
    188191                );
     
    190193                $this->fallbackDirsPsr0 = array_merge(
    191194                    $this->fallbackDirsPsr0,
    192                     $paths
     195                    (array) $paths
    193196                );
    194197            }
     
    199202        $first = $prefix[0];
    200203        if (!isset($this->prefixesPsr0[$first][$prefix])) {
    201             $this->prefixesPsr0[$first][$prefix] = $paths;
     204            $this->prefixesPsr0[$first][$prefix] = (array) $paths;
    202205
    203206            return;
     
    205208        if ($prepend) {
    206209            $this->prefixesPsr0[$first][$prefix] = array_merge(
    207                 $paths,
     210                (array) $paths,
    208211                $this->prefixesPsr0[$first][$prefix]
    209212            );
     
    211214            $this->prefixesPsr0[$first][$prefix] = array_merge(
    212215                $this->prefixesPsr0[$first][$prefix],
    213                 $paths
     216                (array) $paths
    214217            );
    215218        }
     
    220223     * appending or prepending to the ones previously set for this namespace.
    221224     *
    222      * @param string              $prefix  The prefix/namespace, with trailing '\\'
    223      * @param list<string>|string $paths   The PSR-4 base directories
    224      * @param bool                $prepend Whether to prepend the directories
     225     * @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
    225228     *
    226229     * @throws \InvalidArgumentException
     
    230233    public function addPsr4($prefix, $paths, $prepend = false)
    231234    {
    232         $paths = (array) $paths;
    233235        if (!$prefix) {
    234236            // Register directories for the root namespace.
    235237            if ($prepend) {
    236238                $this->fallbackDirsPsr4 = array_merge(
    237                     $paths,
     239                    (array) $paths,
    238240                    $this->fallbackDirsPsr4
    239241                );
     
    241243                $this->fallbackDirsPsr4 = array_merge(
    242244                    $this->fallbackDirsPsr4,
    243                     $paths
     245                    (array) $paths
    244246                );
    245247            }
     
    251253            }
    252254            $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
    253             $this->prefixDirsPsr4[$prefix] = $paths;
     255            $this->prefixDirsPsr4[$prefix] = (array) $paths;
    254256        } elseif ($prepend) {
    255257            // Prepend directories for an already registered namespace.
    256258            $this->prefixDirsPsr4[$prefix] = array_merge(
    257                 $paths,
     259                (array) $paths,
    258260                $this->prefixDirsPsr4[$prefix]
    259261            );
     
    262264            $this->prefixDirsPsr4[$prefix] = array_merge(
    263265                $this->prefixDirsPsr4[$prefix],
    264                 $paths
     266                (array) $paths
    265267            );
    266268        }
     
    271273     * replacing any others previously set for this prefix.
    272274     *
    273      * @param string              $prefix The prefix
    274      * @param list<string>|string $paths  The PSR-0 base directories
     275     * @param string          $prefix The prefix
     276     * @param string[]|string $paths  The PSR-0 base directories
    275277     *
    276278     * @return void
     
    289291     * replacing any others previously set for this namespace.
    290292     *
    291      * @param string              $prefix The prefix/namespace, with trailing '\\'
    292      * @param list<string>|string $paths  The PSR-4 base directories
     293     * @param string          $prefix The prefix/namespace, with trailing '\\'
     294     * @param string[]|string $paths  The PSR-4 base directories
    293295     *
    294296     * @throws \InvalidArgumentException
     
    424426    {
    425427        if ($file = $this->findFile($class)) {
    426             $includeFile = self::$includeFile;
    427             $includeFile($file);
     428            includeFile($file);
    428429
    429430            return true;
     
    476477
    477478    /**
    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[]
    481482     */
    482483    public static function getRegisteredLoaders()
     
    555556        return false;
    556557    }
    557 
    558     /**
    559      * @return void
    560      */
    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 $file
    573          * @return void
    574          */
    575         self::$includeFile = \Closure::bind(static function($file) {
    576             include $file;
    577         }, null, null);
    578     }
    579558}
     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 */
     569function includeFile($file)
     570{
     571    include $file;
     572}
  • nextgen-gallery/trunk/vendor/composer/InstalledVersions.php

    r3003964 r3004370  
    9999        foreach (self::getInstalled() as $installed) {
    100100            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']);
    102102            }
    103103        }
     
    120120    public static function satisfies(VersionParser $parser, $packageName, $constraint)
    121121    {
    122         $constraint = $parser->parseConstraints((string) $constraint);
     122        $constraint = $parser->parseConstraints($constraint);
    123123        $provided = $parser->parseConstraints(self::getVersionRanges($packageName));
    124124
     
    329329                    $installed[] = self::$installedByVendor[$vendorDir];
    330330                } 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';
    334332                    if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
    335333                        self::$installed = $installed[count($installed) - 1];
     
    343341            // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937
    344342            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';
    348344            } else {
    349345                self::$installed = array();
    350346            }
    351347        }
    352 
    353         if (self::$installed !== array()) {
    354             $installed[] = self::$installed;
    355         }
     348        $installed[] = self::$installed;
    356349
    357350        return $installed;
  • nextgen-gallery/trunk/vendor/composer/autoload_real.php

    r3003964 r3004370  
    33// autoload_real.php @generated by Composer
    44
    5 class ComposerAutoloaderInit947270fe14b33b958df8910a24cbf812
     5class ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211
    66{
    77    private static $loader;
     
    2525        require __DIR__ . '/platform_check.php';
    2626
    27         spl_autoload_register(array('ComposerAutoloaderInit947270fe14b33b958df8910a24cbf812', 'loadClassLoader'), true, true);
     27        spl_autoload_register(array('ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211', 'loadClassLoader'), true, true);
    2828        self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
    29         spl_autoload_unregister(array('ComposerAutoloaderInit947270fe14b33b958df8910a24cbf812', 'loadClassLoader'));
     29        spl_autoload_unregister(array('ComposerAutoloaderInit865a398218c279eb1f33c4f1d4258211', 'loadClassLoader'));
    3030
    3131        require __DIR__ . '/autoload_static.php';
    32         call_user_func(\Composer\Autoload\ComposerStaticInit947270fe14b33b958df8910a24cbf812::getInitializer($loader));
     32        call_user_func(\Composer\Autoload\ComposerStaticInit865a398218c279eb1f33c4f1d4258211::getInitializer($loader));
    3333
    3434        $loader->register(true);
    3535
    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);
    4639        }
    4740
     
    4942    }
    5043}
     44
     45/**
     46 * @param string $fileIdentifier
     47 * @param string $file
     48 * @return void
     49 */
     50function 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  
    55namespace Composer\Autoload;
    66
    7 class ComposerStaticInit947270fe14b33b958df8910a24cbf812
     7class ComposerStaticInit865a398218c279eb1f33c4f1d4258211
    88{
    99    public static $files = array (
     
    2929    {
    3030        return \Closure::bind(function () use ($loader) {
    31             $loader->prefixesPsr0 = ComposerStaticInit947270fe14b33b958df8910a24cbf812::$prefixesPsr0;
    32             $loader->classMap = ComposerStaticInit947270fe14b33b958df8910a24cbf812::$classMap;
     31            $loader->prefixesPsr0 = ComposerStaticInit865a398218c279eb1f33c4f1d4258211::$prefixesPsr0;
     32            $loader->classMap = ComposerStaticInit865a398218c279eb1f33c4f1d4258211::$classMap;
    3333
    3434        }, null, ClassLoader::class);
  • nextgen-gallery/trunk/vendor/composer/installed.json

    r3003964 r3004370  
    8282            "time": "2023-11-10T13:42:01+00:00",
    8383            "type": "library",
    84             "installation-source": "source",
     84            "installation-source": "dist",
    8585            "autoload": {
    8686                "files": [
Note: See TracChangeset for help on using the changeset viewer.