File: //proc/thread-self/cwd/wp-content/plugins/cornerstone/includes/classes/Templating/Export.php
<?php
namespace Themeco\Cornerstone\Templating;
use DomainException;
use Themeco\Cornerstone\Services\GlobalColors;
use Themeco\Cornerstone\Services\GlobalFonts;
use Themeco\Cornerstone\Services\Components;
use Themeco\Cornerstone\Documents\DocumentCache;
use Themeco\Cornerstone\Util\Factory;
class Export {
public $options = [];
public $items = [];
public $images = [];
public $tasks = [];
public $docOrder = [];
public $cache = [];
public $posts = [];
public $dependencies = [];
public $organized = false;
public $salt;
public static $colors;
public static $fonts;
public static $attachment_ids;
public static $component_document_ids;
public $archiveZip;
public $globalColors;
public $globalFonts;
public $components;
public $documentCache;
public function __construct(DocumentCache $documentCache, GlobalColors $globalColors, GlobalFonts $globalFonts, Components $components) {
$this->globalColors = $globalColors;
$this->globalFonts = $globalFonts;
$this->components = $components;
$this->documentCache = $documentCache;
}
public function setOption($key, $value) {
$this->options[$key] = $value;
return $this;
}
public function getOption($key) {
return isset( $this->options[$key] ) ? $this->options[$key] : null;
}
public function isFullSite() {
return $this->getOption('fullSite') === true;
}
public function getColors() {
if ( ! isset( self::$colors) ) {
self::$colors = $this->globalColors->getStoredColorItems();
}
return self::$colors;
}
public function getFonts() {
if ( ! isset( self::$fonts) ) {
self::$fonts = $this->globalFonts->get_font_items();
}
return self::$fonts;
}
public function getAttachmentIds() {
if ( ! isset( self::$attachment_ids) ) {
global $wpdb;
$attachment_ids = $wpdb->get_results("SELECT ID FROM {$wpdb->prefix}posts WHERE post_type = \"attachment\"", ARRAY_N);
self::$attachment_ids = array_map(function($a) {
return (int) $a[0];
}, $attachment_ids);
}
return self::$attachment_ids;
}
public function getComponentDocumentIds() {
if ( ! isset( self::$component_document_ids) ) {
global $wpdb;
$component_document_ids = $wpdb->get_results("SELECT ID FROM {$wpdb->prefix}posts WHERE post_type = \"cs_global_block\"", ARRAY_N);
self::$component_document_ids = array_map(function($a) {
return (int) $a[0];
}, $component_document_ids);
}
return self::$component_document_ids;
}
public function hashSalt() {
if ( !isset( $this->salt ) ) {
$salt = '';
if ( is_multisite() ) {
$salt .= get_current_blog_id();
}
return apply_filters( 'cs_export_hash_salt', $salt );
}
return $this->salt;
}
public function hash($group, $input) {
return md5($this->hashSalt() . ':' . $group . ':' . $input);
}
public function add( $postId, $group = 'template', $hash = null ) {
if ( is_array( $postId ) ) {
foreach ( $postId as $id ) {
$this->add($id, $group);
}
return $this;
}
$id = "t$postId";
list($post, $dependencies) = $this->getCachedPost( $postId );
$firstTime = false;
if ( ! isset( $this->posts[ $id ] ) ) {
$firstTime = true;
$_hash = $hash ? $hash : $this->hash('doc', $postId);
$this->posts[$id] = [ 'type' => $group, 'key' => $_hash, 'data' => $post ];
}
$this->docOrder[] = $id;
foreach ($dependencies as $key => $value) {
if ($value[0] === 'component') {
$this->add($value[1], 'component', $key);
continue;
}
if ($value[0] === 'doc') {
$this->add($value[1], 'doc', $key);
continue;
}
if ($firstTime) {
$this->dependencies[$key] = $value;
}
}
return $this;
}
/**
* Add menus as task
*/
public function addMenus() {
$menus = wp_get_nav_menus();
foreach ($menus as $menu) {
$this->addMenu($menu);
}
}
/**
* Add single menu as menu task
*/
public function addMenu($menu) {
// Grab items from menu
$items = wp_get_nav_menu_items($menu);
$itemsFormatted = [];
$itemChildren = [];
foreach ($items as $item) {
// Get signature ID
// for use in import
$cachedID = $this->hash('sig', $item->object_id);
$postTitle = $item->post_title;
// Custom links already have a post tile
if (empty($postTitle)) {
$navPost = get_post($item->object_id);
$postTitle = $navPost->post_title;
}
// add item we use the update keys
// for easier importing
$navItem = [
'menu-item-title' => $postTitle,
'menu-item-object-id' => $cachedID,
'menu-item-object' => $item->object,
'menu-item-status' => 'publish',
'menu-item-type' => $item->type,
];
// Top level
if (empty($item->menu_item_parent)) {
$itemsFormatted[$item->ID] = $navItem;
} else {
// Item children setup
if (empty($itemChildren[$item->menu_item_parent])) {
$itemChildren[$item->menu_item_parent] = [ 'children' => [] ];
}
// @TODO this is not recursive
// we just needed to finish the Personify Project
// Child menu item
$itemChildren[$item->menu_item_parent]['children'][] = $navItem;
}
}
// Loop children and add to parents
// this is done later so the order of the top level
// is not affected
foreach ($itemChildren as $parentID => $group) {
if (empty($itemsFormatted[$parentID]['children'])) {
$itemsFormatted[$parentID]['children'] = [];
}
foreach ($group['children'] as $child) {
$itemsFormatted[$parentID]['children'][] = $child;
}
}
// Add task
$task = ['menu', [
'name' => $menu->name,
'items' => $itemsFormatted,
]];
$this->tasks[] = $task;
}
public function getCachedPost( $postId ) {
$id = "t$postId";
if ( ! isset( $this->cache[ $id ] ) ) {
list($template, $post, $isTemplate) = $this->getPost( $postId );
$this->cache[$id] = Factory::create(DependencyMapper::class)
->setup($this, $template, $post, $isTemplate)
->enumerate();
}
return $this->cache[ $id];
}
public function getPost( $postId ) {
$post = get_post($postId);
if ($post->post_type !== 'cs_template') {
add_filter( 'cs_is_template_export', '__return_true' );
$document = $this->documentCache->get( $postId );
$template = apply_filters( '_cs_supply_export_template', null, $document );
if (is_null( $template ) ) {
$template = Template::create( 'document', $document->getDocType(), true );
$data = $document->data();
$template->setMeta( [
'elements' => $data['elements'],
'settings' => $data['settings']
], false);
}
$template->setTitle( $document->title() );
remove_filter( 'cs_is_template_export', '__return_true' );
return [$template, $post, false];
}
$template = Template::locate($post);
$template->loadMeta();
return [$template, $post, true];
}
public function getDependantColorsOrFonts( $ids, $stored ) {
$fullSite = $this->isFullSite();
$used = [];
$groupMap = [];
$groups = [];
foreach ($stored as $color) {
if (isset($color['children'])) {
foreach ($color['children'] as $child ) {
$groupMap[$child] = $color['_id'];
$groups[$color['_id']] = $color['children'];
}
}
}
foreach ($stored as $color) {
if ( $fullSite || in_array( $color['_id'], $ids, true ) ) {
if ( isset( $groupMap[ $color['_id']] ) ) {
$group = $groupMap[ $color['_id']];
$used[] = $group;
$used = array_merge($used, $groups[$group]);
}
$used[] = $color['_id'];
}
}
$used = array_unique($used);
$result = [];
foreach ($stored as $color) {
if ( in_array( $color['_id'], $used, true ) ) {
$result[] = $color;
}
}
return $result;
}
public function parseDependencies() {
$font_ids = [];
$color_ids = [];
$images = [];
$options = [];
if ($this->isFullSite()) {
$options['customCSS'] = cornerstone('ThemeOptions')->get_global_css();
}
foreach ($this->dependencies as $key => $value) {
list ($type, $content) = $value;
if ($type === 'global-font') {
$font_ids[] = $content;
continue;
}
if ($type === 'global-color') {
$color_ids[] = $content;
continue;
}
if ($type === 'image-uri') {
$images[$key] = ['uri' => $content];
continue;
}
if ($type === 'image-attachment') {
$images[$key] = [ 'id' => $content[0], 'uri' => $content[1] ];
continue;
}
}
$colors = $this->getDependantColorsOrFonts( $color_ids, $this->getColors() );
if ( ! empty($colors) ) {
$options['colors'] = $colors;
}
$fonts = $this->getDependantColorsOrFonts( $font_ids, $this->getFonts() );
if ( ! empty($fonts) ) {
$options['fonts'] = $fonts;
}
if ( ! empty($options) ) {
$this->tasks[] = ['options', $options];
}
if (count($images) > 0) {
$this->tasks[] = ['images', $images];
}
}
public function addDocuments() {
// $this->docOrder includes all docs in the order they are requested.
// By reversing this, and only adding unique entries, we can ensure
// documents are created in the order they are needed.
// A document that depends on another will always be able to look that up by it's hash/key
$addedDocs = [];
$reversed = array_reverse($this->docOrder);
foreach ($reversed as $doc) {
if ( in_array( $doc, $addedDocs, true) ) {
continue;
}
$addedDocs[] = $doc;
$this->tasks[] = ['doc',$this->posts[$doc]];
}
}
public function includeTerms() {
$terms = [];
$addTerm = function($id, $key) use (&$terms, &$addTerm) {
$term = get_term($id);
$terms[$key] = [
'name' => $term->name,
'slug' => $term->slug,
'description' => $term->description,
'taxonomy' => $term->taxonomy
];
if ( $term->parent ) {
$addTerm($term->parent, $this->hash('term', $term->parent ));
}
};
foreach ($this->dependencies as $key => $value) {
list ($type, $content) = $value;
if ($type === 'term') {
$addTerm($content, $key);
}
}
return $terms;
}
public function organize() {
if ( $this->organized ) {
return $this;
}
$terms = $this->includeTerms();
$this->parseDependencies();
$this->addDocuments();
$this->tasks[] = ['terms', $terms];
// $this->tasks is a list of things to import
// Tasks must be imported in the order they are found to ensure dependencies are created first
$this->organized = true;
return $this;
}
public function archive() {
if ( ! class_exists( 'ZipArchive' ) ) {
return new \WP_Error( 'missing_zip_package', __( 'Export not supported please install php-zip.', 'cornerstone' ) );
}
$this->archiveZip = get_temp_dir() . 'cs-' . wp_generate_password( 12, false, false ) . '.zip';
$zip = new \ZipArchive();
if ( true !== $zip->open( $this->archiveZip, \ZipArchive::CREATE | \ZipArchive::OVERWRITE ) ) {
return new \WP_Error( 'unable_to_create_zip', __( 'Unable to open export file (archive) for writing.', 'cornerstone' ) );
}
$manifest = [];
foreach ($this->tasks as $task) {
list($type, $content) = $task;
if ($type === 'doc') {
$file = 'doc-' . $content['key'] . '.json';
$zip->addFromString( $file, json_encode($content['data']) );
$manifest[] = ['doc', [
'type' => $content['type'],
'strategy' => apply_filters('cs_export_doc_strategy', 'original', $content ),
'key' => $content['key'],
'file' => $file
] ];
} else if ($type === 'images') {
$images = [];
foreach ($content as $key => $value) {
$images[$key] = $this->addImage($zip, $key, $value);
}
$manifest[] = ['images', $images];
} else {
$manifest[] = $task;
}
}
$zip->addFromString( 'manifest.json', json_encode([ 'version' => 3, 'tasks' => $manifest ], JSON_PRETTY_PRINT) );
$zip->close();
return $this->archiveZip;
}
public function addImage($zip, $key, $value) {
$parts = explode('/', $value['uri']);
$original = array_pop($parts);
$fname = 'img-' . $key . '-' . $original;
if ( isset( $value['id'] ) ) {
$path = wp_get_original_image_path( $value['id'], true );
if ($path && $zip->addFile( $path, $fname)) {
// otherwise fall through and try downloading via URI
return ['id', $original ];
};
}
if ( isset( $value['uri'] ) ) {
require_once(ABSPATH . 'wp-admin/includes/media.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');
$tmpFile = \download_url( $value['uri'] );
if (!is_wp_error( $tmpFile)) {
if ( $zip->addFile( $tmpFile, $fname) ) {
return ['uri', $original ];
};
}
}
return ['no-import', $value['uri']];
}
public function debug() {
foreach($this->tasks as $item) {
list($type, $content) = $item;
if ($type !== 'options') {
var_dump($item);
}
}
}
}