diff --git a/classes/Visualizer/Module/Admin.php b/classes/Visualizer/Module/Admin.php index 7e3a508a..614f829f 100644 --- a/classes/Visualizer/Module/Admin.php +++ b/classes/Visualizer/Module/Admin.php @@ -1022,6 +1022,7 @@ public function renderLibraryPage() { } // enqueue charts array $ajaxurl = admin_url( 'admin-ajax.php' ); + wp_localize_script( 'visualizer-library', 'visualizer', diff --git a/classes/Visualizer/Plugin.php b/classes/Visualizer/Plugin.php index 49517b51..3f20628a 100644 --- a/classes/Visualizer/Plugin.php +++ b/classes/Visualizer/Plugin.php @@ -57,6 +57,8 @@ class Visualizer_Plugin { const ACTION_UPLOAD_DATA = 'visualizer-upload-data'; const ACTION_EXPORT_DATA = 'visualizer-export-data'; + const STORE_URL = 'https://store.themeisle.com/'; + /** *Action used for fetching specific users/roles for permissions. */ diff --git a/classes/Visualizer/Render/Library.php b/classes/Visualizer/Render/Library.php index 6263ef64..1c61c5cc 100644 --- a/classes/Visualizer/Render/Library.php +++ b/classes/Visualizer/Render/Library.php @@ -206,7 +206,55 @@ private function getDisplayForm() { '; } + /** + * Renders pro charts blocker. + * + * @access private + */ + private function _renderProPopupBlocker() { + if ( Visualizer_Module::is_pro() ) { + return; + } + $license = get_option( 'visualizer_pro_license_data', 'free' ); + $license_key = ''; + $download_id = ''; + if ( ! empty( $license ) && is_object( $license ) ) { + $license_key = $license->key; + $download_id = $license->download_id; + } + $admin_license_url = admin_url( 'options-general.php#visualizer_pro_license' ); + $renew_license_url = tsdk_utmify( Visualizer_Plugin::STORE_URL . '?edd_license_key=' . $license_key . '&download_id=' . $download_id, 'visualizer_license_block' ); + echo ' +
+
+

Alert!

+

' . esc_html__( 'In order to edit premium charts, benefit from updates and support for Visualizer Premium plugin, please renew your license code or activate it.', 'visualizer' ) . '

