*/
function demos() {
$demos = array(
'build' => array(
'title' => __( 'Build – construction company', 'blockmason-core' ),
'description' => __( 'Adds sample services, projects, team members, testimonials, news posts, the About, Prices and Contact pages, a menu and the images they use. Your existing content is not changed.', 'blockmason-core' ),
'path' => DIR . 'demo/build/',
),
);
/**
* Filters the importable demos.
*
* Each demo needs a title, a description and the path of a folder with a
* content.php file and an images/ folder. Images missing from that folder
* are taken from the Build demo.
*
* @param array $demos Demos keyed by slug.
*/
return (array) apply_filters( 'blockmason_core_demos', $demos );
}
/**
* Folder of a demo, with a trailing slash, or an empty string.
*
* @param string $demo Demo slug.
* @return string
*/
function demo_dir( $demo ) {
$demos = demos();
$demo = sanitize_key( $demo );
return isset( $demos[ $demo ]['path'] ) ? trailingslashit( $demos[ $demo ]['path'] ) : '';
}
/**
* Adds the demo page under Appearance.
*/
function demo_admin_menu() {
add_theme_page(
__( 'Blockmason demo', 'blockmason-core' ),
__( 'Blockmason demo', 'blockmason-core' ),
'manage_options',
'blockmason-demo',
__NAMESPACE__ . '\demo_page'
);
}
/**
* Renders the demo page.
*/
function demo_page() {
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$state = get_option( DEMO_OPTION );
$result = isset( $_GET['blockmason-demo'] ) ? sanitize_key( wp_unslash( $_GET['blockmason-demo'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display only.
?>
array_values( get_post_types() ),
'post_status' => array_values( get_post_stati() ),
'posts_per_page' => -1,
'fields' => 'ids',
'meta_key' => '_blockmason_demo', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Admin only, run on demand.
)
);
return array_values( array_unique( array_map( 'intval', $ids ) ) );
}
/**
* Counts the demo items still on the site.
*
* @return int
*/
function demo_count() {
static $count = null;
if ( null === $count ) {
$count = count( demo_items() );
}
return $count;
}
/**
* Deletes the demo content and restores the reading settings.
*
* @return int Number of deleted items.
*/
function demo_remove() {
$ids = demo_items();
$deleted = 0;
foreach ( array( 'page_on_front', 'page_for_posts' ) as $option ) {
if ( in_array( (int) get_option( $option ), $ids, true ) ) {
update_option( $option, 0 );
}
}
if ( ! get_option( 'page_on_front' ) ) {
update_option( 'show_on_front', 'posts' );
}
foreach ( $ids as $id ) {
$done = 'attachment' === get_post_type( $id ) ? wp_delete_attachment( $id, true ) : wp_delete_post( $id, true );
if ( $done ) {
++$deleted;
}
}
// Terms the importer created, if nothing else uses them now.
$state = get_option( DEMO_OPTION );
$terms = $state['terms'] ?? demo_term_ids( $state['demo'] ?? 'build' );
foreach ( (array) $terms as $taxonomy => $term_ids ) {
foreach ( (array) $term_ids as $term_id ) {
$term = get_term( (int) $term_id, $taxonomy );
if ( $term instanceof \WP_Term && 0 === (int) $term->count ) {
wp_delete_term( $term->term_id, $taxonomy );
}
}
}
if ( ! empty( $state['title'] ) ) {
update_option( 'blogname', $state['title'] );
}
/**
* Fires after the demo content has been removed.
*
* @param string $demo Slug of the demo that was imported.
*/
do_action( 'blockmason_core_demo_removed', (string) ( $state['demo'] ?? 'build' ) );
delete_option( DEMO_OPTION );
flush_rewrite_rules();
return $deleted;
}
/**
* Looks up the demo terms by slug (for imports made before 0.4.0, which did
* not record the terms they created).
*
* @param string $demo Demo slug.
* @return array
*/
function demo_term_ids( $demo ) {
$file = demo_dir( $demo ) . 'content.php';
$data = demo_dir( $demo ) && file_exists( $file ) ? include $file : array();
$ids = array();
foreach ( (array) ( $data['terms'] ?? array() ) as $taxonomy => $items ) {
foreach ( array_keys( $items ) as $slug ) {
$term = get_term_by( 'slug', $slug, $taxonomy );
if ( $term ) {
$ids[ $taxonomy ][] = (int) $term->term_id;
}
}
}
return $ids;
}
/**
* Replaces {{img:key}} tokens in demo content with the URL of the imported image.
*
* @param string $content Content.
* @param callable $image Returns the attachment ID for an image key.
* @return string
*/
function demo_image_tokens( $content, $image ) {
return (string) preg_replace_callback(
'/\{\{img:([a-z0-9-]+)\}\}/',
static function ( $m ) use ( $image ) {
return esc_url( (string) wp_get_attachment_image_url( $image( $m[1] ), 'large' ) );
},
$content
);
}
/**
* Imports a demo.
*
* @param string $demo Demo slug (folder in demo/).
* @return bool
*/
function demo_import( $demo ) {
$state = get_option( DEMO_OPTION );
if ( ! empty( $state['imported'] ) ) {
return true;
}
$dir = demo_dir( $demo );
if ( ! $dir || ! file_exists( $dir . 'content.php' ) ) {
return false;
}
$file = $dir . 'content.php';
$data = include $file;
if ( ! is_array( $data ) ) {
return false;
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';
wp_raise_memory_limit( 'admin' );
if ( function_exists( 'set_time_limit' ) ) {
set_time_limit( 300 ); // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- Image processing can take a while.
}
$mark = static function ( $post_id ) use ( $demo ) {
if ( $post_id && ! is_wp_error( $post_id ) ) {
update_post_meta( $post_id, '_blockmason_demo', $demo );
}
return $post_id;
};
// Images.
$images = array();
foreach ( $data['images'] as $key => $filename ) {
$path = $dir . 'images/' . $filename;
if ( ! file_exists( $path ) ) {
$path = DIR . 'demo/build/images/' . $filename;
}
$images[ $key ] = demo_import_image( $path, $demo );
}
$image = static function ( $key ) use ( $images ) {
return isset( $images[ $key ] ) ? (int) $images[ $key ] : 0;
};
// Terms.
$terms = array();
$created_terms = array();
foreach ( $data['terms'] as $taxonomy => $items ) {
foreach ( $items as $slug => $name ) {
$term = term_exists( $slug, $taxonomy );
if ( ! $term ) {
$term = wp_insert_term( $name, $taxonomy, array( 'slug' => $slug ) );
if ( ! is_wp_error( $term ) ) {
$created_terms[ $taxonomy ][] = (int) $term['term_id'];
}
}
if ( ! is_wp_error( $term ) ) {
$terms[ $taxonomy ][ $slug ] = (int) $term['term_id'];
}
}
}
$author = get_current_user_id();
if ( ! $author ) {
$admins = get_users(
array(
'role' => 'administrator',
'number' => 1,
'fields' => 'ID',
)
);
$author = $admins ? (int) $admins[0] : 0;
}
$insert = static function ( $type, $item, $order = 0 ) use ( $mark, $image, $author ) {
$post_id = wp_insert_post(
array(
'post_type' => $type,
'post_status' => 'publish',
'post_title' => wp_slash( $item['title'] ),
'post_content' => wp_slash( demo_image_tokens( $item['content'] ?? '', $image ) ),
'post_excerpt' => wp_slash( $item['excerpt'] ?? '' ),
'menu_order' => $order,
'post_author' => $author,
),
true
);
if ( is_wp_error( $post_id ) ) {
return 0;
}
$mark( $post_id );
if ( ! empty( $item['image'] ) && $image( $item['image'] ) ) {
set_post_thumbnail( $post_id, $image( $item['image'] ) );
}
foreach ( $item['meta'] ?? array() as $key => $value ) {
update_post_meta( $post_id, $key, $value );
}
return (int) $post_id;
};
// Services.
$services = array();
$order = 0;
foreach ( $data['services'] as $slug => $item ) {
$item['meta'] = array( 'bm_icon' => $item['icon'] );
$services[ $slug ] = $insert( 'bm_service', $item, ++$order );
}
// Projects.
$projects = array();
foreach ( array_reverse( $data['projects'], true ) as $slug => $item ) {
if ( ! empty( $item['before'] ) ) {
$item['meta']['bm_before_image'] = $image( $item['before'] );
$item['meta']['bm_after_image'] = $image( $item['after'] );
}
$post_id = $insert( 'bm_project', $item );
if ( ! $post_id ) {
continue;
}
$projects[ $slug ] = $post_id;
if ( isset( $terms['bm_project_category'][ $item['category'] ] ) ) {
wp_set_object_terms( $post_id, $terms['bm_project_category'][ $item['category'] ], 'bm_project_category' );
}
foreach ( $item['services'] as $service ) {
if ( ! empty( $services[ $service ] ) ) {
add_post_meta( $post_id, 'bm_services', $services[ $service ] );
}
}
}
// Team.
$order = 0;
foreach ( $data['team'] as $item ) {
$post_id = $insert( 'bm_team_member', $item, ++$order );
if ( $post_id && isset( $terms['bm_department'][ $item['department'] ] ) ) {
wp_set_object_terms( $post_id, $terms['bm_department'][ $item['department'] ], 'bm_department' );
}
}
// Testimonials.
$order = 0;
foreach ( $data['testimonials'] as $item ) {
$item['meta']['bm_project'] = $projects[ $item['project'] ] ?? 0;
$insert( 'bm_testimonial', $item, ++$order );
}
// News.
foreach ( array_reverse( $data['posts'] ) as $item ) {
$post_id = $insert( 'post', $item );
if ( $post_id && ! empty( $item['category'] ) && isset( $terms['category'][ $item['category'] ] ) ) {
wp_set_post_categories( $post_id, array( $terms['category'][ $item['category'] ] ) );
}
if ( $post_id && ! empty( $item['tags'] ) ) {
wp_set_post_tags( $post_id, $item['tags'] );
}
}
// Pages.
$pages = array();
foreach ( $data['pages'] as $slug => $item ) {
if ( 'contact' === $slug ) {
$item['content'] = demo_contact_content( $item['content'], $mark, (string) wp_get_attachment_image_url( $image( 'apartments' ), 'full' ) );
}
$pages[ $slug ] = $insert( 'page', $item );
if ( $pages[ $slug ] && ! empty( $item['template'] ) ) {
update_post_meta( $pages[ $slug ], '_wp_page_template', $item['template'] );
}
}
if ( ! empty( $pages['home'] ) && ! empty( $pages['news'] ) ) {
update_option( 'show_on_front', 'page' );
update_option( 'page_on_front', $pages['home'] );
update_option( 'page_for_posts', $pages['news'] );
}
// Menu (used by the Navigation block in the header and footer).
$links = '';
foreach ( $data['menu'] as $link ) {
$links .= sprintf(
'',
esc_attr( $link[0] ),
esc_url_raw( home_url( $link[1] ) )
);
}
$mark(
wp_insert_post(
array(
'post_type' => 'wp_navigation',
'post_status' => 'publish',
'post_title' => __( 'Main menu', 'blockmason-core' ),
'post_content' => wp_slash( $links ),
)
)
);
$old_title = get_option( 'blogname' );
if ( ! empty( $data['site_title'] ) ) {
update_option( 'blogname', $data['site_title'] );
}
flush_rewrite_rules();
update_option(
DEMO_OPTION,
array(
'demo' => $demo,
'imported' => time(),
'terms' => $created_terms,
'title' => $old_title,
),
false
);
/**
* Fires after a demo has been imported.
*
* @param string $demo Demo slug.
* @param array $data The demo's content.php data.
*/
do_action( 'blockmason_core_demo_imported', $demo, $data );
return true;
}
/**
* Adds a Contact Form 7 quote form to the Contact page, when the plugin is active.
*
* The form sits in a white card on a full-width photo.
*
* @param string $content Page content.
* @param callable $mark Marks a post as demo content.
* @param string $image URL of the background photo.
* @return string
*/
function demo_contact_content( $content, $mark, $image = '' ) {
if ( ! class_exists( 'WPCF7_ContactForm' ) || ! method_exists( 'WPCF7_ContactForm', 'get_template' ) ) {
return $content;
}
$form = \WPCF7_ContactForm::get_template(
array(
'title' => __( 'Quote request', 'blockmason-core' ),
)
);
$field = static function ( $label, $tag ) {
return '';
};
$privacy = get_privacy_policy_url();
$consent = $privacy
? sprintf(
/* translators: %s: link to the privacy policy. */
__( 'I agree that my data is stored to answer my request (%s).', 'blockmason-core' ),
'' . esc_html__( 'privacy policy', 'blockmason-core' ) . ''
)
: __( 'I agree that my data is stored to answer my request.', 'blockmason-core' );
$form->set_properties(
array(
'form' => implode(
"\n",
array(
$field( __( 'Your name', 'blockmason-core' ), '[text* your-name autocomplete:name placeholder "' . esc_attr__( 'Your name', 'blockmason-core' ) . '"]' ),
$field( __( 'Email', 'blockmason-core' ), '[email* your-email autocomplete:email placeholder "' . esc_attr__( 'Email', 'blockmason-core' ) . '"]' ),
$field( __( 'Phone', 'blockmason-core' ), '[tel your-phone autocomplete:tel placeholder "' . esc_attr__( 'Phone', 'blockmason-core' ) . '"]' ),
$field( __( 'Type of work', 'blockmason-core' ), '[select your-work first_as_label "' . __( 'Type of work', 'blockmason-core' ) . '" "' . __( 'New build', 'blockmason-core' ) . '" "' . __( 'Renovation', 'blockmason-core' ) . '" "' . __( 'Roofing', 'blockmason-core' ) . '" "' . __( 'Bathroom or kitchen', 'blockmason-core' ) . '" "' . __( 'Other', 'blockmason-core' ) . '"]' ),
$field( __( 'Tell us about the project', 'blockmason-core' ), '[textarea your-message placeholder "' . esc_attr__( 'Tell us about the project', 'blockmason-core' ) . '"]' ),
'[acceptance your-consent] ' . $consent . ' [/acceptance]',
'[submit "' . __( 'Request a quote', 'blockmason-core' ) . '"]',
)
),
)
);
$form_id = $form->save();
if ( ! $form_id ) {
return $content;
}
$mark( $form_id );
$cover = $image
? sprintf( '{"url":"%1$s","dimRatio":20,', esc_url_raw( $image ) )
: '{"dimRatio":100,';
$img = $image
? sprintf( '
', esc_url( $image ) )
: '';
$section = sprintf(
'',
$cover,
$image ? 20 : 100,
$img,
esc_html__( 'Have a project in mind? Get in touch!', 'blockmason-core' ),
(int) $form_id,
esc_attr__( 'Quote request', 'blockmason-core' )
);
// Place the form right after the contacts section.
$anchor = '';
return str_contains( $content, $anchor ) ? str_replace( $anchor, $anchor . $section, $content ) : $content . $section;
}
/**
* Copies a bundled image into the media library.
*
* @param string $path Absolute path of the bundled file.
* @param string $demo Demo slug.
* @return int Attachment ID, or 0.
*/
function demo_import_image( $path, $demo ) {
if ( ! file_exists( $path ) ) {
return 0;
}
$tmp = wp_tempnam( basename( $path ) );
if ( ! $tmp || ! copy( $path, $tmp ) ) {
return 0;
}
$id = media_handle_sideload(
array(
'name' => basename( $path ),
'tmp_name' => $tmp,
),
0
);
if ( is_wp_error( $id ) ) {
wp_delete_file( $tmp );
return 0;
}
update_post_meta( $id, '_blockmason_demo', $demo );
return (int) $id;
}