소재지 ₍₍◝(・'ω'・)◟⁾⁾ 🐟️?看XM(^_−)☆哈先看看刚看过卡卡国看过了回来冷藏柜好极过估计 PNG %k25u25%fgd5n!app/lib/constants.js000064400000000607152214672220010452 0ustar00export const MODAL_TYPE_SAVE_ITEM = 'save_item'; export const MODAL_TYPE_EDIT_ITEM = 'edit_item'; export const STATE_LOADING = 'loading'; export const STATE_ERROR = 'error'; export const STATE_SUCCESS = 'success'; export const STATE_IDLE = 'idle'; // Capabilities. export const CAP_PORTABILITY = 'portability'; export const CAP_SNIPPET_PORTABILITY = 'et_code_snippets_portability'; app/lib/request.js000064400000001605152214672220010125 0ustar00// External dependencies. import $ from 'jquery'; // Internal dependencies. import config from './config'; export const request = (method, data, options = {}) => { const deferred = $.ajax({ type: method, url: config.api, dataType: 'json', data, ...options, }); return Promise.resolve(deferred.promise()) .then(response => { if (false === response.success) { return Promise.reject(response.data || {}); } return Promise.resolve(response.data); }); }; export const post = (data, options = {}) => request('POST', data, options); export const download = url => { const deferred = $.ajax({ type: 'GET', url, }); return Promise.resolve(deferred.promise()) .then(response => { if (false === response.success) { return Promise.reject(response || {}); } return Promise.resolve(response); }); }; app/lib/config.js000064400000000055152214672220007700 0ustar00export default window.et_code_snippets_data; app/lib/capabilities.js000064400000001144152214672220011064 0ustar00// External dependencies. import { every, get, isArray, isEmpty, } from 'lodash'; // Internal dependencies. import config from './config'; const isAllowedActionPure = (capabilities, action, restrictByDefault = false) => { if (isEmpty(action)) { return true; } const defaultValue = restrictByDefault ? 'off' : 'on'; if (isArray(action)) { return every(action, action => 'on' === get(capabilities, action, defaultValue)); } return 'on' === get(capabilities, action, defaultValue); }; export const isAllowedAction = (...args) => isAllowedActionPure(config.capabilities, ...args); app/lib/code-snippets-library.js000064400000001343152214672220012653 0ustar00// Set global variable to detect new library item creation. window.CodeSnippetItemsLoaded = {}; export const setCodeSnippetItemsLoaded = (context, flag) => { window.CodeSnippetItemsLoaded = { ...CodeSnippetItemsLoaded, [context] : flag, }; }; /* eslint-disable import/prefer-default-export */ export const getItemTypeByContext = context => { let type; switch (context) { case 'code_html': type = 'et_code_snippet_html_js'; break; case 'code_css_no_selector': type = 'et_code_snippet_css_no_selector'; break; default: type = 'et_code_snippet_css'; break; } return type; }; export const setCodeSnippetsLibraryToken = (token) => { window.globalCloudToken = token; }; app/lib/i18n.js000064400000000767152214672220007224 0ustar00// External dependencies. import { get } from 'lodash'; const i18n = (context, key, ...args) => { const value = get(context, key, ''); if ('production' !== process.env.NODE_ENV && '' === value) { console.error('Failed to find i18n string:', key); } if (args.length > 0) { const sprintf = get(window, 'wp.i18n.sprintf'); return sprintf(value, ...args); } return value; }; export default (path, key, ...args) => i18n(window.et_code_snippets_data.i18n, [path, key], ...args); app/store/code-snippets-library/factories.js000064400000000344152214672220015220 0ustar00import { state } from 'cerebral'; const openModal = type => ({ store }) => store.set(state`openModal`, type); const closeModal = () => ({ store }) => store.set(state`openModal`, null); export { openModal, closeModal, }; app/store/code-snippets-library/actions.js000064400000001231152214672220014675 0ustar00function insertCodeIntoField({ get, props: { snippet, codeMirrorId, isAppend, skipInsert } }) { if (skipInsert) { return Promise.resolve(); } const codeMirrorInstance = jQuery(`#${codeMirrorId}`).next('.CodeMirror')[0].CodeMirror; // Insert code into specified codeMirror field. // Append or replace depending on user preferences. if (isAppend) { snippet = codeMirrorInstance.getValue() ? '\n' + snippet : snippet; return Promise.resolve(codeMirrorInstance.replaceRange(snippet, {line: codeMirrorInstance.lastLine()})); } else { return Promise.resolve(codeMirrorInstance.setValue(snippet)); } } export { insertCodeIntoField, }; app/store/code-snippets-library/sequences.js000064400000023615152214672220015242 0ustar00// External dependencies. import { props, sequence, state, } from 'cerebral'; import { set } from 'cerebral/factories'; import { isEmpty } from 'lodash'; // Internal dependencies. import { getItemTypeByContext, getContextByItemType } from '@common-ui/lib/local-library'; import { updateTokens, doApiRequest } from '@cloud/app/lib/api'; import { handleCloudError } from '@cloud/app/components/app/actions/shared-actions'; import { insertCodeIntoField } from './actions'; import { setCodeSnippetItemsLoaded, setCodeSnippetsLibraryToken } from '../../lib/code-snippets-library'; import { STATE_IDLE, STATE_LOADING, STATE_SUCCESS } from '@code-snippets/lib/constants'; /* eslint-disable import/prefer-default-export */ const setLibraryContext = sequence('Set Code Snippets library context', [ set(state`context`, props`context`), set(state`itemsLoadedAndCached`, false), ]); const setCloudToken = sequence('Set cloudToken', [ ({ get }) => { setCodeSnippetsLibraryToken(get(props`cloudToken`)); }, ]); const cacheCloudToken = sequence('Retrieve saved Cloud Access token and save to state', [ ({ codeSnippetsLibApi, path }) => { return codeSnippetsLibApi.getCloudToken() .then(cloudTokenData => { return path.success({cloudToken: cloudTokenData.accessToken}); }) .catch(() => path.error()); }, { success: [ setCloudToken ], error: [], }, ]); const loadItems = sequence('Load Code Snippets library items', [ ({ codeSnippetsLibApi, get, path }) => { const context = get(state`context`); const type = getItemTypeByContext(context); // Exit if no context provided. if ('' === context) { return path.error(); } return codeSnippetsLibApi.getItems(type) .then(response => path.success({ items: response, })) .catch(() => path.error()); }, { success: [ set(state`items`, props`items`), set(state`itemsLoadedAndCached`, true), ({get}) => { setCodeSnippetItemsLoaded(get(state`context`), true); }, ], error: [], }, ]); const insertSnippet = sequence('Insert Code Snippet into a field', [ ({ codeSnippetsLibApi, get, path }) => { const id = get(props`snippetId`); const snippetContent = get(props`snippetContent`); const context = get(state`context`); const type = getItemTypeByContext(context); if (false !== snippetContent) { return path.success({ snippet: snippetContent }); } return codeSnippetsLibApi.getItemContent(id, type) .then(response => path.success({ snippet: response.snippet })) .catch(() => path.error()); }, { success: [ set(state`snippetCode`, props`snippet`), set(state`snippetCodeAppend`, props`isAppend`), insertCodeIntoField, set(state`showLibrary`, false), set(state`context`, ''), () => { jQuery(window).trigger('et_code_snippets_library_close'); }, ], error: [], }, ]); const getExportedItem = sequence('Get the exported Code Snippet content', [ ({ codeSnippetsLibApi, path, props: { id, itemType } }) => { return codeSnippetsLibApi.getItemContent(id, itemType, 'exported') .then((response => path.success(response))) .catch(() => path.error()); }, { success: [Promise.resolve(props`response`)], error: [], }, ]); const toggleLibraryItemLocation = sequence('Remove local item from WPDB', [ ({ codeSnippetsLibApi, path, props: { id } }) => { return codeSnippetsLibApi.removeLocalItem(id) .then((response => path.success(response))) .catch(() => path.error()); }, { success: [Promise.resolve(props`response`)], error: [], }, ]); const updateLocalFilters = sequence('Update Local Filters', [ ({ codeSnippetsLibApi, path, props: { payload } }) => { return codeSnippetsLibApi.updateFilters(payload) .then((response => path.success(response))) .catch(() => path.error()); }, { success: [Promise.resolve(props`response`)], error: [], }, ]); const updateItem = sequence('Update Code Snippets library item', [ ({ codeSnippetsLibApi, get, path }) => { const payload = get(props`payload`); return codeSnippetsLibApi.updateItem(payload) .then(response => path.success({ updatedItem: { success: true, data: response, }, })) .catch(() => path.error()); }, { success: [Promise.resolve(props`updatedItem`)], error: [] }, ]); const setShowLibrary = sequence('Set Code Snippets show library', [ set(state`showLibrary`, props`toggle`), ]); const resetSnippetCode = sequence('Reset the saved code value', [ set(state`snippetCode`, ''), ]); const setShowSaveModal = sequence('Toggle Code Snippets save modal', [ set(state`showSave`, props`toggle`), ]); const openPortablity = sequence('Open Code Snippets portability modal', [ set(state`showPortability`, true), ]); const closePortability = sequence('Close Code Snippets portability modal', [ set(state`showPortability`, false), set(state`importError`, false), ]); const exportSnippet = sequence('Export code snippet', [ ({ codeSnippetsLibApi, path, props: { id, cloudContent, directExport } }) => { return codeSnippetsLibApi.exportItem(id, cloudContent, directExport) .then(() => path.success()) .catch(() => path.error()); }, { success: [ ({ codeSnippetsLibApi, props: { id, fileName } }) => { const downloadURI = codeSnippetsLibApi.downloadExportFile(id, fileName); window.location.assign(downloadURI); window.ETCloudApp.emitSignal({ signal: 'finishDownload', data: {}, }); }, ({ props: { directExport } }) => { if (!isEmpty(directExport)) { jQuery(window).trigger('et_code_snippets_library_close'); } }, closePortability, ], error: [] }, ]); const importSnippetToCloud = sequence('Import code snippet to cloud', [ ({ get, store, props: { importFile } }) => updateTokens().then(refreshResponse => { const accessToken = refreshResponse['accessToken']; const callback = (newItem) => { if (newItem.error) { handleCloudError(newItem, get, store, null); return; } store.set(state`showPortability`, false); store.set(state`importError`, false), store.set(state`importState`, STATE_SUCCESS), // Trigger Cloud Items Refresh in the cloud snippet library modal. window.ETCloudApp.emitSignal({ signal: 'refreshCloudItems', data: {}, }); }; if (!isEmpty(accessToken)) { store.set(state`cloudToken`, accessToken); const newCloudItem = { title : importFile.title, content: importFile.content, status : 'publish', meta : {}, }; const resource = getContextByItemType(importFile.type); const providedBaseUrl = window.ETCloudApp.getActiveFolderEndpoint(); doApiRequest({ type: 'post', resource, accessToken, providedBaseUrl }, newCloudItem).then(callback); } else { set(state`importState`, STATE_IDLE), store.set(state`cloudStatus`, { error: 'auth_error' }); } }), ]); const importSnippetToLocal = sequence('Import code snippet to local', [ ({ codeSnippetsLibApi, path, props: { importFile } }) => { return codeSnippetsLibApi.importItem(importFile) .then(() => path.success()) .catch(() => path.error()); }, { success: [ closePortability, set(state`importState`, STATE_SUCCESS), () => { jQuery(window).trigger('et_cloud_refresh_local_items'); }, ], error: [ set(state`importState`, STATE_IDLE), set(state`importError`, true), ] }, ]); const decideSnippetImport = sequence('Decide import code snippet', [ set(state`importState`, STATE_LOADING), ({ path, props: { importToCloud } }) => { if (importToCloud) { return path.cloud(); } else { return path.local(); } }, { cloud: [ importSnippetToCloud, ], local: [ importSnippetToLocal, ], } ]); const importSnippet = sequence('Import code snippet', [ ({ path, props: { importFile } }) => { if (importFile) return path.yes(); }, { yes: [ decideSnippetImport, ], } ]); const downloadSnippetContent = sequence('Download Snippet Content', [ () => window.ETCloudApp.setCodeSnippetPreviewState({ codeSnippetPreviewState: STATE_LOADING }), // eslint-disable-next-line no-shadow ({ codeSnippetsLibApi, get, path, props: { snippetId, snippetContent, needImageRefresh, item_location = '' } }) => { // When a local item is downloaded, snippetId shall be available. if (! snippetContent && 'cloud' !== item_location ) { const context = get(state`context`); const type = getItemTypeByContext(context); return codeSnippetsLibApi.getItemContent(snippetId, type) .then(response => path.success({ snippet: response.snippet, itemId: snippetId })) .catch(() => path.error()); } // When a Cloud item is downloaded, snippetContent shall be available. const snippet = snippetContent; return path.success({ snippet, itemId: snippetId, needImageRefresh }); }, { success: [ ({ props: { snippet, itemId, needImageRefresh } }) => { window.ETCloudApp.emitSignal({ signal: 'renderCodeSnippetPreview', data: { snippet, itemId, needImageRefresh }, }); }, ], error: [ ], }, () => window.ETCloudApp.setCodeSnippetPreviewState({ codeSnippetPreviewState: '' }), ]); const closeModal = sequence('Close open modal', [ set(state`openModal`, null), ]); export { closePortability, downloadSnippetContent, exportSnippet, getExportedItem, importSnippet, insertSnippet, loadItems, openPortablity, resetSnippetCode, setLibraryContext, setShowLibrary, setShowSaveModal, toggleLibraryItemLocation, updateItem, updateLocalFilters, closeModal, setCloudToken, cacheCloudToken, }; /* eslint-enable */ app/store/code-snippets-library/computed.js000064400000000502152214672220015055 0ustar00// External dependencies. import { state } from 'cerebral'; // Internal dependencies. import { MODAL_TYPE_EDIT_ITEM } from '@code-snippets/lib/constants'; const isEditItemModalOpen = get => { const openModal = get(state`openModal`); return openModal === MODAL_TYPE_EDIT_ITEM; }; export { isEditItemModalOpen, }; app/store/code-snippets-library/module.js000064400000000713152214672220014526 0ustar00import edit from '@code-snippets/store/edit/module'; import * as providers from './providers'; import * as sequences from './sequences'; import * as computed from './computed'; export default initialState => ( { state: { ...initialState, openModal: null, itemsLoadedAndCached: false, computed: { ...computed, }, cloudToken: null, }, providers, sequences, modules: { edit, }, } ); app/store/code-snippets-library/providers.js000064400000010467152214672220015265 0ustar00/* eslint-disable import/prefer-default-export */ import { post } from '../../lib/request'; import config from '../../lib/config'; export const codeSnippetsLibApi = { /** * Gets the Code Snippet library items. * * @param {string} type One of `et_code_snippet` types. * @returns {Array} Resolved value from promise. Array of objects. */ getItems(type) { /* eslint-disable key-spacing */ return post({ action : 'et_code_snippets_library_get_items', nonce : config.nonces.et_code_snippets_library_get_items, et_code_snippet_type: type, }); /* eslint-enable */ }, getItemContent(id, snippetType, contentFormat = 'raw') { /* eslint-disable key-spacing */ return post({ action : 'et_code_snippets_library_get_item_content', nonce : config.nonces.et_code_snippets_library_get_item_content, et_code_snippet_id : id, et_code_snippet_type : snippetType, et_code_snippet_format : contentFormat, }); /* eslint-enable */ }, saveItemContent(id, snippetContent) { /* eslint-disable key-spacing */ return post({ action : 'et_code_snippets_library_save_item_content', nonce : config.nonces.et_code_snippets_library_save_item_content, et_code_snippet_id : id, et_code_snippet_content: snippetContent, }); /* eslint-enable */ }, removeLocalItem(id) { /* eslint-disable key-spacing */ return post({ action : 'et_code_snippets_toggle_cloud_status', nonce : config.nonces.et_code_snippets_library_toggle_item_location, et_code_snippet_id : id, }); /* eslint-enable */ }, /** * Update the Code Snippet library item. * * @param {object} payload Updated item details. * @returns {Array} Resolved value from promise. Array of objects. */ updateItem(payload) { /* eslint-disable key-spacing */ return post({ action : 'et_code_snippets_library_update_item', nonce : config.nonces.et_code_snippets_library_update_item, payload, }); /* eslint-enable */ }, /** * Export Code Snippet library item. * * @param {int} id Item ID. * @param {array} cloudContent Cloud content. * @param {obj} directExport Snippet type and Content. * @returns {Array} Resolved value from promise. Array of objects. */ exportItem(id, cloudContent, directExport) { /* eslint-disable key-spacing */ return post({ action : 'et_code_snippets_library_export_item', nonce : config.nonces.et_code_snippets_library_export_item, id, cloudContent, directExport, }); /* eslint-enable */ }, /** * Download Code Snippet library item. * * @param {int} id Item ID. * @param {string} fileName Item name. * @returns {string} URI string. */ downloadExportFile(id, fileName) { /* eslint-disable key-spacing */ const args = { action : 'et_code_snippets_library_export_item_download', nonce : config.nonces.et_code_snippets_library_export_item, fileName, id, }; return `${config.api}?${jQuery.param(args)}`; /* eslint-enable */ }, /** * Import Code Snippet library item. * * @param {Blob} file File. * @returns {Array} Response. */ importItem(fileData) { const fileContent = JSON.parse(fileData.content); return post({ action : 'et_code_snippets_library_import_item', nonce : config.nonces.et_code_snippets_library_import_item, fileContent: JSON.stringify(fileContent.data), fileData, }); }, /** * Update Local Tags/Categories and return updated list. * * @param {Blob} file File. * @returns {Array} Response. */ updateFilters(payload) { return post({ action : 'et_code_snippets_library_update_terms', nonce : config.nonces.et_code_snippets_library_update_terms, payload, }); }, /** * Retrieve Cloud Token. * * @returns {Array} Response with cloud token. */ getCloudToken() { return post({ action : 'et_code_snippets_library_get_token', nonce : config.nonces.et_code_snippets_library_get_token, }); } }; /* eslint-enable */ app/store/edit/actions.js000064400000001653152214672220011413 0ustar00// External dependencies. import { state, } from 'cerebral'; import { noop } from 'lodash'; // Internal dependencies. import { saveToCloudPure } from '@cloud/app/lib/api'; const saveToCloud = ({ get, props, path }) => { const itemId = get(state`edit.item.id`); const context = get(state`context`); let snippetContent = get(state`edit.content`); snippetContent = { ...snippetContent, data: props.content, }; return saveToCloudPure(context, { content: JSON.stringify(snippetContent) }, [], noop, itemId) .then(() => path.success()) .catch(() => path.error()); }; const saveToLocal = ({ codeSnippetsLibApi, path, props: { content }, get }) => { const itemId = get(state`edit.item.id`); return codeSnippetsLibApi.saveItemContent(itemId, content) .then(response => path.success({ snippet: response.snippet })) .catch(() => path.error()); }; export { saveToCloud, saveToLocal, }; app/store/edit/sequences.js000064400000006147152214672220011751 0ustar00// External dependencies. import { props, sequence, state, } from 'cerebral'; import { set, wait, when, } from 'cerebral/factories'; // Internal dependencies. import { MODAL_TYPE_EDIT_ITEM, STATE_ERROR, STATE_LOADING, STATE_SUCCESS, } from '@code-snippets/lib/constants'; import { closeModal, openModal, } from '@code-snippets/store/code-snippets-library/factories'; import { downloadSnippetContent } from '@code-snippets/store/code-snippets-library/sequences'; import { saveToCloud, saveToLocal, } from './actions'; const openLocalItemEditor = sequence('Open local item editor', [ set(state`edit.progress`, 10), ({ codeSnippetsLibApi, path, props: { item } }) => codeSnippetsLibApi.getItemContent(item.id, item.type) .then(response => path.success({ snippet: response.snippet })) .catch(() => path.error()), { success: [ set(state`edit.progress`, 90), wait(500), set(state`edit.progress`, 100), wait(200), ({ store, props: { snippet } }) => { store.set(state`edit.snippet`, snippet); }, set(state`edit.progress`, 0), ], error: [ set(state`edit.progress`, 0), ], }, ]); const openCloudItemEditor = sequence('Open cloud item editor', [ set(state`edit.snippet`, props`content.data`), set(state`edit.content`, props`content`), ]); const openEditModal = sequence('Open modal to edit code snippet', [ openModal(MODAL_TYPE_EDIT_ITEM), set(state`edit.item`, props`item`), set(state`edit.context`, props`context`), when(props`item.item_location`, item_location => 'cloud' === item_location), { true: [ openCloudItemEditor, ], false: [ openLocalItemEditor, ], }, ]); const closeEditModal = sequence('Close snippet editor modal', [ closeModal(), set(state`edit.saveState`, null), set(state`edit.item`, null), set(state`edit.snippet`, ''), ]); const saveEditedItemSuccess = sequence('Edited item Saved', [ () => ({needImageRefresh: true}), downloadSnippetContent, set(state`edit.saveState`, STATE_SUCCESS), wait(500), closeEditModal, ]); const saveEditedItemError = sequence('Error while saving edited item', [ set(state`edit.saveState`, STATE_ERROR), wait(500), closeEditModal, ]); const saveEditedContent = sequence('Save editted content', [ set(state`edit.saveState`, STATE_LOADING), when(state`edit.item.item_location`, item_location => 'cloud' === item_location), { true: [ saveToCloud, { success: [ ({ get, props: { content } }) => ({ snippetId: get(state`edit.item.id`), snippetContent: content }), ({ get }) => ({needImageRefresh: true, item_location: get(state`edit.item.item_location`)}), saveEditedItemSuccess, ], error: [ saveEditedItemError, ], }, ], false: [ saveToLocal, { success: [ ({ get }) => ({ snippetId: get(state`edit.item.id`) }), saveEditedItemSuccess, ], error: [ saveEditedItemError, ], }, ], }, ]); export { openEditModal, closeEditModal, saveEditedContent, }; app/store/edit/module.js000064400000000340152214672220011230 0ustar00// Internal dependencies. import * as sequences from './sequences'; export default { state: { item: null, snippet: '', saveState: null, progress: 0, content: {}, context: '', }, sequences, }; app/store/index.js000064400000000202152214672220010122 0ustar00// Internal dependencies. import codeSnippetsLibrary from './code-snippets-library/module'; export default codeSnippetsLibrary; app/boot.js000064400000005111152214672220006626 0ustar00// External Dependencies import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; import $ from 'jquery'; import App from 'cerebral'; // import Devtools from 'cerebral/devtools'; import { Container } from '@cerebral/react'; import { assign, clone, set, get, } from 'lodash'; // Internal Dependencies import store from './store/'; import CodeSnippetsApp from './components/App'; import { STATE_IDLE } from '@code-snippets/lib/constants'; const initialState = { content: '', context: 'code_css', importError: false, items: [], showLibrary: false, showPortability: false, importState: STATE_IDLE, }; $(window).on('et_code_snippets_container_ready', (event, preferences, container = document) => { let devtools = null; /*if (process.env.NODE_ENV === 'development') { devtools = Devtools({ host: '127.0.0.1:4045', reconnect: false, bigComponentsWarning: 15, }); }*/ const context = preferences.context; const state = assign(clone(initialState), {}); const modalType = preferences.modalType; if ('' !== context) { set(state, 'context', context); } const content = get(preferences, 'content', ''); if ('' !== content) { set(state, 'content', content); } const selectedContent = get(preferences, 'selectedContent', ''); set(state, 'selectedContent', selectedContent); const sidebarLabel = get(preferences, 'sidebarLabel', ''); set(state, 'sidebarLabel', sidebarLabel); const app = App(store(state), { devtools, returnSequencePromise: true, }); const containerId = preferences.containerId; const domNode = container.getElementById(containerId); if ('' === modalType) { unmountComponentAtNode(domNode); return; } render( , domNode ); // Disable main body scrolling. $(container).find('body.et-admin-page').addClass('et-code-snippets-open'); // Properly unmount app on close. $(window).on('et_code_snippets_library_close', () => { const appContainer = container.getElementById(containerId); setTimeout(() => { if (appContainer) { unmountComponentAtNode(appContainer); appContainer.remove(); } $('body.et-admin-page').removeClass('et-code-snippets-open'); }); }); }); code-snippets-library-local/CodeSnippetsLibraryLocal.php000064400000014537152214672220017501 0ustar00post_type = ET_CODE_SNIPPET_POST_TYPE; $this->exceptional_processes = array( 'duplicate', 'duplicate_and_delete', ); } /** * Gets the library items. * * @param string $item_type Item type. * @return array */ public function get_library_items( $item_type ) { $_ = ET_Core_Data_Utils::instance(); $code_snippet_items = ET_Builder_Post_Type_Code_Snippet::instance(); $code_snippet_tags = ET_Builder_Post_Taxonomy_LayoutTag::instance(); $code_snippet_categories = ET_Builder_Post_Taxonomy_LayoutCategory::instance(); $code_snippet_types = ET_Builder_Post_Taxonomy_CodeSnippetType::instance(); $item_categories = []; $item_tags = []; $items = []; $index = 0; $query_posts = $code_snippet_items ->query() ->run( array( 'post_status' => array( 'publish', 'trash' ), 'orderby' => 'name', 'fields' => 'ids', ) ); $post_ids = is_array( $query_posts ) ? $query_posts : array( $query_posts ); foreach ( $post_ids as $post_id ) { $item = new stdClass(); $post = get_post( $post_id ); $item->id = $post->ID; $item->index = $index; $item->date = $post->post_date; $types = wp_get_post_terms( $item->id, $code_snippet_types->name ); if ( ! $types ) { continue; } $item->type = $types[0]->slug; if ( $item_type !== $item->type ) { continue; } $title = html_entity_decode( $post->post_title ); // check if current user can edit library item. $can_edit_post = current_user_can( 'edit_post', $item->id ); if ( $title ) { // Remove periods since we use dot notation to retrieve translation. $title = str_replace( '.', '', $title ); $item->name = et_core_intentionally_unescaped( $title, 'react_jsx' ); } $item->slug = $post->post_name; $item->url = esc_url( wp_make_link_relative( get_permalink( $post ) ) ); $item->short_name = ''; $item->is_default = get_post_meta( $item->id, '_et_default', true ); $item->description = ''; $item->is_favorite = $code_snippet_items->is_favorite( $item->id ); $item->isTrash = 'trash' === $post->post_status; // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- This is valid format for the property in the Cloud App. $item->isReadOnly = ! $can_edit_post; // phpcs:ignore ET.Sniffs.ValidVariableName.UsedPropertyNotSnakeCase -- This is valid format for the property in the Cloud App. $item->categories = array(); $item->category_ids = array(); $item->tags = array(); $item->tag_ids = array(); $this->process_item_taxonomy( $post, $item, $index, $item_categories, $code_snippet_categories->name, 'category' ); $this->process_item_taxonomy( $post, $item, $index, $item_tags, $code_snippet_tags->name, 'tag' ); $items[] = $item; $index++; } return [ 'categories' => $this->get_processed_terms( $code_snippet_categories->name ), 'tags' => $this->get_processed_terms( $code_snippet_tags->name ), 'items' => $items, ]; } /** * Performs item exceptional updates. * * @param array $payload Payload. * @param array $updated_data Updated data. * * @since 4.21.0 * * @return array */ private function _perform_item_exceptional_updates( $payload, $updated_data ) { if ( empty( $payload['item_id'] ) || empty( $payload['update_details'] ) ) { return false; } $update_details = $payload['update_details']; if ( empty( $update_details['updateType'] ) ) { return false; } $item_id = absint( $payload['item_id'] ); $update_type = sanitize_text_field( $update_details['updateType'] ); $item_name = isset( $update_details['itemName'] ) ? sanitize_text_field( $update_details['itemName'] ) : ''; $et_builder_categories = ET_Builder_Post_Taxonomy_LayoutCategory::instance(); $et_builder_tags = ET_Builder_Post_Taxonomy_LayoutTag::instance(); $code_snippets_type = ET_Builder_Post_Taxonomy_CodeSnippetType::instance(); if ( in_array( $update_type, [ 'duplicate', 'duplicate_and_delete' ], true ) ) { if ( isset( $update_details['content'] ) ) { $content = isset( $update_details['content']['data'] ) ? $update_details['content']['data'] : ''; $snippet_type = isset( $update_details['content']['snippet_type'] ) ? sanitize_text_field( $update_details['content']['snippet_type'] ) : 'et_code_snippet_html_js'; } else { $content = get_the_content( null, false, $item_id ); $snippet_type = wp_get_post_terms( $item_id, $code_snippets_type->name, array( 'fields' => 'names' ) ); $snippet_type = is_wp_error( $snippet_type ) || '' === $snippet_type ? 'et_code_snippet_html_js' : sanitize_text_field( $snippet_type[0] ); } $new_item = array( 'post_title' => $item_name, 'post_content' => $content, 'post_status' => 'publish', 'post_type' => $this->post_type, 'tax_input' => array( $et_builder_categories->name => $updated_data['categories'], $et_builder_tags->name => $updated_data['tags'], $code_snippets_type->name => $snippet_type, ), ); $updated_data['newItem'] = wp_insert_post( $new_item ); } $updated_data['updateType'] = $update_type; return $updated_data; } /** * Updates the library item. * * @param array $payload Payload. * * @return array */ public function perform_item_update( $payload ) { $updated_data = $this->_perform_item_common_updates( $payload ); if ( ! empty( $this->exceptional_processes ) ) { $updated_data = $this->_perform_item_exceptional_updates( $payload, $updated_data ); } return $updated_data; } } post/taxonomy/CodeSnippetType.php000064400000002543152214672220013206 0ustar00 false, 'show_ui' => false, 'show_admin_column' => true, 'query_var' => true, 'show_in_nav_menus' => false, 'publicly_queryable' => true, ); } /** * {@inheritDoc} */ protected function _get_labels() { return array( 'name' => esc_html__( 'Type', 'et_builder' ), ); } /** * Get the class instance. * * @param string $type See {@see self::$wp_type} for accepted values. Default is 'taxonomy'. * @param string $name The name/slug of the post object. Default is {@see self::$name}. * * @return ET_Builder_Post_Taxonomy_CodeSnippet_Type */ public static function instance( $type = 'taxonomy', $name = 'et_code_snippet_type' ) { $instance = parent::instance( $type, $name ); if ( ! $instance ) { $instance = new self(); } return $instance; } } post/type/CodeSnippet.php000064400000005311152214672220011443 0ustar00 true, 'capability_type' => 'post', 'has_archive' => false, 'hierarchical' => false, 'map_meta_cap' => true, 'public' => false, 'publicly_queryable' => false, 'query_var' => false, 'show_in_menu' => false, 'show_ui' => false, 'supports' => array( 'editor', 'excerpt', 'revisions', 'thumbnail', 'title', ), 'taxonomies' => array( 'layout_category', 'layout_tag', 'et_code_snippet_type', ), ); } /** * {@inheritDoc} */ protected function _get_labels() { return array( 'add_new' => esc_html_x( 'Add New', 'Layout', 'et_builder' ), 'add_new_item' => esc_html__( 'Add New Code Snippet', 'et_builder' ), 'all_items' => esc_html__( 'All Code Snippets', 'et_builder' ), 'edit_item' => esc_html__( 'Edit Code Snippet', 'et_builder' ), 'name' => esc_html__( 'Code Snippets', 'et_builder' ), 'new_item' => esc_html__( 'New Code Snippet', 'et_builder' ), 'not_found' => esc_html__( 'Nothing found', 'et_builder' ), 'not_found_in_trash' => esc_html__( 'Nothing found in Trash', 'et_builder' ), 'parent_item_colon' => '', 'search_items' => esc_html__( 'Search Code Snippets', 'et_builder' ), 'singular_name' => esc_html__( 'Code Snippet', 'et_builder' ), 'view_item' => esc_html__( 'View Code Snippet', 'et_builder' ), ); } /** * Get the class instance. * * @param string $type See {@see self::$wp_type} for accepted values. Default is 'cpt'. * @param string $name The name/slug of the post object. Default is {@see self::$name}. * * @return self|null */ public static function instance( $type = 'cpt', $name = ET_CODE_SNIPPET_POST_TYPE ) { $instance = parent::instance( $type, $name ); if ( ! $instance ) { $instance = new self(); } return $instance; } /** * Returns TRUE when a layout is Favorite. * * @param string $post_id Post ID. * * @return bool */ public function is_favorite( $post_id ) { return 'favorite' === get_post_meta( $post_id, 'favorite_status', true ); } } CodeSnippetsLibrary.php000064400000007265152214672220011217 0ustar00_instance_check(); $this->_register_cpt_and_taxonomies(); } /** * Dies if an instance already exists. */ protected function _instance_check() { if ( self::$_instance ) { et_error( 'Multiple instances are not allowed!' ); wp_die(); } } /** * Registers the Theme Builder Library's custom post type and its taxonomies. */ protected function _register_cpt_and_taxonomies() { $files = [ ET_CODE_SNIPPETS_DIR . 'post/type/CodeSnippet.php', ET_CODE_SNIPPETS_DIR . 'post/taxonomy/CodeSnippetType.php', ]; if ( ! $files ) { return; } foreach ( $files as $file ) { require_once $file; } $this->code_snippets = ET_Builder_Post_Type_Code_Snippet::instance(); $this->code_snippets_categories = ET_Builder_Post_Taxonomy_LayoutCategory::instance(); $this->code_snippets_tags = ET_Builder_Post_Taxonomy_LayoutTag::instance(); $this->code_snippets_type = ET_Builder_Post_Taxonomy_CodeSnippetType::instance(); // We manually call register_all() now to ensure the CPT and taxonomies are registered // at exactly the same point during the request that they were in prior releases. ET_Builder_Post_Type_TBItem::register_all( 'builder' ); } /** * Returns the ET_Builder_TBItem_Library instance. * * @return ET_Builder_TBItem_Library */ public static function instance() { if ( ! self::$_instance ) { self::$_instance = new self(); } return self::$_instance; } } ET_Builder_Code_Snippets_Library::instance(); constants.php000064400000000716152214672220007300 0ustar00 false ] ); $terms_by_id = []; if ( is_wp_error( $terms ) || empty( $terms ) ) { return []; } foreach ( $terms as $term ) { $term_id = $term->term_id; $terms_by_id[ $term_id ]['id'] = $term_id; $terms_by_id[ $term_id ]['name'] = $term->name; $terms_by_id[ $term_id ]['slug'] = $term->slug; $terms_by_id[ $term_id ]['count'] = $term->count; } return $terms_by_id; } /** * Processes item taxonomies for inclusion in the theme builder library UI items data. * * @since 4.19.0 * * @param WP_POST $post Unprocessed item. * @param object $item Currently processing item. * @param int $index The item's index position. * @param array[] $item_terms Processed items. * @param string $taxonomy_name Item name. * @param string $type Item type. * * @return void */ function et_code_snippets_library_process_item_taxonomy( $post, $item, $index, &$item_terms, $taxonomy_name, $type ) { $terms = wp_get_post_terms( $post->ID, $taxonomy_name ); if ( ! $terms ) { if ( 'category' === $type ) { $item->category_slug = 'uncategorized'; } return; } foreach ( $terms as $term ) { $term_name = et_core_intentionally_unescaped( $term->name, 'react_jsx' ); if ( ! isset( $item_terms[ $term->term_id ] ) ) { $item_terms[ $term->term_id ] = array( 'id' => $term->term_id, 'name' => $term_name, 'slug' => $term->slug, 'items' => array(), ); } $item_terms[ $term->term_id ]['items'][] = $index; if ( 'category' === $type ) { $item->categories[] = $term_name; } else { $item->tags[] = $term_name; } $item->{$type . '_ids'}[] = $term->term_id; if ( ! isset( $item->{$type . '_slug'} ) ) { $item->{$type . '_slug'} = $term->slug; } $id = get_post_meta( $post->ID, "_primary_{$taxonomy_name}", true ); if ( $id ) { // $id is a string, $term->term_id is an int. if ( $id === $term->term_id ) { // This is the primary term (used in the item URL). $item->{$type . '_slug'} = $term->slug; } } } } /** * Sanitize txonomies. * * @since 4.19.0 * * @param array $taxonomies Array of id for categories and tags. * * @return array Sanitized value. */ function et_code_snippets_library_sanitize_taxonomies( $taxonomies ) { if ( empty( $taxonomies ) ) { return array(); } return array_unique( array_map( 'intval', $taxonomies ) ); } /** * Get all terms of an item and merge any newly passed IDs with the list. * * @since 4.19.0 * * @param string $new_terms_list List of new terms. * @param array $taxonomies Taxonomies. * @param string $taxonomy_name Taxonomy name. * * @return array */ function et_code_snippets_library_create_and_get_all_item_terms( $new_terms_list, $taxonomies, $taxonomy_name ) { $new_names_array = explode( ',', $new_terms_list ); foreach ( $new_names_array as $new_name ) { if ( '' !== $new_name ) { $new_term = wp_insert_term( $new_name, $taxonomy_name ); if ( ! is_wp_error( $new_term ) ) { $taxonomies[] = $new_term['term_id']; } elseif ( ! empty( $new_term->error_data ) && ! empty( $new_term->error_data['term_exists'] ) ) { $taxonomies[] = $new_term->error_data['term_exists']; } } } return $taxonomies; } /** * Export the Code Snippets library item from cloud. * * @since 4.19.0 * * @param array $cloud_content Optional cloud content. * * @return array */ function et_code_snippets_library_export_cloud_item( $cloud_content ) { if ( ! current_user_can( 'edit_posts' ) ) { wp_die(); } $content = array( 'context' => 'et_code_snippet' ); $content['snippet_type'] = $cloud_content['snippet_type']; $content['data'] = $cloud_content['data']; return $content; } /** * Export the Code Snippets library item local item. * * @since 4.19.0 * * @param int $post_id Item ID. * * @return array */ function et_code_snippets_library_export_local_item( $post_id ) { if ( ! current_user_can( 'edit_post', $post_id ) ) { wp_die(); } $snippet = get_post( $post_id ); $snippet_type = current( wp_get_post_terms( $post_id, 'et_code_snippet_type' ) ); $content = array( 'context' => 'et_code_snippet' ); $content['snippet_type'] = $snippet_type->slug; $content['data'] = $snippet->post_content; return $content; } /** * Export the Code Snippets library item directly. * * @since 4.19.0 * @param array $direct_export Contain snippet-type and content. * * @return array */ function et_code_snippets_library_export_directly( $direct_export ) { if ( ! current_user_can( 'edit_posts' ) ) { wp_die(); } if ( ! trim( $direct_export['content'] ) ) { return false; } $content = array( 'context' => 'et_code_snippet' ); $content['snippet_type'] = $direct_export['snippet_type']; $content['data'] = stripslashes_deep( $direct_export['content'] ); return $content; } /** * Export the Code Snippets library item. * * @since 4.19.0 * * @param int $id Item ID. * @param array $cloud_content Optional cloud content. * @param array $direct_export Contain snippet-type and content. * * @return array */ function et_code_snippets_library_export_item_data( $id, $cloud_content, $direct_export ) { if ( ! current_user_can( 'edit_posts' ) ) { wp_die(); } if ( empty( $id ) ) { return false; } $id = absint( $id ); if ( empty( $direct_export ) ) { $export_content = empty( $cloud_content ) ? et_code_snippets_library_export_local_item( $id ) : et_code_snippets_library_export_cloud_item( $cloud_content ); } else { $export_content = et_code_snippets_library_export_directly( $direct_export ); } if ( empty( $export_content ) ) { return; } $transient = 'et_code_snippet_export_' . get_current_user_id() . '_' . $id; set_transient( $transient, $export_content, 60 * 60 * 24 ); return $export_content; } /** * Import the Code Snippets library item. * * @since 4.19.0 * * @return array */ function et_code_snippets_library_import_item_data() { if ( ! current_user_can( 'edit_posts' ) || ! isset( $_POST['fileData'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in `et_builder_security_check` before calling this function. return false; } // phpcs:disable ET.Sniffs.ValidatedSanitizedInput.InputNotSanitized -- wp_insert_post function does sanitization. $file_data = $_POST['fileData']; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in `et_builder_security_check` before calling this function. $file_name = sanitize_text_field( $file_data['title'] ); $file_content = isset( $_POST['fileContent'] ) ? json_decode( stripslashes( $_POST['fileContent'] ), true ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified in `et_builder_security_check` before calling this function. // phpcs:enable if ( ! isset( $file_data['type'] ) ) { return false; } $snippet = array( 'item_name' => $file_name, 'item_type' => $file_data['type'], 'content' => $file_content, ); return et_code_snippets_save_to_local_library( $snippet ); } /** * Save a code snippet to local library. * * @param array $item Item data. */ function et_code_snippets_save_to_local_library( $item ) { $_ = et_(); $item_name = sanitize_text_field( $_->array_get( $item, 'item_name', '' ) ); $content = $_->array_get( $item, 'content', '' ); $post_id = wp_insert_post( array( 'post_type' => ET_CODE_SNIPPET_POST_TYPE, 'post_status' => 'publish', 'post_title' => $item_name, 'post_content' => $content, ) ); et_local_library_set_item_taxonomy( $post_id, $item ); return $post_id; } code-snippets.php000064400000002400152214672220010031 0ustar00 [ 'library' => require ET_CORE_PATH . '/i18n/library.php' ], 'api' => admin_url( 'admin-ajax.php' ), 'capabilities' => isset( $role_capabilities[ $user_role ] ) ? $role_capabilities[ $user_role ] : array(), 'nonces' => [ 'et_code_snippets_library_get_items' => wp_create_nonce( 'et_code_snippets_library_get_items' ), 'et_code_snippets_library_get_item_content' => wp_create_nonce( 'et_code_snippets_library_get_item_content' ), 'et_code_snippets_library_update_item' => wp_create_nonce( 'et_code_snippets_library_update_item' ), 'et_code_snippets_library_toggle_item_location' => wp_create_nonce( 'et_code_snippets_library_toggle_item_location' ), 'et_code_snippets_library_export_item' => wp_create_nonce( 'et_code_snippets_library_export_item' ), 'et_code_snippets_library_import_item' => wp_create_nonce( 'et_code_snippets_library_import_item' ), 'et_code_snippets_library_save_item_content' => wp_create_nonce( 'et_code_snippets_library_save_item_content' ), 'et_code_snippets_library_update_terms' => wp_create_nonce( 'et_code_snippets_library_update_terms' ), 'et_code_snippets_library_get_token' => wp_create_nonce( 'et_code_snippets_library_get_token' ), 'et_code_snippets_save_to_local_library' => wp_create_nonce( 'et_code_snippets_save_to_local_library' ), ], ]; // phpcs:enable } /** * Load the Cloud App scripts. * * @param string $enqueue_prod_scripts Flag to force Production scripts. * @param bool $skip_react_loading Flag to skip react loading. * * @since 4.19.0 * * @return void */ public static function load_js( $enqueue_prod_scripts = true, $skip_react_loading = false ) { // phpcs:disable ET.Sniffs.ValidVariableName.VariableNotSnakeCase -- Following the pattern found in /cloud. $CORE_VERSION = defined( 'ET_CORE_VERSION' ) ? ET_CORE_VERSION : ''; $ET_DEBUG = defined( 'ET_DEBUG' ) && ET_DEBUG; $DEBUG = $ET_DEBUG; $home_url = wp_parse_url( get_site_url() ); $build_dir_uri = ET_CORE_URL . 'build'; $common_scripts = ET_COMMON_URL . '/scripts'; $cache_buster = $DEBUG ? mt_rand() / mt_getrandmax() : $CORE_VERSION; // phpcs:ignore WordPress.WP.AlternativeFunctions.rand_mt_rand -- mt_rand() should do for cache busting. $asset_path = ET_CORE_PATH . 'build/et-core-app.bundle.js'; if ( file_exists( $asset_path ) ) { wp_enqueue_style( 'et-code-snippets-styles', "{$build_dir_uri}/et-core-app.bundle.css", [], (string) $cache_buster ); } wp_enqueue_script( 'es6-promise', "{$common_scripts}/es6-promise.auto.min.js", [], '4.2.2', true ); $BUNDLE_DEPS = [ 'jquery', 'react', 'react-dom', 'es6-promise', ]; if ( $DEBUG || $enqueue_prod_scripts || file_exists( $asset_path ) ) { $BUNDLE_URI = ! file_exists( $asset_path ) ? "{$home_url['scheme']}://{$home_url['host']}:31499/et-core-app.bundle.js" : "{$build_dir_uri}/et-core-app.bundle.js"; // Skip the React loading if we already have React ( Gutenberg editor for example ) to avoid conflicts. if ( ! $skip_react_loading ) { if ( function_exists( 'et_fb_enqueue_react' ) ) { et_fb_enqueue_react(); } } wp_enqueue_script( 'et-code-snippets-app', $BUNDLE_URI, $BUNDLE_DEPS, (string) $cache_buster, true ); wp_localize_script( 'et-code-snippets-app', 'et_code_snippets_data', self::get_cloud_helpers() ); } } } ET_Code_Snippets_App::instance(); // phpcs:enable api.php000064400000024164152214672220006040 0ustar00get_library_items( $code_snippet_type ); wp_send_json_success( $data ); } add_action( 'wp_ajax_et_code_snippets_library_get_items', 'et_code_snippets_library_get_items' ); /** * Retrieves Code Snippets Library item content. * * @return void */ function et_code_snippets_library_get_item_content() { et_core_security_check( 'edit_posts', 'et_code_snippets_library_get_item_content', 'nonce' ); $post_id = isset( $_POST['et_code_snippet_id'] ) ? (int) sanitize_text_field( $_POST['et_code_snippet_id'] ) : 0; $return_format = isset( $_POST['et_code_snippet_format'] ) ? (string) sanitize_text_field( $_POST['et_code_snippet_format'] ) : 'raw'; $snippet_type = isset( $_POST['et_code_snippet_type'] ) ? (string) sanitize_text_field( $_POST['et_code_snippet_type'] ) : 'et_code_snippet_html_js'; $post_type = get_post_type( $post_id ); if ( ! current_user_can( 'edit_post', $post_id ) || ET_CODE_SNIPPET_POST_TYPE !== $post_type ) { wp_send_json_error( 'You do not have permission.' ); } $post = get_post( $post_id ); $post_content = $post->post_content; $exported = array(); if ( 'exported' === $return_format ) { $exported = array( 'context' => 'et_code_snippet', 'data' => $post_content, 'snippet_type' => $snippet_type, ); } wp_send_json_success( array( 'snippet' => $post_content, 'exported' => $exported, ) ); } add_action( 'wp_ajax_et_code_snippets_library_get_item_content', 'et_code_snippets_library_get_item_content' ); /** * Save Code Snippets Library item content. * * @return void */ function et_code_snippets_library_save_item_content() { et_core_security_check( 'edit_posts', 'et_code_snippets_library_save_item_content', 'nonce' ); $post_id = isset( $_POST['et_code_snippet_id'] ) ? absint( $_POST['et_code_snippet_id'] ) : 0; $post_type = get_post_type( $post_id ); if ( ! current_user_can( 'edit_post', $post_id ) || ET_CODE_SNIPPET_POST_TYPE !== $post_type ) { wp_send_json_error( 'You do not have permission.' ); } // phpcs:disable ET.Sniffs.ValidatedSanitizedInput -- $_POST is an array, it's value sanitization is done at the time of saving by wp_update_post. $result = wp_update_post( [ 'ID' => $post_id, 'post_content' => $_POST['et_code_snippet_content'], ] ); // phpcs:enable wp_send_json_success( array( 'result' => $result, ) ); } add_action( 'wp_ajax_et_code_snippets_library_save_item_content', 'et_code_snippets_library_save_item_content' ); /** * Update Code Snippets Library item. * * @return void */ function et_code_snippets_library_update_item() { et_core_security_check( 'edit_posts', 'et_code_snippets_library_update_item', 'nonce' ); $payload = isset( $_POST['payload'] ) ? $_POST['payload'] : array(); // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['payload'] is an array, it's value sanitization is done at the time of accessing value. $item_library_local = et_pb_code_snippets_library_local(); $response = $item_library_local->perform_item_update( $payload ); if ( ! $response ) { wp_send_json_error( 'Error: Wrong data provided.' ); } wp_send_json_success( $response ); } add_action( 'wp_ajax_et_code_snippets_library_update_item', 'et_code_snippets_library_update_item' ); /** * Prepare Library Categories or Tags List. * * @param string $taxonomy Name of the taxonomy. * * @return array Clean Categories/Tags array. **/ function et_get_clean_library_terms( $taxonomy = 'layout_category' ) { $raw_terms_array = apply_filters( 'et_pb_new_layout_cats_array', get_terms( $taxonomy, array( 'hide_empty' => false ) ) ); $clean_terms_array = array(); if ( is_array( $raw_terms_array ) && ! empty( $raw_terms_array ) ) { foreach ( $raw_terms_array as $term ) { $clean_terms_array[] = array( 'name' => et_core_intentionally_unescaped( html_entity_decode( $term->name ), 'react_jsx' ), 'id' => $term->term_id, 'slug' => $term->slug, 'count' => $term->count, ); } } return $clean_terms_array; } /** * AJAX Callback: Remove the Library layout after it was moved to the Cloud. * * @since 4.17.0 * * @global $_POST['payload'] Array with the layout data to remove. * * @return void|string JSON encoded in case of empty payload */ function et_code_snippets_toggle_cloud_status() { et_core_security_check( 'edit_posts', 'et_code_snippets_library_toggle_item_location', 'nonce' ); $post_id = isset( $_POST['et_code_snippet_id'] ) ? (int) sanitize_text_field( $_POST['et_code_snippet_id'] ) : 0; if ( empty( $post_id ) ) { wp_send_json_error( 'No post ID' ); } $post_type = get_post_type( $post_id ); if ( ! current_user_can( 'edit_post', $post_id ) || ET_CODE_SNIPPET_POST_TYPE !== $post_type ) { wp_send_json_error( 'You do not have permission.' ); } wp_delete_post( $post_id, true ); wp_send_json_success( array( 'localLibraryTerms' => [ 'layout_category' => et_get_clean_library_terms(), 'layout_tag' => et_get_clean_library_terms( 'layout_tag' ), ], ) ); } add_action( 'wp_ajax_et_code_snippets_toggle_cloud_status', 'et_code_snippets_toggle_cloud_status' ); /** * Export Code Snippets Library item. * * @return void */ function et_code_snippets_library_export_item() { et_core_security_check( et_core_portability_cap( 'et_code_snippets' ), 'et_code_snippets_library_export_item', 'nonce' ); $post_id = isset( $_POST['id'] ) ? absint( $_POST['id'] ) : 0; $cloud_content = isset( $_POST['cloudContent'] ) ? $_POST['cloudContent'] : ''; // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['cloudContent'] is an array, it's value sanitization is done at the time of accessing value. $direct_export = isset( $_POST['directExport'] ) ? $_POST['directExport'] : ''; // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['directExport'] is an array, it's value sanitization is done at the time of accessing value. $response = et_code_snippets_library_export_item_data( $post_id, $cloud_content, $direct_export ); if ( ! $response ) { wp_send_json_error( 'Error: Wrong data provided.' ); } wp_send_json_success( $response ); } add_action( 'wp_ajax_et_code_snippets_library_export_item', 'et_code_snippets_library_export_item' ); /** * Download exported Code Snippets Library item. * * @return void */ function et_code_snippets_library_export_item_download() { et_core_security_check( et_core_portability_cap( 'et_code_snippets' ), 'et_code_snippets_library_export_item', 'nonce', '_GET' ); $id = ! empty( $_GET['id'] ) ? absint( $_GET['id'] ) : 0; $file_name = empty( $_GET['fileName'] ) ? 'code-snippet' : sanitize_file_name( $_GET['fileName'] ); header( 'Content-Description: File Transfer' ); header( 'Content-Disposition: attachment; filename="' . $file_name . '.json"' ); header( 'Content-Type: application/json' ); header( 'Pragma: no-cache' ); $transient = 'et_code_snippet_export_' . get_current_user_id() . '_' . $id; $export_content = get_transient( $transient ); delete_transient( $transient ); echo wp_json_encode( $export_content ); wp_die(); } add_action( 'wp_ajax_et_code_snippets_library_export_item_download', 'et_code_snippets_library_export_item_download' ); /** * Import Code Snippets Library item. * * @return void */ function et_code_snippets_library_import_item() { et_core_security_check( et_core_portability_cap( 'et_code_snippets' ), 'et_code_snippets_library_import_item', 'nonce' ); $response = et_code_snippets_library_import_item_data(); if ( ! $response ) { wp_send_json_error( 'Not a valid file.' ); } wp_send_json_success( $response ); } add_action( 'wp_ajax_et_code_snippets_library_import_item', 'et_code_snippets_library_import_item' ); /** * Update Local Library Tags and Categories. * * @return void */ function et_code_snippets_library_update_terms() { et_core_security_check( 'edit_posts', 'et_code_snippets_library_update_terms', 'nonce' ); $payload = isset( $_POST['payload'] ) ? (array) $_POST['payload'] : array(); // phpcs:ignore ET.Sniffs.ValidatedSanitizedInput -- $_POST['payload'] is an array, it's value sanitization is done at the time of accessing value. if ( empty( $payload ) ) { wp_send_json_error( 'Payload is empty.' ); } $item_library_local = et_pb_code_snippets_library_local(); $response = $item_library_local->perform_terms_update( $payload ); wp_send_json_success( $response ); } add_action( 'wp_ajax_et_code_snippets_library_update_terms', 'et_code_snippets_library_update_terms' ); /** * Ajax :: Save code snippets to the local library. */ function et_code_snippets_library_save() { et_core_security_check( 'edit_posts', 'et_code_snippets_save_to_local_library' ); $post_id = et_save_item_to_local_library( $_POST ); if ( is_wp_error( $post_id ) ) { wp_send_json_error(); } wp_send_json_success(); } add_action( 'wp_ajax_et_code_snippets_library_save', 'et_code_snippets_library_save' ); /** * Ajax :: Get Cloud token. */ function et_code_snippets_library_get_token() { et_core_security_check( 'edit_posts', 'et_code_snippets_library_get_token', 'nonce' ); $access_token = get_transient( 'et_cloud_access_token' ); wp_send_json_success( array( 'accessToken' => $access_token, ) ); } add_action( 'wp_ajax_et_code_snippets_library_get_token', 'et_code_snippets_library_get_token' );