+
+ + + + + + + +
+
+ '; + } /** * Renders library content. * @@ -215,10 +263,14 @@ private function getDisplayForm() { * @access private */ private function _renderLibrary() { + // Added by Ash/Upwork $filterBy = ! empty( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended // Added by Ash/Upwork echo $this->custom_css; + + $this->_renderProPopupBlocker(); + echo '
'; echo ''; $this->getDisplayForm(); diff --git a/css/library.css b/css/library.css index 5fdd3c07..81017ca3 100644 --- a/css/library.css +++ b/css/library.css @@ -522,6 +522,7 @@ div#visualizer-types ul, div#visualizer-types form p { .vizualizer-renew-notice-overlay { + display: none; position: fixed; top: 0; left: 0; @@ -532,7 +533,7 @@ div#visualizer-types ul, div#visualizer-types form p { } .vizualizer-renew-notice-popup { - display: block; + display: none; position: fixed; top: 50%; left: 50%; @@ -594,8 +595,17 @@ div#visualizer-types ul, div#visualizer-types form p { .vizualizer-renew-notice-close-icon { position: absolute; - top: 10px; - right: 10px; + top: -10px; + right: -70px; cursor: pointer; color: #333; + background: none; + border: none; + padding: 0; + outline: none; + /* Reset button styles */ + display: inline-block; + font: inherit; + text-align: inherit; + text-decoration: none; } diff --git a/js/library.js b/js/library.js index 4718d915..d0efddd1 100644 --- a/js/library.js +++ b/js/library.js @@ -33,63 +33,13 @@ }); })(wp.media.view); -function createPopupProBlocker() { - - var link = document.createElement('link'); - link.rel = 'stylesheet'; - link.href = 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css'; - document.head.appendChild(link); - - var overlay = document.createElement('div'); - overlay.classList.add('vizualizer-renew-notice-overlay'); - overlay.id = 'overlay-visualizer'; - document.body.appendChild(overlay); - - var popup = document.createElement('div'); - popup.classList.add('vizualizer-renew-notice-popup'); - - var closeIcon = document.createElement('i'); - closeIcon.classList.add('fas', 'fa-times', 'vizualizer-renew-notice-close-icon'); - closeIcon.addEventListener('click', function() { - document.body.removeChild(overlay); - popup.style.display = 'none'; - }); - popup.appendChild(closeIcon); - - var heading = document.createElement('h1'); - heading.textContent = 'Alert!'; - heading.classList.add('vizualizer-renew-notice-heading'); - popup.appendChild(heading); - - var message = document.createElement('p'); - message.textContent = 'In order to edit premium charts, benefit from updates and support for Visualizer Premium plugin, please renew your license code or activate it.'; - message.classList.add('vizualizer-renew-notice-message'); - popup.appendChild(message); - - var buttonsContainer = document.createElement('div'); - buttonsContainer.classList.add('vizualizer-renew-notice-buttons-container'); - - var link1 = document.createElement('a'); - link1.href = 'https://store.themeisle.com/'; - link1.target = '_blank'; - var button1 = document.createElement('button'); - button1.innerHTML = ' Renew License'; - button1.classList.add('vizualizer-renew-notice-button', 'vizualizer-renew-notice-renew-button'); - link1.appendChild(button1); - buttonsContainer.appendChild(link1); - - var link2 = document.createElement('a'); - link2.href = '/wp-admin/options-general.php#visualizer_pro_license'; - var button2 = document.createElement('button'); - button2.innerHTML = ' Activate License'; - button2.classList.add('vizualizer-renew-notice-button', 'vizualizer-renew-notice-activate-button'); - link2.appendChild(button2); - buttonsContainer.appendChild(link2); - - popup.appendChild(buttonsContainer); - - document.body.appendChild(popup); - +function createPopupProBlocker( $ , e ) { + if ( ! visualizer.is_pro_user && e.target.classList.contains('viz-is-pro-chart') ) { + $("#overlay-visualizer").css("display", "block"); + $(".vizualizer-renew-notice-popup").css("display", "block"); + return true; + } + return false; } (function ($, vmv, vu) { @@ -135,12 +85,11 @@ function createPopupProBlocker() { $(this).parent('form').submit(); }); - $('.visualizer-chart-shortcode').click(function (e) { + $('.visualizer-chart-shortcode').click(function (event) { - if ( ! visualizer.is_pro_user && e.target.classList.contains('viz-is-pro-chart') ) { - createPopupProBlocker(); - e.preventDefault(); - e.stopPropagation(); + if ( createPopupProBlocker( $, event ) ) { + event.preventDefault(); + event.stopPropagation(); return; } @@ -149,12 +98,12 @@ function createPopupProBlocker() { if (window.getSelection && document.createRange) { selection = window.getSelection(); range = document.createRange(); - range.selectNodeContents(e.target); + range.selectNodeContents(event.target); selection.removeAllRanges(); selection.addRange(range); } else if (document.selection && document.body.createTextRange) { range = document.body.createTextRange(); - range.moveToElementText(e.target); + range.moveToElementText(event.target); range.select(); } }); @@ -195,8 +144,7 @@ function createPopupProBlocker() { $('.visualizer-chart-edit').click(function (event) { - if ( ! visualizer.is_pro_user && event.target.classList.contains('viz-is-pro-chart') ) { - createPopupProBlocker(); + if ( createPopupProBlocker( $, event ) ) { return; } @@ -215,16 +163,14 @@ function createPopupProBlocker() { return false; }); $(".visualizer-chart-clone").on("click", function ( event ) { - if ( ! visualizer.is_pro_user && event.target.classList.contains('viz-is-pro-chart') ) { - createPopupProBlocker(); + if ( createPopupProBlocker( $, event ) ) { event.preventDefault(); } }); $(".visualizer-chart-export").on("click", function (event) { - if ( ! visualizer.is_pro_user && event.target.classList.contains('viz-is-pro-chart') ) { - createPopupProBlocker(); + if ( createPopupProBlocker( $, event ) ) { return; } @@ -249,8 +195,7 @@ function createPopupProBlocker() { }); $(".visualizer-chart-image").on("click", function (event) { - if ( ! visualizer.is_pro_user && event.target.classList.contains('viz-is-pro-chart') ) { - createPopupProBlocker(); + if ( createPopupProBlocker( $, event ) ) { return; } $('body').trigger('visualizer:action:specificchart', {action: 'image', id: $(this).attr("data-chart"), data: null, dataObj: {name: $(this).attr("data-chart-title")}}); diff --git a/tests/e2e/specs/upsell.spec.js b/tests/e2e/specs/upsell.spec.js index 9e63ffb3..170b7ef7 100644 --- a/tests/e2e/specs/upsell.spec.js +++ b/tests/e2e/specs/upsell.spec.js @@ -9,99 +9,125 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); const { deleteAllCharts, getAssetFilePath, CHART_JS_LABELS, selectChartAdmin } = require('../utils/common'); test.describe( 'Upsell', () => { - test.beforeEach( async ( { admin, requestUtils, page } ) => { - await deleteAllCharts( requestUtils ); - await admin.visitAdminPage( 'admin.php?page=visualizer' ); - page.setDefaultTimeout( 5000 ); - } ); - - test( 'chart selection on admin', async ( { admin, page } ) => { - await admin.visitAdminPage( 'admin.php?page=visualizer&vaction=addnew' ); - await page.waitForURL( '**/admin.php?page=visualizer&vaction=addnew' ); - await page.waitForSelector('h1:text("Visualizer")'); - - expect( await page.frameLocator('iframe').locator('.pro-upsell').count() ).toBe( 11 ); - - const proUpsellElements = await page.frameLocator('iframe').locator('a.pro-upsell').all(); - - for (const element of proUpsellElements) { - const href = await element.getAttribute('href'); - const searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('charttypes'); - } - } ); - - test( 'chart settings on admin', async ( { admin, page } ) => { - await admin.visitAdminPage( 'admin.php?page=visualizer&vaction=addnew' ); - await page.waitForURL( '**/admin.php?page=visualizer&vaction=addnew' ); - await page.waitForSelector('h1:text("Visualizer")'); - await selectChartAdmin( page.frameLocator('iframe'), CHART_JS_LABELS.pie ); - - await expect( page.frameLocator('iframe').locator( '#viz-tabs' ) ).toBeVisible(); - - expect( await page.frameLocator('iframe').locator('#vz-chart-source .viz-group-title .dashicons-lock').count() ).toBe( 5 ); - - - const uploadFileUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_csv .only-pro-inner a'); - let href = await uploadFileUpsell.getAttribute('href'); - let searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('import-file'); - - const remoteImportUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_json .only-pro-inner a').first(); - href = await remoteImportUpsell.getAttribute('href'); - searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('import-url'); - - const otherChartUpsell = page.frameLocator('iframe').locator('#vz-chart-source .viz-import-from-other .only-pro-inner a'); - href = await otherChartUpsell.getAttribute('href'); - searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('import-chart'); - - const wpImportUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_query_wp .only-pro-inner a'); - href = await wpImportUpsell.getAttribute('href'); - searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('import-wp'); - await page.frameLocator('iframe').getByRole('heading', { name: /Import from WordPress/ }).click(); - await expect(page.frameLocator('iframe').locator('#vz-chart-source')).toContainText('Upgrade to PRO to activate this feature!'); - - const dbImportUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_query .only-pro-inner a'); - href = await dbImportUpsell.getAttribute('href'); - searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('db-query'); - - await page.frameLocator('iframe').getByRole('heading', { name: /Import from database/ }).click(); - await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade to Plus plan to activate this feature!'); - await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade Now'); - - await page.frameLocator('iframe').getByRole('link', { name: 'Settings' }).click(); - - const dataFilterConfigurationUpsell = page.frameLocator('iframe').locator('#vz-data-controls .only-pro-inner a'); - href = await dataFilterConfigurationUpsell.getAttribute('href'); - searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('data-filter-configuration'); - - const frontendActionsUpsell = page.frameLocator('iframe').locator('#vz-frontend-actions .only-pro-inner a'); - href = await frontendActionsUpsell.getAttribute('href'); - searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('frontend-actions'); - - const chartPermissionsUpsell = page.frameLocator('iframe').locator('#vz-permissions .only-pro-inner a'); - href = await chartPermissionsUpsell.getAttribute('href'); - searchParams = new URLSearchParams(href); - expect( searchParams.get('utm_campaign') ).toBe('chart-permissions'); - await page.frameLocator('iframe').getByRole('heading', { name: /Permissions/ }).click(); - await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade to Plus plan to activate this feature!'); - await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade Now'); - }); - - test( 'featured tab in Install Plugin (SDK)', async ( { admin, page } ) => { - await admin.visitAdminPage( 'plugin-install.php' ); - - // Those should be visible only when a PRO product is installed. - await expect( page.getByText('Image Optimization by Optimole') ).toBeHidden(); - await expect( page.locator('#the-list div').filter({ hasText: 'Otter Blocks' }).nth(1) ).toBeHidden(); - - await expect( page.getByLabel('Install Image Optimization by') ).toBeHidden(); - await expect( page.getByLabel('Install Otter Blocks') ).toBeHidden(); - }); + test.beforeEach( async ( { admin, requestUtils, page } ) => { + await deleteAllCharts( requestUtils ); + await admin.visitAdminPage( 'admin.php?page=visualizer' ); + page.setDefaultTimeout( 5000 ); + } ); + + test( 'chart selection on admin', async ( { admin, page } ) => { + await admin.visitAdminPage( 'admin.php?page=visualizer&vaction=addnew' ); + await page.waitForURL( '**/admin.php?page=visualizer&vaction=addnew' ); + await page.waitForSelector('h1:text("Visualizer")'); + + expect( await page.frameLocator('iframe').locator('.pro-upsell').count() ).toBe( 11 ); + + const proUpsellElements = await page.frameLocator('iframe').locator('a.pro-upsell').all(); + + for (const element of proUpsellElements) { + const href = await element.getAttribute('href'); + const searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('charttypes'); + } + } ); + + test( 'chart settings on admin', async ( { admin, page } ) => { + await admin.visitAdminPage( 'admin.php?page=visualizer&vaction=addnew' ); + await page.waitForURL( '**/admin.php?page=visualizer&vaction=addnew' ); + await page.waitForSelector('h1:text("Visualizer")'); + await selectChartAdmin( page.frameLocator('iframe'), CHART_JS_LABELS.pie ); + + await expect( page.frameLocator('iframe').locator( '#viz-tabs' ) ).toBeVisible(); + + expect( await page.frameLocator('iframe').locator('#vz-chart-source .viz-group-title .dashicons-lock').count() ).toBe( 5 ); + + + const uploadFileUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_csv .only-pro-inner a'); + let href = await uploadFileUpsell.getAttribute('href'); + let searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('import-file'); + + const remoteImportUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_json .only-pro-inner a').first(); + href = await remoteImportUpsell.getAttribute('href'); + searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('import-url'); + + const otherChartUpsell = page.frameLocator('iframe').locator('#vz-chart-source .viz-import-from-other .only-pro-inner a'); + href = await otherChartUpsell.getAttribute('href'); + searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('import-chart'); + + const wpImportUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_query_wp .only-pro-inner a'); + href = await wpImportUpsell.getAttribute('href'); + searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('import-wp'); + await page.frameLocator('iframe').getByRole('heading', { name: /Import from WordPress/ }).click(); + await expect(page.frameLocator('iframe').locator('#vz-chart-source')).toContainText('Upgrade to PRO to activate this feature!'); + + const dbImportUpsell = page.frameLocator('iframe').locator('#vz-chart-source .visualizer_source_query .only-pro-inner a'); + href = await dbImportUpsell.getAttribute('href'); + searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('db-query'); + + await page.frameLocator('iframe').getByRole('heading', { name: /Import from database/ }).click(); + await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade to Plus plan to activate this feature!'); + await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade Now'); + + await page.frameLocator('iframe').getByRole('link', { name: 'Settings' }).click(); + + const dataFilterConfigurationUpsell = page.frameLocator('iframe').locator('#vz-data-controls .only-pro-inner a'); + href = await dataFilterConfigurationUpsell.getAttribute('href'); + searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('data-filter-configuration'); + + const frontendActionsUpsell = page.frameLocator('iframe').locator('#vz-frontend-actions .only-pro-inner a'); + href = await frontendActionsUpsell.getAttribute('href'); + searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('frontend-actions'); + + const chartPermissionsUpsell = page.frameLocator('iframe').locator('#vz-permissions .only-pro-inner a'); + href = await chartPermissionsUpsell.getAttribute('href'); + searchParams = new URLSearchParams(href); + expect( searchParams.get('utm_campaign') ).toBe('chart-permissions'); + await page.frameLocator('iframe').getByRole('heading', { name: /Permissions/ }).click(); + await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade to Plus plan to activate this feature!'); + await expect(page.frameLocator('iframe').locator('#vz-db-wizard')).toContainText('Upgrade Now'); + }); + + test( 'featured tab in Install Plugin (SDK)', async ( { admin, page } ) => { + await admin.visitAdminPage( 'plugin-install.php' ); + + // Those should be visible only when a PRO product is installed. + await expect( page.getByText('Image Optimization by Optimole') ).toBeHidden(); + await expect( page.locator('#the-list div').filter({ hasText: 'Otter Blocks' }).nth(1) ).toBeHidden(); + + await expect( page.getByLabel('Install Image Optimization by') ).toBeHidden(); + await expect( page.getByLabel('Install Otter Blocks') ).toBeHidden(); + }); + + test( 'pro chart license lock', async ( { admin, page } ) => { + await admin.visitAdminPage('admin.php?page=visualizer'); + await page.waitForURL('**/admin.php?page=visualizer'); + + // Check if the popup HTML is present + const popupSelector = '.vizualizer-renew-notice-popup'; + const popup = await page.$(popupSelector); + expect(popup).not.toBeNull(); + + const heading = await page.$('h1.vizualizer-renew-notice-heading'); + expect(heading).not.toBeNull(); + + const message = await page.$('p.vizualizer-renew-notice-message'); + expect(message).not.toBeNull(); + + const renewButton = await page.$('button.vizualizer-renew-notice-renew-button'); + expect(renewButton).not.toBeNull(); + + const activateButton = await page.$('button.vizualizer-renew-notice-activate-button'); + expect(activateButton).not.toBeNull(); + + const closeButton = await page.$('button.vizualizer-renew-notice-close-icon'); + expect(closeButton).not.toBeNull(); + }); + } );