first
This commit is contained in:
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* A3 Lazy Load Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_A3_Lazy_Load
|
||||
*/
|
||||
class Visual_Portfolio_3rd_A3_Lazy_Load {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_A3_Lazy_Load constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Fix conflict with lazy loading.
|
||||
add_filter( 'a3_lazy_load_skip_images_classes', array( $this, 'a3_lazy_load_skip_images_classes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add lazyload class to skip.
|
||||
*
|
||||
* @param string $classes classes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function a3_lazy_load_skip_images_classes( $classes ) {
|
||||
if ( '' !== $classes && ! empty( $classes ) ) {
|
||||
$classes .= ',';
|
||||
}
|
||||
|
||||
$classes .= 'vp-lazyload';
|
||||
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_A3_Lazy_Load();
|
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
/**
|
||||
* All In One SEO Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_All_In_One_Seo
|
||||
*/
|
||||
class Visual_Portfolio_3rd_All_In_One_Seo {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_All_In_One_Seo constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Fixed canonical links.
|
||||
add_filter( 'aioseo_canonical_url', array( 'Visual_Portfolio_Archive_Mapping', 'get_canonical' ) );
|
||||
add_filter( 'aioseo_schema_output', array( $this, 'graph_schema_output' ) );
|
||||
add_action( 'wp_print_footer_scripts', array( $this, 'set_query_as_archive' ), 8 ); // priority one level lower than what the plugin uses.
|
||||
add_action( 'wp_print_footer_scripts', array( $this, 'remove_query_as_archive' ), 13 ); // priority one level higher than what the plugin uses.
|
||||
add_action( 'wp', array( $this, 'set_query_as_archive' ), 9 );
|
||||
add_action( 'wp', array( $this, 'remove_query_as_archive' ), 13 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows changing graph output.
|
||||
*
|
||||
* @param array $graph - Graph output array.
|
||||
* @return array
|
||||
*/
|
||||
public function graph_schema_output( $graph ) {
|
||||
if ( isset( $graph ) && ! empty( $graph ) && is_array( $graph ) ) {
|
||||
foreach ( $graph as $key => $graph_item ) {
|
||||
if ( isset( $graph_item['@type'] ) ) {
|
||||
switch ( $graph_item['@type'] ) {
|
||||
case 'BreadcrumbList':
|
||||
$graph[ $key ]['@id'] = Visual_Portfolio_Archive_Mapping::get_canonical_anchor( $graph_item['@id'] );
|
||||
break;
|
||||
case 'WebPage':
|
||||
case 'CollectionPage':
|
||||
$graph[ $key ]['@id'] = Visual_Portfolio_Archive_Mapping::get_canonical_anchor( $graph_item['@id'] );
|
||||
$graph[ $key ]['url'] = Visual_Portfolio_Archive_Mapping::get_canonical( $graph_item['@id'] );
|
||||
$graph[ $key ]['breadcrumb']['@id'] = Visual_Portfolio_Archive_Mapping::get_canonical_anchor( $graph_item['@id'] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set query as archive temporary.
|
||||
* This is necessary for the plugin to work correctly and set all the necessary settings in the page footer.
|
||||
* Because our custom archive and taxonomy pages override the base query and interfere with the global object,
|
||||
* Conflicts may occur with some SEO plugins that work this way.
|
||||
* In this case, the search plugin is trying to place the assets needed for a regular page in the footer,
|
||||
* While the page itself is defined as a taxonomy.
|
||||
* In this case, we let the plugin know that this is not a page, but a category.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_query_as_archive() {
|
||||
if ( Visual_Portfolio_Archive_Mapping::is_category() ) {
|
||||
global $wp_query;
|
||||
|
||||
$wp_query->is_archive = true;
|
||||
$wp_query->is_single = false;
|
||||
$wp_query->is_singular = false;
|
||||
$wp_query->is_page = false;
|
||||
$wp_query->is_post_type_archive = true;
|
||||
$wp_query->is_category = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set query as archive temporary.
|
||||
* This is necessary for the plugin to work correctly and set all the necessary settings in the page footer.
|
||||
* Because our custom archive and taxonomy pages override the base query and interfere with the global object,
|
||||
* Conflicts may occur with some SEO plugins that work this way.
|
||||
* In this case, the search plugin is trying to place the assets needed for a regular page in the footer,
|
||||
* While the page itself is defined as a taxonomy.
|
||||
* In this case, we let the plugin know that this is not a page, but a category.
|
||||
* This function cancels previous settings so as not to interfere with further system operation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove_query_as_archive() {
|
||||
if ( Visual_Portfolio_Archive_Mapping::is_category() ) {
|
||||
global $wp_query;
|
||||
|
||||
$wp_query->is_archive = false;
|
||||
$wp_query->is_single = false;
|
||||
$wp_query->is_singular = true;
|
||||
$wp_query->is_page = true;
|
||||
$wp_query->is_post_type_archive = false;
|
||||
$wp_query->is_category = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_3rd_All_In_One_Seo();
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
/**
|
||||
* Divi Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Divi
|
||||
*/
|
||||
class Visual_Portfolio_Divi {
|
||||
/**
|
||||
* Visual_Portfolio_Divi constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'wp_head', array( $this, 'maybe_fix_images_width' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add CSS to fix lazy loaded Divi images widths.
|
||||
* When the image has lazy loading attributes, width is set to 4px, not the actual image size.
|
||||
*/
|
||||
public function maybe_fix_images_width() {
|
||||
if ( ! defined( 'ET_CORE' ) || 'full' !== Visual_Portfolio_Settings::get_option( 'lazy_loading', 'vp_images' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<style type="text/css">
|
||||
.et-db #et-boc .et-l .et_pb_module .et_pb_image_wrap,
|
||||
.et-db #et-boc .et-l .et_pb_module .et_pb_image_wrap img[data-src] {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Divi();
|
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
/**
|
||||
* Widget for Elementor
|
||||
*
|
||||
* @package visual-portfolio/elementor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Elementor_Widget
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Elementor_Widget extends \Elementor\Widget_Base {
|
||||
/**
|
||||
* Constructor of Visual_Portfolio_3rd_Elementor_Widget class.
|
||||
*
|
||||
* @param array $data default widget data.
|
||||
* @param null|array $args default widget args.
|
||||
*/
|
||||
public function __construct( $data = array(), $args = null ) {
|
||||
// Migrate from old 'id' control to new 'saved_id'.
|
||||
if ( isset( $data['settings']['id'] ) ) {
|
||||
if ( $data['settings']['id'] && ( ! isset( $data['settings']['saved_id'] ) || ! $data['settings']['saved_id'] ) ) {
|
||||
$data['settings']['saved_id'] = $data['settings']['id'];
|
||||
}
|
||||
|
||||
unset( $data['settings']['id'] );
|
||||
}
|
||||
|
||||
parent::__construct( $data, $args );
|
||||
|
||||
if ( $this->is_preview_mode() ) {
|
||||
Visual_Portfolio_Assets::register_script( 'iframe-resizer', 'assets/vendor/iframe-resizer/js/iframeResizer.min', array(), '4.3.7' );
|
||||
Visual_Portfolio_Assets::register_script( 'visual-portfolio-elementor', 'build/assets/admin/js/elementor', array( 'elementor-frontend', 'iframe-resizer' ) );
|
||||
|
||||
Visual_Portfolio_Assets::register_style( 'visual-portfolio-elementor', 'build/assets/admin/css/elementor' );
|
||||
wp_style_add_data( 'visual-portfolio-elementor', 'rtl', 'replace' );
|
||||
wp_style_add_data( 'visual-portfolio-elementor', 'suffix', '.min' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Is edit mode check.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_preview_mode() {
|
||||
return \Elementor\Plugin::$instance->preview->is_preview_mode() || \Elementor\Plugin::$instance->editor->is_edit_mode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get widget name.
|
||||
*
|
||||
* @return string Widget name.
|
||||
*/
|
||||
public function get_name() {
|
||||
return 'visual-portfolio';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get widget title.
|
||||
*
|
||||
* @return string Widget title.
|
||||
*/
|
||||
public function get_title() {
|
||||
return visual_portfolio()->plugin_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get widget icon.
|
||||
*
|
||||
* @return string Widget icon.
|
||||
*/
|
||||
public function get_icon() {
|
||||
return 'eicon-gallery-grid';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get widget categories.
|
||||
*
|
||||
* @return array Widget categories.
|
||||
*/
|
||||
public function get_categories() {
|
||||
return array( 'general' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get widget keywords.
|
||||
*
|
||||
* @return array Widget keywords.
|
||||
*/
|
||||
public function get_keywords() {
|
||||
return array( 'portfolio', 'gallery', 'images', 'visual portfolio', 'vpf' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get script dependencies.
|
||||
*
|
||||
* @return array Widget script dependencies.
|
||||
*/
|
||||
public function get_script_depends() {
|
||||
if ( $this->is_preview_mode() ) {
|
||||
return array( 'visual-portfolio-elementor' );
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* We should add the prefix to all options, because Select2 conflicts with the Safari for some reason.
|
||||
*
|
||||
* @param String $option - option value.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function set_option_prefix( $option ) {
|
||||
return 'post-id-' . $option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove prefix from the option.
|
||||
*
|
||||
* @param String $option - prefixed option value.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function unset_option_prefix( $option ) {
|
||||
return str_replace( 'post-id-', '', $option );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get style dependencies.
|
||||
*
|
||||
* @return array Widget style dependencies.
|
||||
*/
|
||||
public function get_style_depends() {
|
||||
if ( $this->is_preview_mode() ) {
|
||||
return array( 'visual-portfolio-elementor' );
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds different input fields to allow the user to change and customize the widget settings.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function register_controls() {
|
||||
// get all visual-portfolio post types.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408 .
|
||||
$vp_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
|
||||
$options = array(
|
||||
'' => esc_html__( '-- Select Layout --', 'visual-portfolio' ),
|
||||
);
|
||||
foreach ( $vp_query as $post ) {
|
||||
$options[ $this->set_option_prefix( $post->ID ) ] = '#' . $post->ID . ' - ' . $post->post_title;
|
||||
}
|
||||
|
||||
$this->start_controls_section(
|
||||
'content_section',
|
||||
array(
|
||||
'label' => __( 'General', 'visual-portfolio' ),
|
||||
'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
|
||||
)
|
||||
);
|
||||
|
||||
$this->add_control(
|
||||
'saved_id',
|
||||
array(
|
||||
'label' => esc_html__( 'Saved Layout', 'visual-portfolio' ),
|
||||
'type' => \Elementor\Controls_Manager::SELECT2,
|
||||
'options' => $options,
|
||||
'dynamic' => array(
|
||||
'active' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$this->end_controls_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* Render widget output on the frontend.
|
||||
*/
|
||||
protected function render() {
|
||||
$settings = array_merge(
|
||||
array(
|
||||
'saved_id' => '',
|
||||
'class' => '',
|
||||
),
|
||||
$this->get_settings_for_display()
|
||||
);
|
||||
|
||||
// No saved layout selected.
|
||||
if ( ! $settings['saved_id'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->is_preview_mode() ) {
|
||||
$this->add_render_attribute(
|
||||
'wrapper',
|
||||
array(
|
||||
'class' => 'visual-portfolio-elementor-preview',
|
||||
'data-id' => $this->unset_option_prefix( $settings['saved_id'] ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
||||
<div
|
||||
<?php
|
||||
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo $this->get_render_attribute_string( 'wrapper' );
|
||||
?>
|
||||
>
|
||||
<?php if ( $this->is_preview_mode() ) : ?>
|
||||
<iframe allowtransparency="true"></iframe>
|
||||
<?php else : ?>
|
||||
<?php echo do_shortcode( '[visual_portfolio id="' . esc_attr( $this->unset_option_prefix( $settings['saved_id'] ) ) . '"]' ); ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render shortcode widget output in the editor.
|
||||
*
|
||||
* Written as a Backbone JavaScript template and used to generate the live preview.
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @access protected
|
||||
*/
|
||||
protected function content_template() {}
|
||||
|
||||
/**
|
||||
* Render Plain Content
|
||||
*
|
||||
* @param array $instance instance data.
|
||||
*/
|
||||
// phpcs:ignore
|
||||
public function render_plain_content( $instance = array() ) {}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* Class for Elementor
|
||||
*
|
||||
* @package visual-portfolio/elementor
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Elementor
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Elementor {
|
||||
/**
|
||||
* Lightbox fix added.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $lightbox_fix_added = false;
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Elementor constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'elementor/widgets/register', array( $this, 'register_widget' ) );
|
||||
|
||||
// We should also try to include this script in the footer,
|
||||
// since caching plugins place jQuery in the footer, and our script depends on it.
|
||||
add_action( 'wp_body_open', array( $this, 'maybe_fix_elementor_lightbox_conflict' ) );
|
||||
add_action( 'wp_footer', array( $this, 'maybe_fix_elementor_lightbox_conflict' ), 20 );
|
||||
|
||||
// Compatibility code for Swiper library.
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'fix_elementor_swiper_assets' ), 101 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register widget
|
||||
*/
|
||||
public function register_widget() {
|
||||
require_once visual_portfolio()->plugin_path . 'classes/3rd/plugins/class-elementor-widget.php';
|
||||
|
||||
\Elementor\Plugin::instance()->widgets_manager->register( new Visual_Portfolio_3rd_Elementor_Widget() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix Elementor lightbox conflict.
|
||||
*
|
||||
* @see https://github.com/nk-crew/visual-portfolio/issues/103
|
||||
*/
|
||||
public function maybe_fix_elementor_lightbox_conflict() {
|
||||
if ( ! defined( 'ELEMENTOR_VERSION' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We should check it, as we are trying to inject this script twice.
|
||||
if ( $this->lightbox_fix_added ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! wp_script_is( 'jquery', 'enqueued' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->lightbox_fix_added = true;
|
||||
|
||||
?>
|
||||
<script>
|
||||
(function($) {
|
||||
if (!$) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Previously we added this code on Elementor pages only,
|
||||
// but sometimes Lightbox enabled globally and it still conflicting with our galleries.
|
||||
// if (!$('.elementor-page').length) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
function addDataAttribute($items) {
|
||||
$items.find('.vp-portfolio__item a:not([data-elementor-open-lightbox])').each(function () {
|
||||
if (/\.(png|jpe?g|gif|svg|webp)(\?.*)?$/i.test(this.href)) {
|
||||
this.dataset.elementorOpenLightbox = 'no';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).on('init.vpf', function(event, vpObject) {
|
||||
if ('vpf' !== event.namespace) {
|
||||
return;
|
||||
}
|
||||
|
||||
addDataAttribute(vpObject.$item);
|
||||
});
|
||||
$(document).on('addItems.vpf', function(event, vpObject, $items) {
|
||||
if ('vpf' !== event.namespace) {
|
||||
return;
|
||||
}
|
||||
|
||||
addDataAttribute($items);
|
||||
});
|
||||
})(window.jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Swiper from the Elementor plugin to prevent conflicts.
|
||||
*
|
||||
* @link https://wordpress.org/support/topic/visual-portfolio-elementor-issue/ - Old Elementor (< v3.11.0) and their lightbox is not working properly if we include new Swiper library.
|
||||
* @link https://wordpress.org/support/topic/elementor-image-carousel-navigation-is-affected-by-this-plugin/ - New Elementor (>= 3.11.0) added support for the latest version of Swiper library and changed their old fallback Swiper library. This is why we have to include Swiper's assets instead of ours.
|
||||
*/
|
||||
public function fix_elementor_swiper_assets() {
|
||||
if ( ! class_exists( '\Elementor\Plugin' ) || ! isset( \Elementor\Plugin::$instance->experiments ) || ! defined( 'ELEMENTOR_URL' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wp_scripts;
|
||||
global $wp_styles;
|
||||
|
||||
// Since the Elementor assets methods like `get_css_assets_url` are protected
|
||||
// and we can't use it directly, we prepare assets URLs manually.
|
||||
$e_swiper_latest = \Elementor\Plugin::$instance->experiments->is_feature_active( 'e_swiper_latest' );
|
||||
$e_swiper_asset_path = $e_swiper_latest ? 'assets/lib/swiper/v8/' : 'assets/lib/swiper/';
|
||||
$e_swiper_version = $e_swiper_latest ? '8.4.5' : '5.3.6';
|
||||
$e_file_name = 'swiper';
|
||||
$e_assets_base_url = ELEMENTOR_URL;
|
||||
$e_assets_relative_url = 'assets/';
|
||||
$e_css_relative_url = $e_swiper_asset_path . 'css/';
|
||||
$e_js_relative_url = $e_swiper_asset_path;
|
||||
|
||||
if ( ! $e_css_relative_url ) {
|
||||
$e_css_relative_url = $e_assets_relative_url . 'css/';
|
||||
}
|
||||
if ( ! $e_js_relative_url ) {
|
||||
$e_js_relative_url = $e_assets_relative_url;
|
||||
}
|
||||
|
||||
$e_swiper_css_url = $e_assets_base_url . $e_css_relative_url . $e_file_name . '.css';
|
||||
$e_swiper_js_url = $e_assets_base_url . $e_js_relative_url . $e_file_name . '.js';
|
||||
|
||||
// Elementor < 3.11.0 does not have a Swiper CSS file.
|
||||
if ( version_compare( ELEMENTOR_VERSION, '3.11.0', '<' ) ) {
|
||||
$e_swiper_css_url = visual_portfolio()->plugin_url . 'assets/vendor/swiper-5-3-6/swiper.min.css';
|
||||
}
|
||||
|
||||
// Since we include Swiper library ourselves, here we have to override assets URLs.
|
||||
if ( isset( $wp_scripts->registered['swiper']->src ) ) {
|
||||
$wp_scripts->registered['swiper']->src = $e_swiper_js_url;
|
||||
$wp_scripts->registered['swiper']->ver = $e_swiper_version;
|
||||
}
|
||||
if ( isset( $wp_styles->registered['swiper']->src ) ) {
|
||||
$wp_styles->registered['swiper']->src = $e_swiper_css_url;
|
||||
$wp_styles->registered['swiper']->ver = $e_swiper_version;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Elementor();
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* EWWW Image Optimizer Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Ewww_Image_Optimizer
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Ewww_Image_Optimizer {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Ewww_Image_Optimizer constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( ! function_exists( 'ewww_image_optimizer_get_option' ) || ! ewww_image_optimizer_get_option( 'ewww_image_optimizer_lazy_load' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable our lazyload if EWWW lazyload used.
|
||||
add_filter( 'vpf_images_lazyload', '__return_false' );
|
||||
add_filter( 'vpf_enqueue_plugin_lazysizes', '__return_false' );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Ewww_Image_Optimizer();
|
@ -0,0 +1,67 @@
|
||||
<?php
|
||||
/**
|
||||
* Imagify Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Imagify
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Imagify {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Imagify constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Fix lazyload attributes.
|
||||
//
|
||||
// Thanks to:
|
||||
// - https://wordpress.org/support/topic/all-images-are-grey/
|
||||
// - https://wordpress.org/support/topic/all-images-are-grey-again/.
|
||||
add_filter( 'imagify_picture_attributes', array( $this, 'imagify_picture_attributes' ) );
|
||||
add_filter( 'imagify_picture_img_attributes', array( $this, 'imagify_picture_img_attributes' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove lazyload class from the picture tag.
|
||||
*
|
||||
* @param array $attributes image tag attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function imagify_picture_attributes( $attributes ) {
|
||||
if ( isset( $attributes['class'] ) && strpos( $attributes['class'], 'vp-lazyload' ) !== false ) {
|
||||
$attributes['class'] = str_replace( 'vp-lazyload', '', $attributes['class'] );
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore lazyload class to the img tag.
|
||||
*
|
||||
* @param array $attributes image tag attributes.
|
||||
* @param array $image image data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function imagify_picture_img_attributes( $attributes, $image ) {
|
||||
if ( isset( $image['attributes']['class'] ) && strpos( $image['attributes']['class'], 'vp-lazyload' ) !== false ) {
|
||||
if ( isset( $attributes['class'] ) ) {
|
||||
$attributes['class'] .= ' ';
|
||||
} else {
|
||||
$attributes['class'] = '';
|
||||
}
|
||||
|
||||
$attributes['class'] .= 'vp-lazyload';
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Imagify();
|
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/**
|
||||
* Jetpack Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Jetpack
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Jetpack {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Jetpack constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Fix conflict with lazy loading.
|
||||
add_filter( 'jetpack_lazy_images_skip_image_with_attributes', array( $this, 'jetpack_lazy_images_skip_image_with_attributes' ), 15, 2 );
|
||||
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ), 20 );
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to init the Jetpack lazy loading manually after Visual Portfolio AJAX completed.
|
||||
*/
|
||||
public function wp_enqueue_scripts() {
|
||||
$wp_scripts = wp_scripts();
|
||||
$jetpack_ll_handler = 'jetpack-lazy-images';
|
||||
|
||||
if ( ! isset( $wp_scripts->registered[ $jetpack_ll_handler ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Visual_Portfolio_Assets::register_script( 'visual-portfolio-3rd-jetpack', 'build/assets/js/3rd/plugin-jetpack' );
|
||||
|
||||
$wp_scripts->registered[ $jetpack_ll_handler ]->deps[] = 'visual-portfolio-3rd-jetpack';
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip Jetpack lazy loading when data-src attribute added to image.
|
||||
*
|
||||
* @param boolean $return skip lazy Jetpack.
|
||||
* @param array $attributes image attributes.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function jetpack_lazy_images_skip_image_with_attributes( $return, $attributes ) {
|
||||
return isset( $attributes['data-src'] );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Jetpack();
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
/**
|
||||
* Lazy Loader Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Lazy_Loader
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Lazy_Loader {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Lazy_Loader constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( ! class_exists( 'FlorianBrinkmann\LazyLoadResponsiveImages\Plugin' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable our lazyload if Lazy Loader plugin installed.
|
||||
add_filter( 'vpf_images_lazyload', '__return_false' );
|
||||
add_filter( 'vpf_enqueue_plugin_lazysizes', '__return_false' );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Lazy_Loader();
|
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
/**
|
||||
* Paid Memberships Pro Plugin.
|
||||
*
|
||||
* @package visual-portfolio/pmp
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Paid_Memberships_Pro
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Paid_Memberships_Pro {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Paid_Memberships_Pro constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'fix_pmpromh_redirect_in_preview' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove redirect action from the preview frame.
|
||||
* Because "Paid Memberships Pro - Member Homepages Add On" make their own redirect and our preview frame failed to load.
|
||||
*/
|
||||
public function fix_pmpromh_redirect_in_preview() {
|
||||
if ( ! function_exists( 'pmpromh_template_redirect_homepage' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_GET['vp_preview'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
remove_action( 'template_redirect', 'pmpromh_template_redirect_homepage' );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Paid_Memberships_Pro();
|
@ -0,0 +1,85 @@
|
||||
<?php
|
||||
/**
|
||||
* Rank Math SEO Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Rank_Math
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Rank_Math {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Rank_Math constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Fixed canonical links.
|
||||
add_filter( 'rank_math/frontend/canonical', array( 'Visual_Portfolio_Archive_Mapping', 'get_canonical' ) );
|
||||
add_filter( 'rank_math/frontend/title', array( $this, 'get_title' ) );
|
||||
add_filter( 'rank_math/opengraph/facebook/og_title', array( $this, 'get_title' ) );
|
||||
add_action( 'rank_math/head', array( $this, 'set_query_as_archive' ), 5 ); // priority one level lower than what the plugin uses.
|
||||
add_action( 'rank_math/head', array( $this, 'remove_query_as_archive' ), 23 ); // priority one level higher than what the plugin uses.
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow changing the Rank Math generated title.
|
||||
*
|
||||
* @param string $title - Current Page Title.
|
||||
* @return string
|
||||
*/
|
||||
public function get_title( $title ) {
|
||||
return Visual_Portfolio_Archive_Mapping::get_current_term_title() ?? $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set query as archive temporary.
|
||||
* This is necessary for the plugin to work correctly and set all the necessary settings in the page header.
|
||||
* Because our custom archive and taxonomy pages override the base query and interfere with the global object,
|
||||
* Conflicts may occur with some SEO plugins that work this way.
|
||||
* In this case, the search plugin is trying to place the assets needed for a regular page in the header,
|
||||
* While the page itself is defined as a taxonomy.
|
||||
* In this case, we let the plugin know that this is not a page, but a category.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_query_as_archive() {
|
||||
if ( Visual_Portfolio_Archive_Mapping::is_category() ) {
|
||||
global $wp_query;
|
||||
|
||||
$wp_query->is_archive = true;
|
||||
$wp_query->is_single = false;
|
||||
$wp_query->is_singular = false;
|
||||
$wp_query->is_page = false;
|
||||
$wp_query->is_post_type_archive = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove query as archive temporary.
|
||||
* This is necessary for the plugin to work correctly and set all the necessary settings in the page header.
|
||||
* Because our custom archive and taxonomy pages override the base query and interfere with the global object,
|
||||
* Conflicts may occur with some SEO plugins that work this way.
|
||||
* In this case, the search plugin is trying to place the assets needed for a regular page in the header,
|
||||
* While the page itself is defined as a taxonomy.
|
||||
* In this case, we let the plugin know that this is not a page, but a category.
|
||||
* This function cancels previous settings so as not to interfere with further system operation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove_query_as_archive() {
|
||||
if ( Visual_Portfolio_Archive_Mapping::is_category() ) {
|
||||
global $wp_query;
|
||||
|
||||
$wp_query->is_archive = false;
|
||||
$wp_query->is_single = true;
|
||||
$wp_query->is_singular = true;
|
||||
$wp_query->is_page = true;
|
||||
$wp_query->is_post_type_archive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_3rd_Rank_Math();
|
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* SiteGround Optimizer Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_SG_Cachepress
|
||||
*/
|
||||
class Visual_Portfolio_3rd_SG_Cachepress {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_SG_Cachepress constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( ! class_exists( '\SiteGround_Optimizer\Options\Options' ) || ! \SiteGround_Optimizer\Options\Options::is_enabled( 'siteground_optimizer_lazyload_images' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable our lazyload if SiteGround Optimizer lazyload used.
|
||||
add_filter( 'vpf_images_lazyload', '__return_false' );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ), 20 );
|
||||
}
|
||||
|
||||
/**
|
||||
* SG lazy loading breaks our scripts which calculate size of the images,
|
||||
* we need to resolve it in a hacky way by changing src placeholder.
|
||||
*/
|
||||
public function wp_enqueue_scripts() {
|
||||
$wp_scripts = wp_scripts();
|
||||
$sg_ll_handler = 'siteground-optimizer-lazy-sizes-js';
|
||||
|
||||
if ( ! isset( $wp_scripts->registered[ $sg_ll_handler ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wp_scripts->registered[ $sg_ll_handler ]->deps[] = 'jquery';
|
||||
|
||||
wp_add_inline_script(
|
||||
$sg_ll_handler,
|
||||
'(function($){
|
||||
if ( !$ ) {
|
||||
return;
|
||||
}
|
||||
|
||||
function maybeFixSGSrc( $images ) {
|
||||
$images.find( "img[src=\"data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7\"]" ).each( function() {
|
||||
var $img = $( this );
|
||||
var width = $img.attr( "width" );
|
||||
var height = $img.attr( "height" );
|
||||
|
||||
if ( width && height ) {
|
||||
var newSrc = "<svg width=\"" + width + "\" height=\"" + height + "\" viewBox=\"0 0 " + width + " " + height + "\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"></svg>";
|
||||
|
||||
newSrc = newSrc
|
||||
.replace( /</g, "%3c" )
|
||||
.replace( />/g, "%3e" )
|
||||
.replace( /#/g, "%23" )
|
||||
.replace( /"/g, "\'" );
|
||||
|
||||
$img.attr( "src", "data:image/svg+xml;utf8," + newSrc );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
// Fix starter images.
|
||||
maybeFixSGSrc( $( ".vp-portfolio__items" ) );
|
||||
|
||||
// Fix AJAX loaded images.
|
||||
$( document ).on( "addItems.vpf", function ( event, self, $items, removeExisting ) {
|
||||
if ( "vpf" !== event.namespace ) {
|
||||
return;
|
||||
}
|
||||
|
||||
maybeFixSGSrc( $items );
|
||||
} );
|
||||
}(window.jQuery));',
|
||||
'before'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_SG_Cachepress();
|
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Extend TinyMCE toolbar
|
||||
*
|
||||
* @package visual-portfolio/tinymce
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_TinyMCE
|
||||
*/
|
||||
class Visual_Portfolio_3rd_TinyMCE {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_TinyMCE constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks.
|
||||
*/
|
||||
public function init_hooks() {
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'admin_head', array( $this, 'admin_head' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin Head Action.
|
||||
*/
|
||||
public function admin_head() {
|
||||
if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) ) {
|
||||
add_filter( 'mce_external_plugins', array( $this, 'mce_external_plugins' ) );
|
||||
add_filter( 'mce_buttons', array( $this, 'mce_buttons' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue admin scripts
|
||||
*
|
||||
* @param string $page - page name.
|
||||
*/
|
||||
public function admin_enqueue_scripts( $page ) {
|
||||
if ( 'post.php' === $page || 'post-new.php' === $page ) {
|
||||
// add tiny mce data.
|
||||
$data_tiny_mce = array(
|
||||
'plugin_name' => visual_portfolio()->plugin_name,
|
||||
'layouts' => array(),
|
||||
);
|
||||
|
||||
// get all visual-portfolio post types.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408 .
|
||||
$vp_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
foreach ( $vp_query as $post ) {
|
||||
$data_tiny_mce['layouts'][] = array(
|
||||
'id' => $post->ID,
|
||||
'title' => '#' . $post->ID . ' - ' . $post->post_title,
|
||||
);
|
||||
}
|
||||
|
||||
// return if no data.
|
||||
if ( empty( $data_tiny_mce['layouts'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Visual_Portfolio_Assets::enqueue_script( 'visual-portfolio-tinymce-localize', 'build/assets/admin/js/mce-localize' );
|
||||
wp_localize_script( 'visual-portfolio-tinymce-localize', 'VPTinyMCEData', $data_tiny_mce );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add script for button
|
||||
*
|
||||
* @param array $plugins - available plugins.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function mce_external_plugins( $plugins ) {
|
||||
$plugins['visual_portfolio'] = visual_portfolio()->plugin_url . 'build/assets/admin/js/mce-dropdown.js';
|
||||
return $plugins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dropdown button to tinymce
|
||||
*
|
||||
* @param array $buttons - available buttons.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function mce_buttons( $buttons ) {
|
||||
array_push( $buttons, 'visual_portfolio' );
|
||||
return $buttons;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_TinyMCE();
|
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
/**
|
||||
* Shortcode for Visual Composer
|
||||
*
|
||||
* @package visual-portfolio/vc
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_VC
|
||||
*/
|
||||
class Visual_Portfolio_3rd_VC {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_VC constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks.
|
||||
*/
|
||||
public function init_hooks() {
|
||||
add_action( 'init', array( $this, 'add_shortcode' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue script for frontend VC
|
||||
*
|
||||
* @param object $page - page object.
|
||||
*/
|
||||
public function admin_enqueue_scripts( $page ) {
|
||||
if ( 'post.php' === $page || 'post-new.php' === $page ) {
|
||||
Visual_Portfolio_Assets::enqueue_script( 'visual-portfolio-vc-frontend', 'build/assets/admin/js/vc-frontend' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add shortcode to the visual composer
|
||||
*/
|
||||
public function add_shortcode() {
|
||||
if ( function_exists( 'vc_map' ) ) {
|
||||
// get all visual-portfolio post types.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408 .
|
||||
$vp_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
|
||||
$data_vc = array();
|
||||
foreach ( $vp_query as $post ) {
|
||||
$data_vc[] = array( $post->ID, '#' . $post->ID . ' - ' . $post->post_title );
|
||||
}
|
||||
|
||||
vc_map(
|
||||
array(
|
||||
'name' => visual_portfolio()->plugin_name,
|
||||
'base' => 'visual_portfolio',
|
||||
'controls' => 'full',
|
||||
'icon' => 'icon-visual-portfolio',
|
||||
'params' => array(
|
||||
array(
|
||||
'type' => 'dropdown',
|
||||
'heading' => esc_html__( 'Select Layout', 'visual-portfolio' ),
|
||||
'param_name' => 'id',
|
||||
'value' => $data_vc,
|
||||
'description' => '',
|
||||
'admin_label' => true,
|
||||
),
|
||||
array(
|
||||
'type' => 'textfield',
|
||||
'heading' => esc_html__( 'Custom Classes', 'visual-portfolio' ),
|
||||
'param_name' => 'class',
|
||||
'value' => '',
|
||||
'description' => '',
|
||||
),
|
||||
array(
|
||||
'type' => 'css_editor',
|
||||
'heading' => esc_html__( 'CSS', 'visual-portfolio' ),
|
||||
'param_name' => 'vc_css',
|
||||
'group' => esc_html__( 'Design Options', 'visual-portfolio' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_VC();
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/**
|
||||
* WP Rocket Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_WP_Rocket
|
||||
*/
|
||||
class Visual_Portfolio_3rd_WP_Rocket {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_WP_Rocket constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Fix conflict with lazy loading.
|
||||
add_filter( 'rocket_delay_js_exclusions', array( $this, 'rocket_delay_js_exclusions' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Exclude all our lazysizes scripts from delayed loading,
|
||||
* because WP Rocket excluded lazysizes automatically, but not other assets,
|
||||
* this causes problems with lazy loading.
|
||||
*
|
||||
* @param array $excluded excluded scripts.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rocket_delay_js_exclusions( $excluded ) {
|
||||
$excluded[] = 'visual-portfolio/assets/js/lazysizes';
|
||||
|
||||
return $excluded;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_WP_Rocket();
|
@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* Register some fields for WPML.
|
||||
*
|
||||
* @package visual-portfolio/preview
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase, WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_WPML
|
||||
*/
|
||||
class Visual_Portfolio_3rd_WPML {
|
||||
/**
|
||||
* Archive Page.
|
||||
*
|
||||
* @var int $archive_page
|
||||
*/
|
||||
private $archive_page = null;
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_3rd_WPML constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
global $iclTranslationManagement;
|
||||
|
||||
if ( class_exists( 'SitePress' ) ) {
|
||||
add_action( 'init', array( $this, 'init' ), 9 );
|
||||
}
|
||||
|
||||
if ( ! isset( $iclTranslationManagement ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( 'vpf_registered_controls', array( $this, 'make_control_translatable' ) );
|
||||
add_filter( 'vpf_extend_options_before_query_args', array( $this, 'prepare_custom_query_taxonomies' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize archive.
|
||||
*
|
||||
* @see __construct
|
||||
*/
|
||||
public function init() {
|
||||
$this->archive_page = Visual_Portfolio_Settings::get_option( 'portfolio_archive_page', 'vp_general' );
|
||||
if ( isset( $this->archive_page ) && ! empty( $this->archive_page ) ) {
|
||||
add_action( 'wp_insert_post', array( $this, 'set_archive_meta' ), 10, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Archive Meta.
|
||||
*
|
||||
* @param int $post_id - Post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function set_archive_meta( $post_id ) {
|
||||
$translate_page_id = self::get_object_id( $this->archive_page );
|
||||
if ( $translate_page_id === $post_id ) {
|
||||
visual_portfolio()->defer_flush_rewrite_rules();
|
||||
|
||||
update_post_meta( (int) $post_id, '_vp_post_type_mapped', 'portfolio' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get wpml object ID.
|
||||
*
|
||||
* @param int $post_id - Post ID.
|
||||
* @return int
|
||||
*/
|
||||
public static function get_object_id( $post_id ) {
|
||||
if ( class_exists( 'SitePress' ) ) {
|
||||
return apply_filters( 'wpml_object_id', $post_id, 'page', true );
|
||||
}
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make Control Translatable.
|
||||
* https://wpml.org/forums/topic/unable-to-save-custom-field-translation-settings-when-acf-ml-is-installed/
|
||||
*
|
||||
* @param array $controls - controls array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function make_control_translatable( $controls ) {
|
||||
global $iclTranslationManagement;
|
||||
|
||||
$allow_save = false;
|
||||
|
||||
// Prepare Saved Layouts meta fields.
|
||||
foreach ( $controls as $control ) {
|
||||
$name = 'vp_' . $control['name'];
|
||||
|
||||
// Create initial arrays.
|
||||
if ( ! isset( $iclTranslationManagement->settings['custom_fields_translation'] ) ) {
|
||||
$iclTranslationManagement->settings['custom_fields_translation'] = array();
|
||||
}
|
||||
if ( ! isset( $iclTranslationManagement->settings['custom_fields_readonly_config'] ) ) {
|
||||
$iclTranslationManagement->settings['custom_fields_readonly_config'] = array();
|
||||
}
|
||||
|
||||
// Add fields translation.
|
||||
if ( ! isset( $iclTranslationManagement->settings['custom_fields_translation'][ $name ] ) ) {
|
||||
$iclTranslationManagement->settings['custom_fields_translation'][ $name ] = $control['wpml'] ? WPML_TRANSLATE_CUSTOM_FIELD : WPML_COPY_CUSTOM_FIELD;
|
||||
|
||||
$allow_save = true;
|
||||
}
|
||||
|
||||
// Add fields read only.
|
||||
if ( ! in_array( $name, $iclTranslationManagement->settings['custom_fields_readonly_config'], true ) ) {
|
||||
$iclTranslationManagement->settings['custom_fields_readonly_config'][] = $name;
|
||||
|
||||
$allow_save = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Images meta array.
|
||||
if ( ! isset( $iclTranslationManagement->settings['custom_fields_attributes_whitelist']['vp_images'] ) ) {
|
||||
$iclTranslationManagement->settings['custom_fields_attributes_whitelist']['vp_images'] = array(
|
||||
'*' => array(
|
||||
'title' => array(),
|
||||
'description' => array(),
|
||||
'author' => array(),
|
||||
'categories' => array(),
|
||||
),
|
||||
);
|
||||
|
||||
$allow_save = true;
|
||||
}
|
||||
|
||||
if ( $allow_save ) {
|
||||
$iclTranslationManagement->save_settings();
|
||||
}
|
||||
|
||||
return $controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert custom taxonomies to the current language.
|
||||
*
|
||||
* @param array $options - query options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function prepare_custom_query_taxonomies( $options ) {
|
||||
if ( isset( $options['posts_taxonomies'] ) && ! empty( $options['posts_taxonomies'] ) ) {
|
||||
foreach ( $options['posts_taxonomies'] as $k => $taxonomy ) {
|
||||
$taxonomy_data = get_term( $taxonomy );
|
||||
|
||||
if ( isset( $taxonomy_data->taxonomy ) ) {
|
||||
$options['posts_taxonomies'][ $k ] = apply_filters( 'wpml_object_id', $taxonomy, $taxonomy_data->taxonomy, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_WPML();
|
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
/**
|
||||
* Yoast SEO Plugin.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Yoast
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Yoast {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Yoast constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Fixed canonical links.
|
||||
add_filter( 'wpseo_canonical', array( 'Visual_Portfolio_Archive_Mapping', 'get_canonical' ), 12, 1 );
|
||||
add_filter( 'wpseo_opengraph_url', array( 'Visual_Portfolio_Archive_Mapping', 'get_canonical' ), 12, 1 );
|
||||
add_filter( 'wpseo_schema_webpage', array( $this, 'graph_schema_webpage' ), 12, 1 );
|
||||
add_filter( 'wpseo_schema_breadcrumb', array( $this, 'graph_schema_breadcrumb' ), 12, 1 );
|
||||
add_filter( 'wpseo_opengraph_title', array( $this, 'graph_title' ), 12, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows changing webpage graph piece output.
|
||||
*
|
||||
* @param array $webpage_graph_piece - The webpage graph piece to filter.
|
||||
* @return array
|
||||
*/
|
||||
public function graph_schema_webpage( $webpage_graph_piece ) {
|
||||
$webpage_graph_piece['@id'] = Visual_Portfolio_Archive_Mapping::get_canonical( $webpage_graph_piece['@id'] );
|
||||
$webpage_graph_piece['url'] = Visual_Portfolio_Archive_Mapping::get_canonical( $webpage_graph_piece['url'] );
|
||||
$webpage_graph_piece['breadcrumb']['@id'] = Visual_Portfolio_Archive_Mapping::get_canonical_anchor( $webpage_graph_piece['breadcrumb']['@id'] );
|
||||
$webpage_graph_piece['name'] = Visual_Portfolio_Archive_Mapping::get_current_term_title() ?? $webpage_graph_piece['name'];
|
||||
|
||||
if ( ! empty( $webpage_graph_piece['potentialAction'] ) ) {
|
||||
foreach ( $webpage_graph_piece['potentialAction'] as $key => $potential_action ) {
|
||||
if ( isset( $potential_action['target'] ) && ! is_array( $potential_action['target'] ) && isset( $potential_action['@type'] ) && 'ReadAction' === $potential_action['@type'] ) {
|
||||
$webpage_graph_piece['potentialAction'][ $key ]['target'] = Visual_Portfolio_Archive_Mapping::get_canonical( $potential_action['target'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $webpage_graph_piece;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows changing breadcrumb graph piece output.
|
||||
*
|
||||
* @param array $breadcrumb_graph_piece - The breadcrumb graph piece to filter.
|
||||
* @return array
|
||||
*/
|
||||
public function graph_schema_breadcrumb( $breadcrumb_graph_piece ) {
|
||||
$breadcrumb_graph_piece['@id'] = Visual_Portfolio_Archive_Mapping::get_canonical_anchor( $breadcrumb_graph_piece['@id'] );
|
||||
|
||||
return $breadcrumb_graph_piece;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow changing the Yoast SEO generated title.
|
||||
*
|
||||
* @param string $title - Current Graph Title.
|
||||
* @return string
|
||||
*/
|
||||
public function graph_title( $title ) {
|
||||
return Visual_Portfolio_Archive_Mapping::get_current_term_title() ?? $title;
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_3rd_Yoast();
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/**
|
||||
* Avada Theme.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Avada
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Avada {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Avada constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$avada_options = get_option( 'fusion_options' );
|
||||
|
||||
// Important - Avada folder is in uppercase, this is not a mistake.
|
||||
if ( 'Avada' !== get_template() || ! isset( $avada_options['lazy_load'] ) || 'avada' !== $avada_options['lazy_load'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable our lazyload if Avada's lazyload used.
|
||||
add_filter( 'vpf_images_lazyload', '__return_false' );
|
||||
add_filter( 'vpf_enqueue_plugin_lazysizes', '__return_false' );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Avada();
|
@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* Enfold Theme.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Enfold
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Enfold {
|
||||
/**
|
||||
* Cache for lazy loading option
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $lazy_loading_option_cache = null;
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Enfold constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'enfold' !== get_template() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable Enfold lightbox by adding classname.
|
||||
add_filter( 'vpf_extend_portfolio_class', array( $this, 'disable_lightbox_class' ) );
|
||||
|
||||
// Disable our lazyload if Enfold lazyload enabled.
|
||||
add_filter( 'vpf_images_lazyload', array( $this, 'disable_lazy_load' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable Enfold lightbox by adding classname.
|
||||
*
|
||||
* @param string $class - portfolio block classname.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function disable_lightbox_class( $class ) {
|
||||
$class .= ' noLightbox';
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable VPF lazy load if Enfold uses their own.
|
||||
*
|
||||
* @param boolean $return - portfolio block classname.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function disable_lazy_load( $return ) {
|
||||
$enfold_option = '';
|
||||
|
||||
if ( null !== $this->lazy_loading_option_cache ) {
|
||||
$enfold_option = $this->lazy_loading_option_cache;
|
||||
} elseif ( function_exists( 'avia_get_option' ) ) {
|
||||
$enfold_option = avia_get_option( 'lazy_loading', '' );
|
||||
}
|
||||
|
||||
if ( null === $this->lazy_loading_option_cache ) {
|
||||
$this->lazy_loading_option_cache = $enfold_option;
|
||||
}
|
||||
|
||||
if ( '' === $enfold_option ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Enfold();
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/**
|
||||
* Thrive Architect Theme Builder.
|
||||
* This builder overrides page output and we can't enqueue inline dynamic styles using `wp_add_inline_style`
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_3rd_Thrive_Architect
|
||||
*/
|
||||
class Visual_Portfolio_3rd_Thrive_Architect {
|
||||
/**
|
||||
* Visual_Portfolio_3rd_Thrive_Architect constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'init' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init action.
|
||||
*/
|
||||
public function init() {
|
||||
if ( ! function_exists( 'tcb_custom_editable_content' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( 'vpf_enqueue_dynamic_styles_inline_style', '__return_false' );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_3rd_Thrive_Architect();
|
3847
wp-content/plugins/visual-portfolio/classes/class-admin.php
Normal file
3847
wp-content/plugins/visual-portfolio/classes/class-admin.php
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
137
wp-content/plugins/visual-portfolio/classes/class-ask-review.php
Normal file
137
wp-content/plugins/visual-portfolio/classes/class-ask-review.php
Normal file
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* Ask Review Notice.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Ask_Review_Notice
|
||||
*/
|
||||
class Visual_Portfolio_Ask_Review_Notice {
|
||||
/**
|
||||
* Option name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $option_name = 'vpf_ask_review_notice';
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Ask_Review_Notice constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'wp_ajax_vpf_dismiss_ask_review_notice', array( $this, 'ajax_vpf_dismiss_ask_review_notice' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we can display notice.
|
||||
*/
|
||||
public function is_notice_allowed() {
|
||||
$state = get_site_option( $this->option_name . '_state' );
|
||||
$time = (int) get_site_option( $this->option_name . '_time' );
|
||||
|
||||
if ( 'yes' === $state || 'already' === $state ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save current time if nothing saved.
|
||||
if ( ! $time ) {
|
||||
$time = time();
|
||||
update_site_option( $this->option_name . '_time', $time );
|
||||
}
|
||||
|
||||
// Allow notice if plugin used for more then 2 weeks.
|
||||
if ( $time < strtotime( '-14 days' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display admin notice if needed.
|
||||
*/
|
||||
public function admin_notices() {
|
||||
if ( ! $this->is_notice_allowed() ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="notice notice-info vpf-admin-notice" id="vpf-review-plugin-notice">
|
||||
<div class="vpf-admin-notice-icon">
|
||||
<i class="dashicons-visual-portfolio"></i>
|
||||
</div>
|
||||
<div class="vpf-admin-notice-content">
|
||||
<h3><?php esc_html_e( 'Satisfied using Visual Portfolio?', 'visual-portfolio' ); ?></h3>
|
||||
<p>
|
||||
<?php
|
||||
// translators: %s - Plugin name.
|
||||
echo wp_kses_post( sprintf( __( 'Hey, we noticed you\'ve been using %s for more than two weeks now – that\'s awesome!', 'visual-portfolio' ), '<strong>' . _x( 'Visual Portfolio', 'plugin name inside the review notice', 'visual-portfolio' ) . '</strong>' ) );
|
||||
?>
|
||||
<br>
|
||||
<?php esc_html_e( 'Could you please do us a BIG favor and give it a rating on WordPress.org to help us spread the word and boost our motivation?', 'visual-portfolio' ); ?>
|
||||
</p>
|
||||
<p>
|
||||
<a href="https://wordpress.org/support/plugin/visual-portfolio/reviews/?filter=5#new-post" class="vpf-review-plugin-notice-dismiss" data-vpf-review-action="yes" target="_blank" rel="noopener noreferrer">
|
||||
<strong>
|
||||
<?php esc_html_e( 'Yes, you deserve it', 'visual-portfolio' ); ?>
|
||||
</strong>
|
||||
</a>
|
||||
<br>
|
||||
<a href="#" class="vpf-review-plugin-notice-dismiss" data-vpf-review-action="later">
|
||||
<?php esc_html_e( 'No, maybe later', 'visual-portfolio' ); ?>
|
||||
</a><br>
|
||||
<a href="#" class="vpf-review-plugin-notice-dismiss" data-vpf-review-action="already">
|
||||
<?php esc_html_e( 'I already did', 'visual-portfolio' ); ?>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue script.
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
if ( is_customize_preview() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
Visual_Portfolio_Assets::enqueue_script( 'visual-portfolio-ask-review-notice', 'build/assets/admin/js/ask-review-notice' );
|
||||
wp_localize_script(
|
||||
'visual-portfolio-ask-review-notice',
|
||||
'VPAskReviewNotice',
|
||||
array(
|
||||
'nonce' => wp_create_nonce( $this->option_name ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles Ajax request to persist notices dismissal.
|
||||
* Uses check_ajax_referer to verify nonce.
|
||||
*/
|
||||
public function ajax_vpf_dismiss_ask_review_notice() {
|
||||
check_ajax_referer( $this->option_name, 'nonce' );
|
||||
|
||||
$type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : 'yes';
|
||||
|
||||
update_site_option( $this->option_name . '_state', $type );
|
||||
|
||||
// Update time if user clicked "No, maybe later" button.
|
||||
if ( 'later' === $type ) {
|
||||
$time = time();
|
||||
update_site_option( $this->option_name . '_time', $time );
|
||||
}
|
||||
|
||||
wp_die();
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Ask_Review_Notice();
|
945
wp-content/plugins/visual-portfolio/classes/class-assets.php
Normal file
945
wp-content/plugins/visual-portfolio/classes/class-assets.php
Normal file
@ -0,0 +1,945 @@
|
||||
<?php
|
||||
/**
|
||||
* Assets static and dynamic.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Assets
|
||||
*/
|
||||
class Visual_Portfolio_Assets {
|
||||
/**
|
||||
* List with stored assets.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $stored_assets = array(
|
||||
'script' => array(),
|
||||
'style' => array(),
|
||||
'template_style' => array(),
|
||||
);
|
||||
|
||||
/**
|
||||
* When styles already included in head.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $head_css_included = false;
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Assets constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// template_redirect is used instead of wp_enqueue_scripts just because some plugins use it and included an old isotope plugin. So, it was conflicted.
|
||||
add_action( 'template_redirect', array( $this, 'register_scripts' ), 9 );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_head_assets' ), 9 );
|
||||
|
||||
add_action( 'template_redirect', array( $this, 'popup_custom_styles' ) );
|
||||
add_action( 'template_redirect', array( $this, 'assets_for_default_wordpress_images' ) );
|
||||
|
||||
add_action( 'wp_footer', array( $this, 'wp_enqueue_foot_assets' ) );
|
||||
|
||||
add_action( 'wp_head', array( $this, 'localize_global_data' ) );
|
||||
|
||||
// noscript tag.
|
||||
add_action( 'wp_head', array( $this, 'add_noscript_styles' ) );
|
||||
|
||||
// parse shortcodes from post content.
|
||||
add_filter( 'wp', array( $this, 'maybe_parse_shortcodes_from_content' ), 10 );
|
||||
add_action( 'vpf_parse_blocks', array( $this, 'maybe_parse_blocks_from_content' ), 11 );
|
||||
|
||||
// enqueue runtime.
|
||||
add_action( 'enqueue_block_editor_assets', 'Visual_Portfolio_Assets::enqueue_runtime', 11 );
|
||||
add_action( 'wp_enqueue_scripts', 'Visual_Portfolio_Assets::enqueue_runtime', 8 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Webpack HMR file available.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_webpack_hmr_support() {
|
||||
return file_exists( visual_portfolio()->plugin_path . '/build/runtime.js' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue runtime script.
|
||||
*/
|
||||
public static function enqueue_runtime() {
|
||||
// HMR Webpack.
|
||||
if ( self::is_webpack_hmr_support() ) {
|
||||
self::enqueue_script( 'visual-portfolio-runtime', 'build/runtime', array(), null, false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get .asset.php file data.
|
||||
*
|
||||
* @param string $filepath asset file path.
|
||||
* @param string $filetype asset file type [style|script].
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_asset_file( $filepath, $filetype = '' ) {
|
||||
$asset_path = visual_portfolio()->plugin_path . '/' . str_replace( '.min', '', $filepath ) . '.asset.php';
|
||||
|
||||
if ( file_exists( $asset_path ) ) {
|
||||
// phpcs:ignore WPThemeReview.CoreFunctionality.FileInclude.FileIncludeFound
|
||||
return include $asset_path;
|
||||
} elseif ( ! empty( $filetype ) ) {
|
||||
$file_ext = 'style' === $filetype ? 'css' : 'js';
|
||||
$full_file_path = visual_portfolio()->plugin_path . '/' . $filepath . '.' . $file_ext;
|
||||
$file_version = file_exists( $full_file_path ) ? filemtime( $full_file_path ) : null;
|
||||
}
|
||||
|
||||
return array(
|
||||
'dependencies' => array(),
|
||||
'version' => $file_version ?? VISUAL_PORTFOLIO_VERSION,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register script.
|
||||
*
|
||||
* @param string $name asset name.
|
||||
* @param string $path file path.
|
||||
* @param array $dependencies asset dependencies.
|
||||
* @param string $version asset version.
|
||||
* @param boolean $in_footer render in footer.
|
||||
*/
|
||||
public static function register_script( $name, $path, $dependencies = array(), $version = null, $in_footer = true ) {
|
||||
$script_data = self::get_asset_file( $path, 'script' );
|
||||
|
||||
if ( ! empty( $dependencies ) ) {
|
||||
$script_data['dependencies'] = array_unique(
|
||||
array_merge(
|
||||
$script_data['dependencies'],
|
||||
$dependencies
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
wp_register_script(
|
||||
$name,
|
||||
visual_portfolio()->plugin_url . $path . '.js',
|
||||
$script_data['dependencies'],
|
||||
$version ?? $script_data['version'],
|
||||
$in_footer
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue script.
|
||||
*
|
||||
* @param string $name asset name.
|
||||
* @param string $path file path.
|
||||
* @param array $dependencies asset dependencies.
|
||||
* @param string $version asset version.
|
||||
* @param boolean $in_footer render in footer.
|
||||
*/
|
||||
public static function enqueue_script( $name, $path, $dependencies = array(), $version = null, $in_footer = true ) {
|
||||
self::register_script( $name, $path, $dependencies, $version, $in_footer );
|
||||
|
||||
wp_enqueue_script( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register style
|
||||
*
|
||||
* @param string $name asset name.
|
||||
* @param string $path file path.
|
||||
* @param array $dependencies asset dependencies.
|
||||
* @param string $version asset version.
|
||||
*/
|
||||
public static function register_style( $name, $path, $dependencies = array(), $version = null ) {
|
||||
$style_data = self::get_asset_file( $path, 'style' );
|
||||
|
||||
wp_register_style(
|
||||
$name,
|
||||
visual_portfolio()->plugin_url . $path . '.css',
|
||||
$dependencies,
|
||||
$version ?? $style_data['version']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue style
|
||||
*
|
||||
* @param string $name asset name.
|
||||
* @param string $path file path.
|
||||
* @param array $dependencies asset dependencies.
|
||||
* @param string $version asset version.
|
||||
*/
|
||||
public static function enqueue_style( $name, $path, $dependencies = array(), $version = null ) {
|
||||
self::register_style( $name, $path, $dependencies, $version );
|
||||
|
||||
wp_enqueue_style( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Store used assets, so we can enqueue it later.
|
||||
*
|
||||
* @param string $name - asset name.
|
||||
* @param bool|string $value - just enqueue flag or url to asset.
|
||||
* @param string $type - assets type [script|style|template_style].
|
||||
* @param int $priority - asset enqueue priority.
|
||||
*/
|
||||
public static function store_used_assets( $name, $value = true, $type = 'script', $priority = 10 ) {
|
||||
if ( ! isset( self::$stored_assets[ $type ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isset( self::$stored_assets[ $type ][ $name ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$stored_assets[ $type ][ $name ] = array(
|
||||
'value' => $value,
|
||||
'priority' => $priority,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove stored assets. May be used for advanced functionality.
|
||||
*
|
||||
* @param string $name - asset name.
|
||||
* @param string $type - assets type [script|style|template_style].
|
||||
*/
|
||||
public static function remove_stored_assets( $name, $type = 'script' ) {
|
||||
if ( ! isset( self::$stored_assets[ $type ][ $name ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
unset( self::$stored_assets[ $type ][ $name ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue stored assets.
|
||||
*
|
||||
* @param string $type - assets type [script|style|template_style].
|
||||
*/
|
||||
public static function enqueue_stored_assets( $type = 'script' ) {
|
||||
if ( ! isset( self::$stored_assets[ $type ] ) || empty( self::$stored_assets[ $type ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
uasort(
|
||||
self::$stored_assets[ $type ],
|
||||
function ( $a, $b ) {
|
||||
if ( $a === $b ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( isset( $a['priority'] ) && isset( $b['priority'] ) ) {
|
||||
return $a['priority'] < $b['priority'] ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
|
||||
foreach ( self::$stored_assets[ $type ] as $name => $data ) {
|
||||
if ( isset( $data['value'] ) && $data['value'] ) {
|
||||
if ( 'script' === $type ) {
|
||||
wp_enqueue_script( $name, '', array(), VISUAL_PORTFOLIO_VERSION, true );
|
||||
} elseif ( is_string( $data['value'] ) ) {
|
||||
// Don't provide version for template style,
|
||||
// it will be added automatically using `filemtime`.
|
||||
visual_portfolio()->include_template_style( $name, $data['value'], array() );
|
||||
} else {
|
||||
wp_enqueue_style( $name, '', array(), VISUAL_PORTFOLIO_VERSION );
|
||||
}
|
||||
|
||||
self::$stored_assets[ $type ]['value'] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue assets based on layout data.
|
||||
*
|
||||
* @param array $options - layout data.
|
||||
*/
|
||||
public static function enqueue( $options ) {
|
||||
$options = Visual_Portfolio_Get::get_options( $options );
|
||||
|
||||
do_action( 'vpf_before_assets_enqueue', $options, $options['id'] );
|
||||
|
||||
self::store_used_assets( 'visual-portfolio', true, 'style', 9 );
|
||||
self::store_used_assets( 'visual-portfolio-notices-default', true, 'style', 9 );
|
||||
self::store_used_assets(
|
||||
'visual-portfolio-notices-default',
|
||||
'notices/style',
|
||||
'template_style'
|
||||
);
|
||||
|
||||
self::store_used_assets( 'visual-portfolio-errors-default', true, 'style', 9 );
|
||||
self::store_used_assets(
|
||||
'visual-portfolio-errors-default',
|
||||
'errors/style',
|
||||
'template_style'
|
||||
);
|
||||
|
||||
// Additional styles for Elementor.
|
||||
if ( class_exists( '\Elementor\Plugin' ) ) {
|
||||
self::store_used_assets( 'visual-portfolio-elementor', true, 'style', 9 );
|
||||
}
|
||||
|
||||
self::store_used_assets( 'visual-portfolio', true, 'script', 12 );
|
||||
|
||||
// Layout.
|
||||
switch ( $options['layout'] ) {
|
||||
case 'masonry':
|
||||
self::store_used_assets( 'visual-portfolio-layout-masonry', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-layout-masonry', true, 'style' );
|
||||
break;
|
||||
case 'grid':
|
||||
self::store_used_assets( 'visual-portfolio-layout-grid', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-layout-grid', true, 'style' );
|
||||
break;
|
||||
case 'tiles':
|
||||
self::store_used_assets( 'visual-portfolio-layout-tiles', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-layout-tiles', true, 'style' );
|
||||
break;
|
||||
case 'justified':
|
||||
self::store_used_assets( 'visual-portfolio-layout-justified', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-layout-justified', true, 'style' );
|
||||
break;
|
||||
case 'slider':
|
||||
self::store_used_assets( 'visual-portfolio-layout-slider', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-layout-slider', true, 'style' );
|
||||
break;
|
||||
}
|
||||
|
||||
// Custom Scrollbar.
|
||||
self::store_used_assets( 'visual-portfolio-custom-scrollbar', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-custom-scrollbar', true, 'style' );
|
||||
|
||||
// Items Style.
|
||||
if ( $options['items_style'] ) {
|
||||
$items_style_pref = '';
|
||||
|
||||
if ( 'default' !== $options['items_style'] ) {
|
||||
$items_style_pref = '/' . $options['items_style'];
|
||||
}
|
||||
|
||||
switch ( $options['items_style'] ) {
|
||||
case 'fly':
|
||||
self::store_used_assets( 'visual-portfolio-items-style-fly', true, 'script' );
|
||||
break;
|
||||
}
|
||||
|
||||
self::store_used_assets(
|
||||
'visual-portfolio-items-style-' . $options['items_style'],
|
||||
'items-list/items-style' . $items_style_pref . '/style',
|
||||
'template_style'
|
||||
);
|
||||
}
|
||||
|
||||
// Images Lazy Loading.
|
||||
if ( Visual_Portfolio_Settings::get_option( 'lazy_loading', 'vp_images' ) ) {
|
||||
self::enqueue_lazyload_assets();
|
||||
}
|
||||
|
||||
// Popup.
|
||||
if ( 'popup_gallery' === $options['items_click_action'] ) {
|
||||
self::enqueue_popup_assets();
|
||||
}
|
||||
|
||||
$layout_elements = array();
|
||||
|
||||
if ( isset( $options['layout_elements']['top']['elements'] ) ) {
|
||||
$layout_elements = array_merge( $layout_elements, $options['layout_elements']['top']['elements'] );
|
||||
}
|
||||
if ( isset( $options['layout_elements']['bottom']['elements'] ) ) {
|
||||
$layout_elements = array_merge( $layout_elements, $options['layout_elements']['bottom']['elements'] );
|
||||
}
|
||||
|
||||
// Filter.
|
||||
if ( in_array( 'filter', $layout_elements, true ) ) {
|
||||
$filter_style_pref = '';
|
||||
|
||||
if ( 'default' !== $options['filter'] ) {
|
||||
$filter_style_pref = '/' . $options['filter'];
|
||||
}
|
||||
|
||||
self::store_used_assets(
|
||||
'visual-portfolio-filter-' . $options['filter'],
|
||||
'items-list/filter' . $filter_style_pref . '/style',
|
||||
'template_style'
|
||||
);
|
||||
}
|
||||
|
||||
// Sort.
|
||||
if ( in_array( 'sort', $layout_elements, true ) ) {
|
||||
$sort_style_pref = '';
|
||||
|
||||
if ( 'default' !== $options['sort'] ) {
|
||||
$sort_style_pref = '/' . $options['sort'];
|
||||
}
|
||||
|
||||
self::store_used_assets(
|
||||
'visual-portfolio-sort-' . $options['sort'],
|
||||
'items-list/sort' . $sort_style_pref . '/style',
|
||||
'template_style'
|
||||
);
|
||||
}
|
||||
|
||||
// Pagination.
|
||||
if ( in_array( 'pagination', $layout_elements, true ) ) {
|
||||
$pagination_style_pref = '';
|
||||
|
||||
if ( 'default' !== $options['pagination_style'] ) {
|
||||
$pagination_style_pref = '/' . $options['pagination_style'];
|
||||
}
|
||||
|
||||
// Infinite scroll pagination script.
|
||||
if ( 'infinite' === $options['pagination'] ) {
|
||||
self::store_used_assets( 'visual-portfolio-pagination-infinite', true, 'script' );
|
||||
}
|
||||
|
||||
// Minimal page pagination helpful script.
|
||||
if ( 'minimal' === $options['pagination_style'] && 'paged' === $options['pagination'] ) {
|
||||
self::store_used_assets( 'visual-portfolio-pagination-minimal-paged', true, 'script' );
|
||||
}
|
||||
|
||||
self::store_used_assets(
|
||||
'visual-portfolio-pagination-' . $options['pagination_style'],
|
||||
'items-list/pagination' . $pagination_style_pref . '/style',
|
||||
'template_style'
|
||||
);
|
||||
}
|
||||
|
||||
// Dynamic styles.
|
||||
// Always add it even if no custom CSS available to better render dynamic styles in preview.
|
||||
$dynamic_styles = Visual_Portfolio_Controls_Dynamic_CSS::get( $options );
|
||||
$controls_css_handle = 'vp-dynamic-styles-' . $options['id'];
|
||||
|
||||
if ( ! wp_style_is( $controls_css_handle, 'enqueued' ) ) {
|
||||
$dynamic_styles = wp_kses( $dynamic_styles, array( '\'', '\"' ) );
|
||||
$dynamic_styles = str_replace( '>', '>', $dynamic_styles );
|
||||
|
||||
$dynamic_styles_inline_style = apply_filters( 'vpf_enqueue_dynamic_styles_inline_style', ! self::$head_css_included, $dynamic_styles, $controls_css_handle );
|
||||
|
||||
// Enqueue custom CSS.
|
||||
if ( $dynamic_styles_inline_style ) {
|
||||
wp_register_style( $controls_css_handle, false, array(), VISUAL_PORTFOLIO_VERSION );
|
||||
wp_enqueue_style( $controls_css_handle );
|
||||
wp_add_inline_style( $controls_css_handle, $dynamic_styles ? $dynamic_styles : ' ' );
|
||||
|
||||
// Enqueue JS instead of CSS when rendering in <body> to prevent W3C errors.
|
||||
} elseif ( ! wp_script_is( $controls_css_handle, 'enqueued' ) ) {
|
||||
wp_register_script( $controls_css_handle, false, array(), VISUAL_PORTFOLIO_VERSION, true );
|
||||
wp_enqueue_script( $controls_css_handle );
|
||||
wp_add_inline_script(
|
||||
$controls_css_handle,
|
||||
'(function(){
|
||||
var styleTag = document.createElement("style");
|
||||
styleTag.id = "' . esc_attr( $controls_css_handle ) . '-inline-css";
|
||||
styleTag.innerHTML = ' . wp_json_encode( $dynamic_styles ? $dynamic_styles : ' ' ) . ';
|
||||
document.body.appendChild(styleTag);
|
||||
}());'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
self::store_used_assets( $controls_css_handle, true, 'style' );
|
||||
|
||||
do_action( 'vpf_after_assets_enqueue', $options, $options['id'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue popup assets.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function enqueue_popup_assets() {
|
||||
$popup_vendor = Visual_Portfolio_Settings::get_option( 'vendor', 'vp_popup_gallery' );
|
||||
|
||||
// Photoswipe.
|
||||
if ( 'photoswipe' === $popup_vendor && apply_filters( 'vpf_enqueue_plugin_photoswipe', true ) ) {
|
||||
self::store_used_assets( 'visual-portfolio-plugin-photoswipe', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-popup-photoswipe', true, 'style' );
|
||||
|
||||
// Fancybox.
|
||||
} elseif ( 'fancybox' === $popup_vendor && apply_filters( 'vpf_enqueue_plugin_fancybox', true ) ) {
|
||||
self::store_used_assets( 'visual-portfolio-plugin-fancybox', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-popup-fancybox', true, 'style' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue lazyload assets.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function enqueue_lazyload_assets() {
|
||||
// Disable lazyload assets using filter.
|
||||
// Same filter used in `class-images.php`.
|
||||
if ( ! apply_filters( 'vpf_images_lazyload', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::store_used_assets( 'visual-portfolio-lazyload', true, 'script' );
|
||||
self::store_used_assets( 'visual-portfolio-lazyload', true, 'style' );
|
||||
|
||||
// lazy load fallback.
|
||||
add_action( 'wp_head', 'Visual_Portfolio_Assets::add_lazyload_fallback_script' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register scripts that will be used in the future when portfolio will be printed.
|
||||
*/
|
||||
public function register_scripts() {
|
||||
$vp_deps = array( 'imagesloaded' );
|
||||
$vp_style_deps = array();
|
||||
|
||||
$popup_vendor = Visual_Portfolio_Settings::get_option( 'vendor', 'vp_popup_gallery' );
|
||||
|
||||
do_action( 'vpf_before_assets_register' );
|
||||
|
||||
// Isotope.
|
||||
if ( apply_filters( 'vpf_enqueue_plugin_isotope', true ) ) {
|
||||
self::register_script( 'isotope', 'assets/vendor/isotope-layout/dist/isotope.pkgd.min', array( 'jquery' ), '3.0.6' );
|
||||
}
|
||||
|
||||
// fjGallery.
|
||||
if ( apply_filters( 'vpf_enqueue_plugin_flickr_justified_gallery', true ) ) {
|
||||
self::register_script( 'flickr-justified-gallery', 'assets/vendor/flickr-justified-gallery/dist/fjGallery.min', array( 'jquery' ), '2.1.2' );
|
||||
}
|
||||
|
||||
// PhotoSwipe.
|
||||
if ( 'photoswipe' === $popup_vendor && apply_filters( 'vpf_enqueue_plugin_photoswipe', true ) ) {
|
||||
self::register_style( 'photoswipe', 'assets/vendor/photoswipe/dist/photoswipe', array(), '4.1.3' );
|
||||
self::register_style( 'photoswipe-default-skin', 'assets/vendor/photoswipe/dist/default-skin/default-skin', array( 'photoswipe' ), '4.1.3' );
|
||||
self::register_script( 'photoswipe', 'assets/vendor/photoswipe/dist/photoswipe.min', array( 'jquery' ), '4.1.3' );
|
||||
self::register_script( 'photoswipe-ui-default', 'assets/vendor/photoswipe/dist/photoswipe-ui-default.min', array( 'jquery', 'photoswipe' ), '4.1.3' );
|
||||
|
||||
// Fancybox.
|
||||
} elseif ( 'fancybox' === $popup_vendor && apply_filters( 'vpf_enqueue_plugin_fancybox', true ) ) {
|
||||
self::register_style( 'fancybox', 'assets/vendor/fancybox/dist/jquery.fancybox.min', array(), '3.5.7' );
|
||||
self::register_script( 'fancybox', 'assets/vendor/fancybox/dist/jquery.fancybox.min', array( 'jquery' ), '3.5.7' );
|
||||
}
|
||||
|
||||
// Swiper.
|
||||
if ( apply_filters( 'vpf_enqueue_plugin_swiper', true ) ) {
|
||||
self::register_style( 'swiper', 'assets/vendor/swiper/swiper-bundle.min', array(), '8.4.7' );
|
||||
self::register_script( 'swiper', 'assets/vendor/swiper/swiper-bundle.min', array(), '8.4.7' );
|
||||
}
|
||||
|
||||
// Simplebar.
|
||||
if ( apply_filters( 'vpf_enqueue_plugin_simplebar', true ) ) {
|
||||
self::register_style( 'simplebar', 'assets/vendor/simplebar/dist/simplebar.min', array(), '5.3.0' );
|
||||
self::register_script( 'simplebar', 'assets/vendor/simplebar/dist/simplebar.min', array(), '5.3.0' );
|
||||
}
|
||||
|
||||
// LazySizes.
|
||||
if ( apply_filters( 'vpf_enqueue_plugin_lazysizes', true ) ) {
|
||||
self::register_script( 'lazysizes-config', 'build/assets/js/lazysizes-cfg', array() );
|
||||
self::register_script( 'lazysizes-object-fit-cover', 'build/assets/js/lazysizes-object-fit-cover', array(), '4.1.0' );
|
||||
self::register_script( 'lazysizes-swiper-duplicates-load', 'build/assets/js/lazysizes-swiper-duplicates-load', array() );
|
||||
self::register_script( 'lazysizes', 'assets/vendor/lazysizes/lazysizes.min', array( 'lazysizes-config', 'lazysizes-object-fit-cover', 'lazysizes-swiper-duplicates-load' ), '5.3.2' );
|
||||
}
|
||||
|
||||
// Visual Portfolio CSS.
|
||||
$vp_styles = array(
|
||||
'visual-portfolio' => array( 'build/assets/css/main', $vp_style_deps ),
|
||||
'visual-portfolio-elementor' => array( 'build/assets/css/elementor', array( 'visual-portfolio' ) ),
|
||||
'visual-portfolio-lazyload' => array( 'build/assets/css/lazyload', array() ),
|
||||
'visual-portfolio-custom-scrollbar' => array( 'build/assets/css/custom-scrollbar', array( 'simplebar' ) ),
|
||||
'visual-portfolio-layout-justified' => array( 'build/assets/css/layout-justified', array( 'visual-portfolio' ) ),
|
||||
'visual-portfolio-layout-slider' => array( 'build/assets/css/layout-slider', array( 'visual-portfolio', 'swiper' ) ),
|
||||
'visual-portfolio-layout-masonry' => array( 'build/assets/css/layout-masonry', array( 'visual-portfolio' ) ),
|
||||
'visual-portfolio-layout-grid' => array( 'build/assets/css/layout-grid', array( 'visual-portfolio' ) ),
|
||||
'visual-portfolio-layout-tiles' => array( 'build/assets/css/layout-tiles', array( 'visual-portfolio' ) ),
|
||||
'visual-portfolio-popup-fancybox' => array( 'build/assets/css/popup-fancybox', array( 'visual-portfolio', 'fancybox' ) ),
|
||||
'visual-portfolio-popup-photoswipe' => array( 'build/assets/css/popup-photoswipe', array( 'visual-portfolio', 'photoswipe-default-skin' ) ),
|
||||
);
|
||||
|
||||
foreach ( $vp_styles as $name => $data ) {
|
||||
self::register_style( $name, $data[0], $data[1] );
|
||||
wp_style_add_data( $name, 'rtl', 'replace' );
|
||||
wp_style_add_data( $name, 'suffix', '.min' );
|
||||
}
|
||||
|
||||
// Visual Portfolio JS.
|
||||
$vp_scripts = array(
|
||||
'visual-portfolio' => array(
|
||||
'build/assets/js/main',
|
||||
$vp_deps,
|
||||
),
|
||||
'visual-portfolio-plugin-isotope' => array(
|
||||
'build/assets/js/plugin-isotope',
|
||||
array(
|
||||
'isotope',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-plugin-fj-gallery' => array(
|
||||
'build/assets/js/plugin-fj-gallery',
|
||||
array(
|
||||
'flickr-justified-gallery',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-plugin-swiper' => array(
|
||||
'build/assets/js/plugin-swiper',
|
||||
array(
|
||||
'swiper',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-custom-scrollbar' => array(
|
||||
'build/assets/js/custom-scrollbar',
|
||||
array(
|
||||
'simplebar',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-lazyload' => array(
|
||||
'build/assets/js/lazyload',
|
||||
array(
|
||||
'lazysizes',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-popup-gallery' => array(
|
||||
'build/assets/js/popup-gallery',
|
||||
),
|
||||
'visual-portfolio-plugin-photoswipe' => array(
|
||||
'build/assets/js/plugin-photoswipe',
|
||||
array(
|
||||
'photoswipe-ui-default',
|
||||
'visual-portfolio-popup-gallery',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-plugin-fancybox' => array(
|
||||
'build/assets/js/plugin-fancybox',
|
||||
array(
|
||||
'fancybox',
|
||||
'visual-portfolio-popup-gallery',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-layout-masonry' => array(
|
||||
'build/assets/js/layout-masonry',
|
||||
array(
|
||||
'visual-portfolio-plugin-isotope',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-layout-grid' => array(
|
||||
'build/assets/js/layout-grid',
|
||||
array(
|
||||
'visual-portfolio-plugin-isotope',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-layout-tiles' => array(
|
||||
'build/assets/js/layout-tiles',
|
||||
array(
|
||||
'visual-portfolio-plugin-isotope',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-layout-justified' => array(
|
||||
'build/assets/js/layout-justified',
|
||||
array(
|
||||
'visual-portfolio-plugin-fj-gallery',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-layout-slider' => array(
|
||||
'build/assets/js/layout-slider',
|
||||
array(
|
||||
'visual-portfolio-plugin-swiper',
|
||||
),
|
||||
),
|
||||
'visual-portfolio-items-style-fly' => array(
|
||||
'build/assets/js/items-style-fly',
|
||||
),
|
||||
'visual-portfolio-pagination-infinite' => array(
|
||||
'build/assets/js/pagination-infinite',
|
||||
),
|
||||
'visual-portfolio-pagination-minimal-paged' => array(
|
||||
'build/assets/js/pagination-minimal-paged',
|
||||
),
|
||||
);
|
||||
|
||||
foreach ( $vp_scripts as $name => $data ) {
|
||||
self::register_script( $name, $data[0], $data[1] ?? array() );
|
||||
}
|
||||
|
||||
do_action( 'vpf_after_assets_register' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic styles for popup gallery plugins.
|
||||
*/
|
||||
public function popup_custom_styles() {
|
||||
$bg_color = Visual_Portfolio_Settings::get_option( 'background_color', 'vp_popup_gallery' );
|
||||
|
||||
if ( $bg_color ) {
|
||||
wp_add_inline_style( 'visual-portfolio-popup-fancybox', '.vp-fancybox .fancybox-bg { background-color: ' . esc_attr( $bg_color ) . '; }' );
|
||||
wp_add_inline_style( 'visual-portfolio-popup-photoswipe', '.vp-pswp .pswp__bg { background-color: ' . esc_attr( $bg_color ) . '; }' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add popup for default WordPress images.
|
||||
*/
|
||||
public function assets_for_default_wordpress_images() {
|
||||
if ( Visual_Portfolio_Settings::get_option( 'enable_on_wordpress_images', 'vp_popup_gallery' ) ) {
|
||||
self::enqueue_popup_assets();
|
||||
}
|
||||
if ( 'full' === Visual_Portfolio_Settings::get_option( 'lazy_loading', 'vp_images' ) ) {
|
||||
self::enqueue_lazyload_assets();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add global Visual Portfolio data.
|
||||
*/
|
||||
public function localize_global_data() {
|
||||
$data = array(
|
||||
'version' => VISUAL_PORTFOLIO_VERSION,
|
||||
'pro' => false,
|
||||
'__' => array(
|
||||
// translators: %s - plugin name.
|
||||
'couldnt_retrieve_vp' => sprintf( __( 'Couldn\'t retrieve %s ID.', 'visual-portfolio' ), visual_portfolio()->plugin_name ),
|
||||
|
||||
'pswp_close' => esc_attr__( 'Close (Esc)', 'visual-portfolio' ),
|
||||
'pswp_share' => esc_attr__( 'Share', 'visual-portfolio' ),
|
||||
'pswp_fs' => esc_attr__( 'Toggle fullscreen', 'visual-portfolio' ),
|
||||
'pswp_zoom' => esc_attr__( 'Zoom in/out', 'visual-portfolio' ),
|
||||
'pswp_prev' => esc_attr__( 'Previous (arrow left)', 'visual-portfolio' ),
|
||||
'pswp_next' => esc_attr__( 'Next (arrow right)', 'visual-portfolio' ),
|
||||
'pswp_share_fb' => esc_attr__( 'Share on Facebook', 'visual-portfolio' ),
|
||||
'pswp_share_tw' => esc_attr__( 'Tweet', 'visual-portfolio' ),
|
||||
'pswp_share_pin' => esc_attr__( 'Pin it', 'visual-portfolio' ),
|
||||
|
||||
'fancybox_close' => esc_attr__( 'Close', 'visual-portfolio' ),
|
||||
'fancybox_next' => esc_attr__( 'Next', 'visual-portfolio' ),
|
||||
'fancybox_prev' => esc_attr__( 'Previous', 'visual-portfolio' ),
|
||||
'fancybox_error' => __( 'The requested content cannot be loaded. <br /> Please try again later.', 'visual-portfolio' ),
|
||||
'fancybox_play_start' => esc_attr__( 'Start slideshow', 'visual-portfolio' ),
|
||||
'fancybox_play_stop' => esc_attr__( 'Pause slideshow', 'visual-portfolio' ),
|
||||
'fancybox_full_screen' => esc_attr__( 'Full screen', 'visual-portfolio' ),
|
||||
'fancybox_thumbs' => esc_attr__( 'Thumbnails', 'visual-portfolio' ),
|
||||
'fancybox_download' => esc_attr__( 'Download', 'visual-portfolio' ),
|
||||
'fancybox_share' => esc_attr__( 'Share', 'visual-portfolio' ),
|
||||
'fancybox_zoom' => esc_attr__( 'Zoom', 'visual-portfolio' ),
|
||||
),
|
||||
'settingsPopupGallery' => array(
|
||||
// Default WordPress Images.
|
||||
'enable_on_wordpress_images' => Visual_Portfolio_Settings::get_option( 'enable_on_wordpress_images', 'vp_popup_gallery' ),
|
||||
|
||||
// Vendor.
|
||||
'vendor' => Visual_Portfolio_Settings::get_option( 'vendor', 'vp_popup_gallery' ),
|
||||
|
||||
// Deep Linking.
|
||||
'deep_linking' => Visual_Portfolio_Settings::get_option( 'deep_linking', 'vp_popup_gallery' ),
|
||||
'deep_linking_url_to_share_images' => Visual_Portfolio_Settings::get_option( 'deep_linking_url_to_share_images', 'vp_popup_gallery' ),
|
||||
|
||||
// General.
|
||||
'show_arrows' => Visual_Portfolio_Settings::get_option( 'show_arrows', 'vp_popup_gallery' ),
|
||||
'show_counter' => Visual_Portfolio_Settings::get_option( 'show_counter', 'vp_popup_gallery' ),
|
||||
'show_zoom_button' => Visual_Portfolio_Settings::get_option( 'show_zoom_button', 'vp_popup_gallery' ),
|
||||
'show_fullscreen_button' => Visual_Portfolio_Settings::get_option( 'show_fullscreen_button', 'vp_popup_gallery' ),
|
||||
'show_share_button' => Visual_Portfolio_Settings::get_option( 'show_share_button', 'vp_popup_gallery' ),
|
||||
'show_close_button' => Visual_Portfolio_Settings::get_option( 'show_close_button', 'vp_popup_gallery' ),
|
||||
|
||||
// Fancybox.
|
||||
'show_thumbs' => Visual_Portfolio_Settings::get_option( 'show_thumbs', 'vp_popup_gallery' ),
|
||||
'show_download_button' => Visual_Portfolio_Settings::get_option( 'show_download_button', 'vp_popup_gallery' ),
|
||||
'show_slideshow' => Visual_Portfolio_Settings::get_option( 'show_slideshow', 'vp_popup_gallery' ),
|
||||
|
||||
'click_to_zoom' => Visual_Portfolio_Settings::get_option( 'click_to_zoom', 'vp_popup_gallery' ),
|
||||
'restore_focus' => Visual_Portfolio_Settings::get_option( 'restore_focus', 'vp_popup_gallery' ),
|
||||
),
|
||||
|
||||
// Screen sizes (breakpoints) for responsive feature: xs, sm, md, lg, xl.
|
||||
'screenSizes' => Visual_Portfolio_Breakpoints::get_breakpoints(),
|
||||
);
|
||||
|
||||
$data = apply_filters( 'vpf_global_data', $data );
|
||||
|
||||
echo "<script type='text/javascript'>\n";
|
||||
echo "/* <![CDATA[ */\n";
|
||||
echo 'var VPData = ' . wp_json_encode( $data ) . ';';
|
||||
echo "\n/* ]]> */\n";
|
||||
echo "</script>\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue styles in head.
|
||||
*/
|
||||
public function wp_enqueue_head_assets() {
|
||||
self::enqueue_stored_assets( 'style' );
|
||||
self::enqueue_stored_assets( 'template_style' );
|
||||
|
||||
self::$head_css_included = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue scripts and styles in foot.
|
||||
*/
|
||||
public function wp_enqueue_foot_assets() {
|
||||
self::enqueue_stored_assets( 'style' );
|
||||
self::enqueue_stored_assets( 'template_style' );
|
||||
self::enqueue_stored_assets( 'script' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add noscript styles.
|
||||
* Previously we used the `style_loader_tag` filter to add noscript to enqueued CSS,
|
||||
* but it is not working properly with optimizations plugins.
|
||||
*/
|
||||
public function add_noscript_styles() {
|
||||
$styles = '';
|
||||
$styles_path = visual_portfolio()->plugin_path . '/build/assets/css/noscript.css';
|
||||
|
||||
if ( file_exists( $styles_path ) ) {
|
||||
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
|
||||
$styles = file_get_contents( $styles_path );
|
||||
$styles = str_replace( '>', '>', $styles );
|
||||
}
|
||||
|
||||
if ( ! $styles ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<noscript>
|
||||
<style type="text/css">
|
||||
<?php echo wp_kses( $styles, array( '\'', '\"' ) ); ?>
|
||||
</style>
|
||||
</noscript>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Add fallback for lazyloading.
|
||||
*/
|
||||
public static function add_lazyload_fallback_script() {
|
||||
$css_url = visual_portfolio()->plugin_url . 'assets/css/lazyload-fallback.min.css?ver=' . VISUAL_PORTFOLIO_VERSION;
|
||||
$js_url = visual_portfolio()->plugin_url . 'assets/js/lazyload-fallback.min.js?ver=' . VISUAL_PORTFOLIO_VERSION;
|
||||
|
||||
?>
|
||||
<script>
|
||||
(function(){
|
||||
// Check if fallback is not necessary.
|
||||
if ( CSS.supports('selector(:has(div))') ) {
|
||||
return;
|
||||
}
|
||||
|
||||
var linkTag = document.createElement("link");
|
||||
linkTag.setAttribute('rel', 'stylesheet');
|
||||
linkTag.setAttribute('href', '<?php echo esc_url( $css_url ); ?>');
|
||||
document.head.appendChild(linkTag);
|
||||
|
||||
var scriptTag = document.createElement("script");
|
||||
scriptTag.setAttribute('src', '<?php echo esc_url( $js_url ); ?>');
|
||||
document.head.appendChild(scriptTag);
|
||||
}());
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse shortcodes from content.
|
||||
*/
|
||||
public function maybe_parse_shortcodes_from_content() {
|
||||
global $wp_query;
|
||||
|
||||
if ( is_admin() || ! isset( $wp_query->posts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$posts = $wp_query->posts;
|
||||
$pattern = get_shortcode_regex();
|
||||
|
||||
$layout_ids = array();
|
||||
|
||||
// parse all posts content.
|
||||
foreach ( $posts as $post ) {
|
||||
if (
|
||||
isset( $post->post_content )
|
||||
&& preg_match_all( '/' . $pattern . '/s', $post->post_content, $matches )
|
||||
&& array_key_exists( 2, $matches )
|
||||
&& in_array( 'visual_portfolio', $matches[2], true )
|
||||
) {
|
||||
$keys = array();
|
||||
$shortcodes = array();
|
||||
|
||||
foreach ( $matches[0] as $key => $value ) {
|
||||
// $matches[3] return the shortcode attribute as string
|
||||
// replace space with '&' for parse_str() function.
|
||||
$get = str_replace( ' ', '&', $matches[3][ $key ] );
|
||||
parse_str( $get, $output );
|
||||
|
||||
// get all shortcode attribute keys.
|
||||
$keys = array_unique( array_merge( $keys, array_keys( $output ) ) );
|
||||
$shortcodes[] = $output;
|
||||
}
|
||||
|
||||
if ( $keys && $shortcodes ) {
|
||||
// Loop the result array and add the missing shortcode attribute key.
|
||||
foreach ( $shortcodes as $key => $value ) {
|
||||
// Loop the shortcode attribute key.
|
||||
foreach ( $keys as $attr_key ) {
|
||||
$shortcodes[ $key ][ $attr_key ] = isset( $shortcodes[ $key ][ $attr_key ] ) ? $shortcodes[ $key ][ $attr_key ] : null;
|
||||
}
|
||||
|
||||
// sort the array key.
|
||||
ksort( $shortcodes[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
// get all IDs from shortcodes.
|
||||
foreach ( $shortcodes as $shortcode ) {
|
||||
if ( isset( $shortcode['id'] ) && $shortcode['id'] && ! in_array( $shortcode['id'], $layout_ids, true ) ) {
|
||||
$layout_ids[] = str_replace( '"', '', $shortcode['id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $layout_ids ) ) {
|
||||
foreach ( $layout_ids as $id ) {
|
||||
self::enqueue( array( 'id' => $id ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse blocks from content.
|
||||
*
|
||||
* @param array $blocks - blocks list.
|
||||
*/
|
||||
public function maybe_parse_blocks_from_content( $blocks ) {
|
||||
if ( empty( $blocks ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $blocks as $block ) {
|
||||
// Block.
|
||||
if (
|
||||
isset( $block['blockName'] ) &&
|
||||
'visual-portfolio/block' === $block['blockName'] &&
|
||||
isset( $block['attrs']['content_source'] ) &&
|
||||
isset( $block['attrs']['block_id'] )
|
||||
) {
|
||||
self::enqueue( $block['attrs'] );
|
||||
|
||||
// Saved block.
|
||||
} elseif (
|
||||
isset( $block['blockName'] ) &&
|
||||
(
|
||||
'visual-portfolio/saved' === $block['blockName'] ||
|
||||
'nk/visual-portfolio' === $block['blockName']
|
||||
) &&
|
||||
isset( $block['attrs']['id'] )
|
||||
) {
|
||||
self::enqueue( $block['attrs'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Assets();
|
@ -0,0 +1,183 @@
|
||||
<?php
|
||||
/**
|
||||
* Breakpoints.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Breakpoints
|
||||
*/
|
||||
class Visual_Portfolio_Breakpoints {
|
||||
/**
|
||||
* Extra Small Default Breakpoint.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $default_xs = 320;
|
||||
|
||||
/**
|
||||
* Mobile Default Breakpoint.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $default_sm = 576;
|
||||
|
||||
/**
|
||||
* Tablet Breakpoint.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $default_md = 768;
|
||||
|
||||
/**
|
||||
* Desktop Breakpoint.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $default_lg = 992;
|
||||
|
||||
/**
|
||||
* Large Desktop Breakpoint.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
private static $default_xl = 1200;
|
||||
|
||||
/**
|
||||
* Get Breakpoints.
|
||||
*/
|
||||
public static function get_breakpoints() {
|
||||
$xs = self::get_breakpoint_xs();
|
||||
$xs = ( ! empty( $xs ) && $xs ) ? $xs : self::$default_xs;
|
||||
|
||||
$sm = self::get_breakpoint_sm();
|
||||
$sm = ( ! empty( $sm ) && $sm ) ? $sm : self::$default_sm;
|
||||
|
||||
$md = self::get_breakpoint_md();
|
||||
$md = ( ! empty( $md ) && $md ) ? $md : self::$default_md;
|
||||
|
||||
$lg = self::get_breakpoint_lg();
|
||||
$lg = ( ! empty( $lg ) && $lg ) ? $lg : self::$default_lg;
|
||||
|
||||
$xl = self::get_breakpoint_xl();
|
||||
$xl = ( ! empty( $xl ) && $xl ) ? $xl : self::$default_xl;
|
||||
|
||||
return array(
|
||||
$xs,
|
||||
$sm,
|
||||
$md,
|
||||
$lg,
|
||||
$xl,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default breakpoints.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_default_breakpoints() {
|
||||
return array(
|
||||
'xs' => self::get_default_breakpoint_xs(),
|
||||
'sm' => self::get_default_breakpoint_sm(),
|
||||
'md' => self::get_default_breakpoint_md(),
|
||||
'lg' => self::get_default_breakpoint_lg(),
|
||||
'xl' => self::get_default_breakpoint_xl(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Default Extra Small Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_default_breakpoint_xs() {
|
||||
return apply_filters( 'vpf_default_breakpoint_xs', self::$default_xs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Extra Small Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_breakpoint_xs() {
|
||||
return apply_filters( 'vpf_breakpoint_xs', self::get_default_breakpoint_xs() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Default Mobile Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_default_breakpoint_sm() {
|
||||
return apply_filters( 'vpf_default_breakpoint_sm', self::$default_sm );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Mobile Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_breakpoint_sm() {
|
||||
return apply_filters( 'vpf_breakpoint_sm', self::get_default_breakpoint_sm() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Default Tablet Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_default_breakpoint_md() {
|
||||
return apply_filters( 'vpf_default_breakpoint_md', self::$default_md );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Tablet Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_breakpoint_md() {
|
||||
return apply_filters( 'vpf_breakpoint_md', self::get_default_breakpoint_md() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Default Desktop Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_default_breakpoint_lg() {
|
||||
return apply_filters( 'vpf_default_breakpoint_lg', self::$default_lg );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Desktop Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_breakpoint_lg() {
|
||||
return apply_filters( 'vpf_breakpoint_lg', self::get_default_breakpoint_lg() );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Default Large Desktop Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_default_breakpoint_xl() {
|
||||
return apply_filters( 'vpf_default_breakpoint_xl', self::$default_xl );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Large Desktop Breakpoint.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function get_breakpoint_xl() {
|
||||
return apply_filters( 'vpf_breakpoint_xl', self::get_default_breakpoint_xl() );
|
||||
}
|
||||
}
|
356
wp-content/plugins/visual-portfolio/classes/class-controls.php
Normal file
356
wp-content/plugins/visual-portfolio/classes/class-controls.php
Normal file
@ -0,0 +1,356 @@
|
||||
<?php
|
||||
/**
|
||||
* Controls
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Controls
|
||||
*/
|
||||
class Visual_Portfolio_Controls {
|
||||
/**
|
||||
* Registered user categories to print it in the future.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $registered_categories = array();
|
||||
|
||||
/**
|
||||
* Registered user fields to print it in the future.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $registered_fields = array();
|
||||
|
||||
/**
|
||||
* Cached all registered controls.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $cached_all_registered_controls = array();
|
||||
|
||||
/**
|
||||
* Cached saved layout meta.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $cached_saved_layout_meta = array();
|
||||
|
||||
/**
|
||||
* Default control args.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $default_args = array(
|
||||
// category for registered fields.
|
||||
'category' => '',
|
||||
|
||||
'type' => 'text',
|
||||
'label' => false,
|
||||
'description' => false,
|
||||
'group' => false,
|
||||
'name' => '',
|
||||
'value' => '',
|
||||
'placeholder' => '',
|
||||
'readonly' => false,
|
||||
'value_callback' => '',
|
||||
'sanitize_callback' => '',
|
||||
'reload_iframe' => true,
|
||||
|
||||
// control-specific args.
|
||||
// notice.
|
||||
'status' => 'info',
|
||||
// select.
|
||||
'options' => array(),
|
||||
'searchable' => false,
|
||||
'multiple' => false,
|
||||
'creatable' => false,
|
||||
// range.
|
||||
'min' => '',
|
||||
'max' => '',
|
||||
'step' => '1',
|
||||
// textarea.
|
||||
'cols' => '',
|
||||
'rows' => '',
|
||||
// color.
|
||||
'alpha' => false,
|
||||
'gradient' => false,
|
||||
// align.
|
||||
'extended' => false,
|
||||
// code editor.
|
||||
'mode' => 'css',
|
||||
'max_lines' => 20,
|
||||
'min_lines' => 5,
|
||||
'allow_modal' => true,
|
||||
'classes_tree' => false,
|
||||
'encode' => false,
|
||||
'code_placeholder' => '',
|
||||
// elements selector.
|
||||
'locations' => array(),
|
||||
// gallery.
|
||||
'focal_point' => false,
|
||||
|
||||
// hint, deprecated.
|
||||
'hint' => false,
|
||||
'hint_place' => 'top',
|
||||
|
||||
// display in setup wizard.
|
||||
'setup_wizard' => false,
|
||||
|
||||
// support for WPML.
|
||||
'wpml' => false,
|
||||
|
||||
// condition.
|
||||
'condition' => array(
|
||||
/**
|
||||
* Array of arrays with data:
|
||||
* 'control' - control name.
|
||||
* 'operator' - operator (==, !==, >, <, >=, <=).
|
||||
* 'value' - condition value.
|
||||
*/
|
||||
),
|
||||
|
||||
// style.
|
||||
'style' => array(
|
||||
/**
|
||||
* Array of arrays with data:
|
||||
* 'element' - CSS selector string (.vp-portfolio__item, .vp-portfolio__item-overlay, etc).
|
||||
* 'property' - CSS property (color, font-size, etc).
|
||||
* 'mask' - CSS value mask, for ex. "$px".
|
||||
*/
|
||||
),
|
||||
|
||||
'class' => '',
|
||||
'wrapper_class' => '',
|
||||
);
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Controls constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'wp_ajax_vp_dynamic_control_callback', array( $this, 'ajax_dynamic_control_callback' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamic control AJAX callback.
|
||||
*/
|
||||
public function ajax_dynamic_control_callback() {
|
||||
check_ajax_referer( 'vp-ajax-nonce', 'nonce' );
|
||||
if ( ! isset( $_POST['vp_control_name'] ) ) {
|
||||
wp_die();
|
||||
}
|
||||
|
||||
$result = null;
|
||||
$found = null;
|
||||
$controls = self::get_registered_array();
|
||||
|
||||
// find control callback.
|
||||
foreach ( $controls as $control ) {
|
||||
if (
|
||||
isset( $control['name'] ) &&
|
||||
$control['name'] === $_POST['vp_control_name'] &&
|
||||
isset( $control['value_callback'] ) &&
|
||||
is_callable( $control['value_callback'] )
|
||||
) {
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
$attributes = isset( $_POST['vp_attributes'] ) ? Visual_Portfolio_Security::sanitize_attributes( $_POST['vp_attributes'] ) : array();
|
||||
$found = true;
|
||||
$result = call_user_func( $control['value_callback'], $attributes, $control );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( null === $found ) {
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'response' => esc_attr__( 'Dynamic control callback function is not found.', 'visual-portfolio' ),
|
||||
'error' => true,
|
||||
)
|
||||
);
|
||||
} else {
|
||||
echo wp_json_encode(
|
||||
array(
|
||||
'response' => $result,
|
||||
'success' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
wp_die();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register category to print in the future.
|
||||
*
|
||||
* @param array $categories - categories args.
|
||||
*/
|
||||
public static function register_categories( $categories = array() ) {
|
||||
self::$registered_categories = array_merge( self::$registered_categories, $categories );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register control to print in the future.
|
||||
*
|
||||
* @param array $args - control args.
|
||||
*/
|
||||
public static function register( $args = array() ) {
|
||||
if ( ! isset( $args['name'] ) ) {
|
||||
return;
|
||||
}
|
||||
self::$registered_fields[ $args['name'] ] = apply_filters( 'vpf_register_control', $args, $args['name'] );
|
||||
|
||||
do_action( 'vpf_registered_control', $args['name'], $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered controls.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_registered_array() {
|
||||
// Return cached version of all controls.
|
||||
if ( ! empty( self::$cached_all_registered_controls ) ) {
|
||||
return self::$cached_all_registered_controls;
|
||||
}
|
||||
|
||||
$result = array();
|
||||
|
||||
foreach ( self::$registered_fields as $k => $args ) {
|
||||
$result[ $k ] = array_merge( self::$default_args, $args );
|
||||
|
||||
// Gallery image controls.
|
||||
if ( 'gallery' === $result[ $k ]['type'] && isset( $result[ $k ]['image_controls'] ) && ! empty( $result[ $k ]['image_controls'] ) ) {
|
||||
$img_controls = array();
|
||||
|
||||
// Extend.
|
||||
// phpcs:ignore Squiz.PHP.CommentedOutCode.Found, Squiz.Commenting.BlockComment.NoEmptyLineBefore
|
||||
/*
|
||||
* Example:
|
||||
array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'label' => esc_html__( 'Title', 'visual-portfolio' ),
|
||||
),
|
||||
'description' => array(
|
||||
'type' => 'textarea',
|
||||
'label' => esc_html__( 'Description', 'visual-portfolio' ),
|
||||
),
|
||||
)
|
||||
*/
|
||||
$result[ $k ]['image_controls'] = apply_filters( 'vpf_extend_image_controls', $result[ $k ]['image_controls'], $result[ $k ]['name'] );
|
||||
|
||||
// Get default controls data.
|
||||
foreach ( $result[ $k ]['image_controls'] as $i => $img_args ) {
|
||||
$img_controls[ $i ] = array_merge( self::$default_args, $img_args );
|
||||
}
|
||||
|
||||
$result[ $k ]['image_controls'] = $img_controls;
|
||||
}
|
||||
|
||||
$result[ $k ] = apply_filters( 'vpf_registered_control_args', $result[ $k ] );
|
||||
}
|
||||
|
||||
self::$cached_all_registered_controls = apply_filters( 'vpf_registered_controls', $result );
|
||||
|
||||
return self::$cached_all_registered_controls;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered categories.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_registered_categories() {
|
||||
return self::$registered_categories;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get registered control value.
|
||||
*
|
||||
* @param string $name - field name.
|
||||
* @param int|bool $post_id - post id to get meta data.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function get_registered_value( $name, $post_id = false ) {
|
||||
// get meta data.
|
||||
$result = null;
|
||||
|
||||
// get meta data from saved layout.
|
||||
// get all layout meta at once and cache them (works faster).
|
||||
if ( $post_id ) {
|
||||
if ( ! isset( self::$cached_saved_layout_meta[ $post_id ] ) ) {
|
||||
$saved_meta = get_post_meta( $post_id );
|
||||
$result_meta = array();
|
||||
|
||||
// We should unserialize array data as in standard function https://developer.wordpress.org/reference/functions/get_metadata_raw/.
|
||||
if ( is_array( $saved_meta ) ) {
|
||||
foreach ( $saved_meta as $key => $val ) {
|
||||
if ( isset( $val[0] ) ) {
|
||||
$result_meta[ $key ] = maybe_unserialize( $val[0] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self::$cached_saved_layout_meta[ $post_id ] = $result_meta;
|
||||
}
|
||||
if ( isset( self::$cached_saved_layout_meta[ $post_id ] ) && isset( self::$cached_saved_layout_meta[ $post_id ][ 'vp_' . $name ] ) ) {
|
||||
$result = self::$cached_saved_layout_meta[ $post_id ][ 'vp_' . $name ];
|
||||
}
|
||||
}
|
||||
|
||||
// registered data.
|
||||
$registered_array = self::get_registered_array();
|
||||
$registered_data = isset( $registered_array[ $name ] ) ? $registered_array[ $name ] : false;
|
||||
|
||||
// find default.
|
||||
$default = null;
|
||||
if ( isset( $registered_data ) ) {
|
||||
$default = isset( $registered_data['default'] ) ? $registered_data['default'] : $default;
|
||||
}
|
||||
if ( ! isset( $result ) && isset( $default ) ) {
|
||||
$result = $default;
|
||||
}
|
||||
|
||||
// filter.
|
||||
$result = apply_filters( 'vpf_control_value', $result, $name, $post_id );
|
||||
|
||||
// fix for gallery array.
|
||||
if ( isset( $registered_data['type'] ) && 'gallery' === $registered_data['type'] ) {
|
||||
$result = (array) ( is_string( $result ) ? json_decode( $result, true ) : $result );
|
||||
|
||||
// add image url if doesn't exist.
|
||||
foreach ( $result as $k => $data ) {
|
||||
if ( ! isset( $data['imgUrl'] ) && isset( $data['id'] ) ) {
|
||||
$result[ $k ]['imgUrl'] = Visual_Portfolio_Images::wp_get_attachment_image_url( $data['id'], 'full' );
|
||||
$result[ $k ]['imgThumbnailUrl'] = Visual_Portfolio_Images::wp_get_attachment_image_url( $data['id'], 'thumbnail' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fix bool values.
|
||||
if ( 'false' === $result ) {
|
||||
$result = false;
|
||||
}
|
||||
if ( 'true' === $result ) {
|
||||
$result = true;
|
||||
}
|
||||
|
||||
if ( 'custom_css' === $name && $result ) {
|
||||
// Decode.
|
||||
$result = visual_portfolio_decode( $result );
|
||||
|
||||
// Fix for old plugin versions (< 2.0).
|
||||
$result = str_replace( '>', '>', $result );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Controls();
|
@ -0,0 +1,419 @@
|
||||
<?php
|
||||
/**
|
||||
* Add custom meta data to posts.
|
||||
*
|
||||
* @package visual-portfolio/admin
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Custom_Post_Meta
|
||||
*/
|
||||
class Visual_Portfolio_Custom_Post_Meta {
|
||||
/**
|
||||
* Visual_Portfolio_Custom_Post_Meta constructor.
|
||||
*/
|
||||
public static function init() {
|
||||
// add post formats.
|
||||
add_action( 'after_setup_theme', array( __CLASS__, 'add_extra_post_format' ), 99 );
|
||||
add_action( 'init', array( __CLASS__, 'register_post_meta' ) );
|
||||
add_action( 'add_meta_boxes', array( __CLASS__, 'add_post_format_metaboxes' ), 1 );
|
||||
add_action( 'save_post', array( __CLASS__, 'save_post_format_metaboxes' ) );
|
||||
add_action( 'save_post', array( __CLASS__, 'update_words_count' ) );
|
||||
add_action( 'wp_head', array( __CLASS__, 'update_views_count' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current page is gutenberg.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function is_gutenberg() {
|
||||
$current_screen = get_current_screen();
|
||||
if ( method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add video post format.
|
||||
*/
|
||||
public static function add_extra_post_format() {
|
||||
global $_wp_theme_features;
|
||||
|
||||
$formats = array( 'image', 'video' );
|
||||
|
||||
// Add existing formats.
|
||||
if ( isset( $_wp_theme_features['post-formats'] ) && isset( $_wp_theme_features['post-formats'][0] ) ) {
|
||||
$formats = array_merge( (array) $_wp_theme_features['post-formats'][0], $formats );
|
||||
}
|
||||
$formats = array_unique( $formats );
|
||||
|
||||
add_theme_support( 'post-formats', $formats );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register post meta.
|
||||
*/
|
||||
public static function register_post_meta() {
|
||||
$post_type_names = array_keys( get_post_types() );
|
||||
|
||||
foreach ( $post_type_names as $post_type ) {
|
||||
if ( ! is_post_type_viewable( $post_type ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Register meta for all post types.
|
||||
register_meta(
|
||||
'post',
|
||||
'_vp_format_video_url',
|
||||
array(
|
||||
'object_subtype' => $post_type,
|
||||
'type' => 'string',
|
||||
'single' => true,
|
||||
'show_in_rest' => true,
|
||||
'auth_callback' => array( __CLASS__, 'rest_auth' ),
|
||||
)
|
||||
);
|
||||
register_meta(
|
||||
'post',
|
||||
'_vp_image_focal_point',
|
||||
array(
|
||||
'object_subtype' => $post_type,
|
||||
'type' => 'object',
|
||||
'single' => true,
|
||||
'show_in_rest' => array(
|
||||
'schema' => array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'x' => array(
|
||||
'type' => 'number',
|
||||
),
|
||||
'y' => array(
|
||||
'type' => 'number',
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
'auth_callback' => array( __CLASS__, 'rest_auth' ),
|
||||
)
|
||||
);
|
||||
|
||||
// Add support for 'custom-fields' to work in Gutenberg.
|
||||
add_post_type_support( $post_type, 'custom-fields' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines REST API authentication.
|
||||
*
|
||||
* @param bool $allowed Whether it is allowed.
|
||||
* @param string $meta_key The meta key being checked.
|
||||
* @param int $post_id The post ID being checked.
|
||||
* @param int $user_id The user ID being checked.
|
||||
* @param string $cap The current capability.
|
||||
* @param array $caps All capabilities.
|
||||
* @return bool Whether the user can do it.
|
||||
*/
|
||||
// phpcs:ignore
|
||||
public static function rest_auth( $allowed, $meta_key, $post_id, $user_id, $cap, $caps ) {
|
||||
return user_can( $user_id, 'edit_post', $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add post format metaboxes.
|
||||
*
|
||||
* @param string $post_type post type.
|
||||
*/
|
||||
public static function add_post_format_metaboxes( $post_type ) {
|
||||
// Prevent if Gutenberg enabled.
|
||||
if ( self::is_gutenberg() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent if no Video post format supported.
|
||||
if ( ! post_type_supports( $post_type, 'post-formats' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_meta_box(
|
||||
'vp_format_video',
|
||||
esc_html__( 'Video', 'visual-portfolio' ),
|
||||
array( __CLASS__, 'add_video_format_metabox' ),
|
||||
null,
|
||||
'side',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Video Format metabox
|
||||
*
|
||||
* @param object $post The post object.
|
||||
*/
|
||||
public static function add_video_format_metabox( $post ) {
|
||||
wp_nonce_field( basename( __FILE__ ), 'vp_format_video_nonce' );
|
||||
|
||||
$video_url = self::get_video_format_url( $post->ID );
|
||||
$oembed_html = false;
|
||||
|
||||
$wpkses_iframe = array(
|
||||
'iframe' => array(
|
||||
'src' => array(),
|
||||
'height' => array(),
|
||||
'width' => array(),
|
||||
'frameborder' => array(),
|
||||
'allowfullscreen' => array(),
|
||||
),
|
||||
);
|
||||
|
||||
if ( $video_url ) {
|
||||
$oembed = visual_portfolio()->get_oembed_data( $video_url );
|
||||
|
||||
if ( $oembed && isset( $oembed['html'] ) ) {
|
||||
$oembed_html = $oembed['html'];
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<p></p>
|
||||
<input class="vp-input" name="_vp_format_video_url" type="url" id="_vp_format_video_url" value="<?php echo esc_attr( $video_url ); ?>" placeholder="<?php echo esc_attr__( 'https://', 'visual-portfolio' ); ?>">
|
||||
<div class="vp-oembed-preview">
|
||||
<?php
|
||||
if ( $oembed_html ) {
|
||||
echo wp_kses( $oembed_html, $wpkses_iframe );
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<style>
|
||||
#vp_format_video {
|
||||
display: <?php echo has_post_format( 'video' ) ? 'block' : 'none'; ?>;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Save Format metabox
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function save_post_format_metaboxes( $post_id ) {
|
||||
if ( ! isset( $_POST['vp_format_video_nonce'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! wp_verify_nonce( sanitize_key( $_POST['vp_format_video_nonce'] ), basename( __FILE__ ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$meta = array(
|
||||
'_vp_format_video_url',
|
||||
);
|
||||
|
||||
foreach ( $meta as $item ) {
|
||||
if ( isset( $_POST[ $item ] ) ) {
|
||||
if ( is_array( $_POST[ $item ] ) ) {
|
||||
$result = array_map( 'sanitize_text_field', wp_unslash( $_POST[ $item ] ) );
|
||||
} else {
|
||||
$result = sanitize_text_field( wp_unslash( $_POST[ $item ] ) );
|
||||
}
|
||||
|
||||
update_post_meta( $post_id, $item, $result );
|
||||
|
||||
// remove old video meta.
|
||||
if ( '_vp_format_video_url' === $item && get_post_meta( $post_id, 'video_url', true ) ) {
|
||||
delete_post_meta( $post_id, 'video_url' );
|
||||
}
|
||||
} else {
|
||||
update_post_meta( $post_id, $item, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get video format URL.
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function get_video_format_url( $post_id ) {
|
||||
if ( ! $post_id ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$video_url = get_post_meta( $post_id, '_vp_format_video_url', true );
|
||||
|
||||
// fallback.
|
||||
if ( ! $video_url ) {
|
||||
$video_url = get_post_meta( $post_id, 'video_url', true );
|
||||
}
|
||||
|
||||
return $video_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get featured image focal point.
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function get_featured_image_focal_point( $post_id ) {
|
||||
if ( ! $post_id ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$focal_point = get_post_meta( $post_id, '_vp_image_focal_point', true );
|
||||
|
||||
if (
|
||||
! isset( $focal_point ) ||
|
||||
empty( $focal_point ) ||
|
||||
! isset( $focal_point['x'] ) || ! isset( $focal_point['y'] ) ||
|
||||
( '0.5' === $focal_point['x'] && '0.5' === $focal_point['y'] )
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $focal_point;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update views count.
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function update_views_count( $post_id ) {
|
||||
if ( ! is_single() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! $post_id ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$current_views = self::get_views_count( $post_id );
|
||||
|
||||
update_post_meta( $post_id, '_vp_views_count', $current_views + 1 );
|
||||
|
||||
// Support for https://wordpress.org/plugins/post-views-counter/ .
|
||||
if ( function_exists( 'pvc_view_post' ) ) {
|
||||
pvc_view_post( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get views count.
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function get_views_count( $post_id ) {
|
||||
if ( ! $post_id ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
// Support for https://wordpress.org/plugins/post-views-counter/ .
|
||||
if ( function_exists( 'pvc_get_post_views' ) ) {
|
||||
return pvc_get_post_views( $post_id );
|
||||
}
|
||||
|
||||
$current_views = get_post_meta( $post_id, '_vp_views_count', true );
|
||||
|
||||
if ( ! $current_views ) {
|
||||
$current_views = 0;
|
||||
}
|
||||
|
||||
return $current_views;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update reading time.
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function update_words_count( $post_id ) {
|
||||
if ( ! $post_id ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$current_reading_time = self::calculate_words_count( $post_id );
|
||||
|
||||
update_post_meta( $post_id, '_vp_words_count', $current_reading_time );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reading time.
|
||||
*
|
||||
* Read time is based on the average reading speed of an adult (roughly 265 WPM).
|
||||
* We take the total word count of a post and translate it into minutes.
|
||||
* For posts in Chinese, Japanese and Korean, it's a function of
|
||||
* number of characters (500 characters/min).
|
||||
*
|
||||
* @thanks https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function get_reading_time( $post_id ) {
|
||||
if ( ! $post_id ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$post_words_count = get_post_meta( $post_id, '_vp_words_count', true );
|
||||
|
||||
if ( ! $post_words_count ) {
|
||||
$post_words_count = self::calculate_words_count( $post_id );
|
||||
}
|
||||
|
||||
$locale = get_locale();
|
||||
|
||||
switch ( $locale ) {
|
||||
// zh_CN - Chinese (China)
|
||||
// zh_HK - Chinese (Hong Kong SAR China)
|
||||
// zh_SG - Chinese (Singapore)
|
||||
// zh_TW - Chinese (Taiwan)
|
||||
// ja_JP - Japanese (Japan)
|
||||
// ko_KR - Korean (South Korea).
|
||||
case 'zh_CN':
|
||||
case 'zh_HK':
|
||||
case 'zh_SG':
|
||||
case 'zh_TW':
|
||||
case 'ja_JP':
|
||||
case 'ko_KR':
|
||||
$reading_time = $post_words_count / 500;
|
||||
break;
|
||||
default:
|
||||
$reading_time = $post_words_count / 265;
|
||||
break;
|
||||
}
|
||||
|
||||
// When reading time is 0, return it as `< 1` instead of `0`.
|
||||
if ( 1 > $reading_time ) {
|
||||
$reading_time = esc_html__( '< 1', 'visual-portfolio' );
|
||||
} else {
|
||||
$reading_time = ceil( $reading_time );
|
||||
}
|
||||
|
||||
return $reading_time;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate words count.
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
*/
|
||||
public static function calculate_words_count( $post_id ) {
|
||||
if ( ! $post_id ) {
|
||||
$post_id = get_the_ID();
|
||||
}
|
||||
|
||||
$content = get_the_content( null, false, $post_id );
|
||||
$content = wp_strip_all_tags( $content );
|
||||
$words_count = count( preg_split( '/\s+/', $content ) );
|
||||
|
||||
return $words_count;
|
||||
}
|
||||
}
|
||||
|
||||
Visual_Portfolio_Custom_Post_Meta::init();
|
@ -0,0 +1,869 @@
|
||||
<?php
|
||||
/**
|
||||
* Register Custom Post Types.
|
||||
*
|
||||
* @package visual-portfolio/admin
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Custom_Post_Type
|
||||
*/
|
||||
class Visual_Portfolio_Custom_Post_Type {
|
||||
/**
|
||||
* Option of register portfolio post type.
|
||||
*
|
||||
* @deprecated deprecated since version 2.17.1
|
||||
* @var string
|
||||
*/
|
||||
public static $register_portfolio_post_type = true;
|
||||
|
||||
/**
|
||||
* Menu slug.
|
||||
*
|
||||
* @deprecated deprecated since version 2.17.1
|
||||
* @var string
|
||||
*/
|
||||
public static $menu_slug = 'edit.php?post_type=portfolio';
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Custom_Post_Type constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// custom post types.
|
||||
// We have to use priority < 10 to add compatibility for 'post-terms' block.
|
||||
// @link https://github.com/WordPress/gutenberg/blob/7880f08f57ac9275c21129d1f7e1f56af40bea87/packages/block-library/src/post-terms/index.php#L61-L110.
|
||||
add_action( 'init', array( $this, 'add_custom_post_type' ), 9 );
|
||||
add_action( 'restrict_manage_posts', array( $this, 'filter_custom_post_by_taxonomies' ), 10 );
|
||||
|
||||
// custom post roles.
|
||||
add_action( 'init', array( $this, 'add_role_caps' ) );
|
||||
|
||||
// remove screen options from portfolio list page.
|
||||
add_action( 'screen_options_show_screen', array( $this, 'remove_screen_options' ), 10, 2 );
|
||||
|
||||
// show thumbnail in portfolio list table.
|
||||
add_filter( 'manage_portfolio_posts_columns', array( $this, 'add_portfolio_img_column' ) );
|
||||
add_filter( 'manage_portfolio_posts_custom_column', array( $this, 'manage_portfolio_img_column' ), 10, 2 );
|
||||
|
||||
// show notice in vp_lists admin list page.
|
||||
add_filter( 'admin_notices', array( $this, 'add_vp_lists_notice' ) );
|
||||
|
||||
// show icon and shortcode columns in vp_lists table.
|
||||
add_filter( 'manage_vp_lists_posts_columns', array( $this, 'add_vp_lists_custom_columns' ) );
|
||||
add_action( 'manage_vp_lists_posts_custom_column', array( $this, 'manage_vp_lists_custom_columns' ), 10, 2 );
|
||||
add_action( 'restrict_manage_posts', array( $this, 'restrict_manage_posts_vp_lists' ) );
|
||||
add_action( 'parse_query', array( $this, 'parse_query_vp_lists' ) );
|
||||
|
||||
// change allowed blocks for vp_lists post type.
|
||||
add_filter( 'allowed_block_types_all', array( $this, 'vp_lists_allowed_block_types_all' ), 10, 2 );
|
||||
|
||||
// force enable Gutenberg editor in 'vp_lists' for Classic Editor plugin.
|
||||
add_action( 'classic_editor_enabled_editors_for_post_type', array( $this, 'vp_lists_classic_plugin_force_gutenberg' ), 150, 2 );
|
||||
add_action( 'use_block_editor_for_post_type', array( $this, 'vp_lists_classic_plugin_force_gutenberg_2' ), 150, 2 );
|
||||
add_action( 'use_block_editor_for_post', array( $this, 'vp_lists_classic_plugin_force_gutenberg_3' ), 150, 2 );
|
||||
|
||||
// force enable Gutenberg in 'vp_lists' for users with disabled option "Visual Editor".
|
||||
add_filter( 'user_can_richedit', array( $this, 'vp_lists_user_can_richedit_force' ) );
|
||||
|
||||
// highlight admin menu items.
|
||||
add_action( 'admin_menu', array( $this, 'add_proofing_admin_menu' ), 10 );
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ), 12 );
|
||||
|
||||
// show admin menu dropdown with available portfolios on the current page.
|
||||
add_action( 'wp_before_admin_bar_render', array( $this, 'wp_before_admin_bar_render' ) );
|
||||
|
||||
// add backward compatibility with old Pro version.
|
||||
add_action( 'init', array( __CLASS__, 'set_settings_of_register_portfolio_post_type' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set settings of register portfolio post type.
|
||||
*
|
||||
* @deprecated deprecated since version 2.17.1
|
||||
* @return void
|
||||
*/
|
||||
public static function set_settings_of_register_portfolio_post_type() {
|
||||
self::$register_portfolio_post_type = Visual_Portfolio_Settings::get_option( 'register_portfolio_post_type', 'vp_general' );
|
||||
self::$menu_slug = self::$register_portfolio_post_type ? 'edit.php?post_type=portfolio' : 'visual-portfolio-settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get menu slug.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_menu_slug() {
|
||||
return self::portfolio_post_type_is_registered() ? 'edit.php?post_type=portfolio' : 'visual-portfolio-settings';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if portfolio post type is registered.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function portfolio_post_type_is_registered() {
|
||||
return Visual_Portfolio_Settings::get_option( 'register_portfolio_post_type', 'vp_general' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom post type
|
||||
*/
|
||||
public function add_custom_post_type() {
|
||||
$archive_page = Visual_Portfolio_Settings::get_option( 'portfolio_archive_page', 'vp_general' );
|
||||
$custom_slug = (int) get_option( 'page_on_front' ) === (int) $archive_page ? '/' : Visual_Portfolio_Archive_Mapping::get_portfolio_slug();
|
||||
$custom_label = Visual_Portfolio_Archive_Mapping::get_portfolio_label();
|
||||
$permalinks = Visual_Portfolio_Archive_Mapping::get_permalink_structure( true );
|
||||
|
||||
// portfolio post type / project post type.
|
||||
if ( self::portfolio_post_type_is_registered() ) {
|
||||
register_post_type(
|
||||
'portfolio',
|
||||
array(
|
||||
'labels' => array(
|
||||
// We have to use label from the actual Portfolio page
|
||||
// because 3rd-party breadcrumbs will display this name and it is
|
||||
// required to show breadcrumbs like:
|
||||
//
|
||||
// Home > Portfolio > Project Name
|
||||
//
|
||||
// Instead of this one:
|
||||
// Home > Projects > Project Name.
|
||||
'name' => $custom_label,
|
||||
'singular_name' => _x( 'Project', 'Post Type Singular Name', 'visual-portfolio' ),
|
||||
'menu_name' => visual_portfolio()->plugin_name,
|
||||
'parent_item_colon' => __( 'Parent Project', 'visual-portfolio' ),
|
||||
'all_items' => __( 'Projects', 'visual-portfolio' ),
|
||||
'view_item' => __( 'View Project', 'visual-portfolio' ),
|
||||
'add_new_item' => __( 'Add New Project', 'visual-portfolio' ),
|
||||
'add_new' => __( 'Add New', 'visual-portfolio' ),
|
||||
'edit_item' => __( 'Edit Project', 'visual-portfolio' ),
|
||||
'update_item' => __( 'Update Project', 'visual-portfolio' ),
|
||||
'search_items' => __( 'Search Project', 'visual-portfolio' ),
|
||||
'not_found' => __( 'Not Found', 'visual-portfolio' ),
|
||||
'not_found_in_trash' => __( 'Not found in Trash', 'visual-portfolio' ),
|
||||
),
|
||||
'public' => true,
|
||||
'publicly_queryable' => true,
|
||||
'has_archive' => $custom_slug,
|
||||
'show_ui' => true,
|
||||
|
||||
// adding to custom menu manually.
|
||||
'show_in_menu' => true,
|
||||
'show_in_admin_bar' => true,
|
||||
'show_in_rest' => true,
|
||||
'menu_icon' => 'dashicons-visual-portfolio',
|
||||
'taxonomies' => array(
|
||||
'portfolio_category',
|
||||
'portfolio_tag',
|
||||
),
|
||||
'map_meta_cap' => true,
|
||||
'capability_type' => 'portfolio',
|
||||
'rewrite' => array(
|
||||
'slug' => $permalinks['portfolio_base'],
|
||||
'with_front' => false,
|
||||
),
|
||||
'supports' => array(
|
||||
'title',
|
||||
'editor',
|
||||
'author',
|
||||
'thumbnail',
|
||||
'comments',
|
||||
'revisions',
|
||||
'excerpt',
|
||||
'post-formats',
|
||||
'page-attributes',
|
||||
'custom-fields',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
register_taxonomy(
|
||||
'portfolio_category',
|
||||
'portfolio',
|
||||
array(
|
||||
'label' => esc_html__( 'Portfolio Categories', 'visual-portfolio' ),
|
||||
'labels' => array(
|
||||
'menu_name' => esc_html__( 'Categories', 'visual-portfolio' ),
|
||||
),
|
||||
'rewrite' => array(
|
||||
'slug' => $permalinks['category_base'],
|
||||
),
|
||||
'hierarchical' => true,
|
||||
'publicly_queryable' => true,
|
||||
'show_in_nav_menus' => true,
|
||||
'show_in_rest' => true,
|
||||
'show_admin_column' => true,
|
||||
'map_meta_cap' => true,
|
||||
'capability_type' => 'portfolio',
|
||||
)
|
||||
);
|
||||
register_taxonomy(
|
||||
'portfolio_tag',
|
||||
'portfolio',
|
||||
array(
|
||||
'label' => esc_html__( 'Portfolio Tags', 'visual-portfolio' ),
|
||||
'labels' => array(
|
||||
'menu_name' => esc_html__( 'Tags', 'visual-portfolio' ),
|
||||
),
|
||||
'rewrite' => array(
|
||||
'slug' => $permalinks['tag_base'],
|
||||
),
|
||||
'hierarchical' => false,
|
||||
'publicly_queryable' => true,
|
||||
'show_in_nav_menus' => true,
|
||||
'show_in_rest' => true,
|
||||
'show_admin_column' => true,
|
||||
'map_meta_cap' => true,
|
||||
'capability_type' => 'portfolio',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// portfolio lists post type.
|
||||
register_post_type(
|
||||
'vp_lists',
|
||||
array(
|
||||
'labels' => array(
|
||||
'name' => _x( 'Saved Layouts', 'Post Type General Name', 'visual-portfolio' ),
|
||||
'singular_name' => _x( 'Saved Layout', 'Post Type Singular Name', 'visual-portfolio' ),
|
||||
'menu_name' => visual_portfolio()->plugin_name,
|
||||
'parent_item_colon' => __( 'Parent Project', 'visual-portfolio' ),
|
||||
'all_items' => __( 'Saved Layouts', 'visual-portfolio' ),
|
||||
'view_item' => __( 'View Saved Layout', 'visual-portfolio' ),
|
||||
'add_new_item' => __( 'Add New Saved Layout', 'visual-portfolio' ),
|
||||
'add_new' => __( 'Add New', 'visual-portfolio' ),
|
||||
'edit_item' => __( 'Edit Saved Layout', 'visual-portfolio' ),
|
||||
'update_item' => __( 'Update Saved Layout', 'visual-portfolio' ),
|
||||
'search_items' => __( 'Search Saved Layout', 'visual-portfolio' ),
|
||||
'not_found' => __( 'Not Found', 'visual-portfolio' ),
|
||||
'not_found_in_trash' => __( 'Not found in Trash', 'visual-portfolio' ),
|
||||
),
|
||||
'public' => false,
|
||||
'has_archive' => false,
|
||||
'show_ui' => true,
|
||||
|
||||
// adding to custom menu manually.
|
||||
'show_in_menu' => self::get_menu_slug(),
|
||||
'show_in_rest' => true,
|
||||
'map_meta_cap' => true,
|
||||
'capability_type' => 'vp_list',
|
||||
'rewrite' => true,
|
||||
'supports' => array(
|
||||
'title',
|
||||
'editor',
|
||||
'revisions',
|
||||
),
|
||||
'template' => array(
|
||||
array(
|
||||
'visual-portfolio/saved-editor',
|
||||
),
|
||||
),
|
||||
// we can't use it since blocks didn't inserted in some posts.
|
||||
// 'template_lock' => 'all',.
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add filter by custom taxonomies
|
||||
*
|
||||
* @param String $post_type - post type name.
|
||||
*/
|
||||
public function filter_custom_post_by_taxonomies( $post_type ) {
|
||||
// Apply this only on a specific post type.
|
||||
if ( 'portfolio' !== $post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A list of taxonomy slugs to filter by.
|
||||
$taxonomies = array( 'portfolio_category', 'portfolio_tag' );
|
||||
|
||||
foreach ( $taxonomies as $taxonomy_slug ) {
|
||||
// Retrieve taxonomy data.
|
||||
$taxonomy_obj = get_taxonomy( $taxonomy_slug );
|
||||
$taxonomy_name = $taxonomy_obj->labels->name;
|
||||
|
||||
// Retrieve taxonomy terms.
|
||||
$terms = get_terms( $taxonomy_slug );
|
||||
|
||||
// Display filter HTML.
|
||||
echo '<select name="' . esc_attr( $taxonomy_slug ) . '" id="' . esc_attr( $taxonomy_slug ) . '" class="postform">';
|
||||
// translators: %s - taxonomy name.
|
||||
echo '<option value="">' . sprintf( esc_html__( 'Show All %s', 'visual-portfolio' ), esc_html( $taxonomy_name ) ) . '</option>';
|
||||
foreach ( $terms as $term ) {
|
||||
printf(
|
||||
'<option value="%1$s" %2$s>%3$s (%4$s)</option>',
|
||||
esc_attr( $term->slug ),
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
isset( $_GET[ $taxonomy_slug ] ) && $_GET[ $taxonomy_slug ] === $term->slug ? ' selected="selected"' : '',
|
||||
esc_html( $term->name ),
|
||||
esc_html( $term->count )
|
||||
);
|
||||
}
|
||||
echo '</select>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Roles
|
||||
*/
|
||||
public function add_role_caps() {
|
||||
if ( ! is_blog_installed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wp_version;
|
||||
|
||||
$check_string = 'Plugin: ' . VISUAL_PORTFOLIO_VERSION . ' WP: ' . $wp_version;
|
||||
|
||||
if ( get_option( 'visual_portfolio_updated_caps' ) === $check_string ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wp_roles = wp_roles();
|
||||
|
||||
if ( ! isset( $wp_roles ) || empty( $wp_roles ) || ! $wp_roles ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$author = $wp_roles->get_role( 'author' );
|
||||
|
||||
$wp_roles->add_role(
|
||||
'portfolio_manager',
|
||||
__( 'Portfolio Manager', 'visual-portfolio' ),
|
||||
$author->capabilities
|
||||
);
|
||||
$wp_roles->add_role(
|
||||
'portfolio_author',
|
||||
__( 'Portfolio Author', 'visual-portfolio' ),
|
||||
$author->capabilities
|
||||
);
|
||||
|
||||
$portfolio_cap = array(
|
||||
'read_portfolio',
|
||||
'read_private_portfolio',
|
||||
'read_private_portfolios',
|
||||
'edit_portfolio',
|
||||
'edit_portfolios',
|
||||
'edit_others_portfolios',
|
||||
'edit_private_portfolios',
|
||||
'edit_published_portfolios',
|
||||
'delete_portfolio',
|
||||
'delete_portfolios',
|
||||
'delete_others_portfolios',
|
||||
'delete_private_portfolios',
|
||||
'delete_published_portfolios',
|
||||
'publish_portfolios',
|
||||
|
||||
// Terms.
|
||||
'manage_portfolio_terms',
|
||||
'edit_portfolio_terms',
|
||||
'delete_portfolio_terms',
|
||||
'assign_portfolio_terms',
|
||||
);
|
||||
|
||||
$lists_cap = array(
|
||||
'read_vp_list',
|
||||
'read_private_vp_list',
|
||||
'read_private_vp_lists',
|
||||
'edit_vp_list',
|
||||
'edit_vp_lists',
|
||||
'edit_others_vp_lists',
|
||||
'edit_private_vp_lists',
|
||||
'edit_published_vp_lists',
|
||||
'delete_vp_list',
|
||||
'delete_vp_lists',
|
||||
'delete_others_vp_lists',
|
||||
'delete_private_vp_lists',
|
||||
'delete_published_vp_lists',
|
||||
'publish_vp_lists',
|
||||
);
|
||||
|
||||
/**
|
||||
* Add capacities
|
||||
*/
|
||||
foreach ( $portfolio_cap as $cap ) {
|
||||
$wp_roles->add_cap( 'portfolio_manager', $cap );
|
||||
$wp_roles->add_cap( 'portfolio_author', $cap );
|
||||
$wp_roles->add_cap( 'administrator', $cap );
|
||||
$wp_roles->add_cap( 'editor', $cap );
|
||||
}
|
||||
foreach ( $lists_cap as $cap ) {
|
||||
$wp_roles->add_cap( 'portfolio_manager', $cap );
|
||||
$wp_roles->add_cap( 'administrator', $cap );
|
||||
}
|
||||
|
||||
update_option( 'visual_portfolio_updated_caps', $check_string );
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove screen options from vp list page.
|
||||
*
|
||||
* @param bool $return return default value.
|
||||
* @param object $screen_object screen object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function remove_screen_options( $return, $screen_object ) {
|
||||
if ( 'vp_lists' === $screen_object->id ) {
|
||||
return false;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add featured image in portfolio list
|
||||
*
|
||||
* @param array $columns columns of the table.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_portfolio_img_column( $columns = array() ) {
|
||||
$column_meta = array(
|
||||
'portfolio_post_thumbs' => esc_html__( 'Thumbnail', 'visual-portfolio' ),
|
||||
);
|
||||
|
||||
// insert after first column.
|
||||
$columns = array_slice( $columns, 0, 1, true ) + $column_meta + array_slice( $columns, 1, null, true );
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add thumb to the column
|
||||
*
|
||||
* @param bool $column_name column name.
|
||||
*/
|
||||
public function manage_portfolio_img_column( $column_name = false ) {
|
||||
if ( 'portfolio_post_thumbs' === $column_name ) {
|
||||
echo '<a href="' . esc_url( get_edit_post_link() ) . '" class="vp-portfolio__thumbnail">';
|
||||
if ( has_post_thumbnail() ) {
|
||||
the_post_thumbnail( 'thumbnail' );
|
||||
}
|
||||
echo '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show notice in vp_lists admin list page.
|
||||
*/
|
||||
public function add_vp_lists_notice() {
|
||||
$current_screen = get_current_screen();
|
||||
|
||||
if ( ! isset( $current_screen->post_type ) || 'vp_lists' !== $current_screen->post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="notice notice-info vpf-admin-notice">
|
||||
<div class="vpf-admin-notice-icon">
|
||||
<i class="dashicons-visual-portfolio"></i>
|
||||
</div>
|
||||
<div class="vpf-admin-notice-content">
|
||||
<h3>
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" width="24" height="24" xmlns="http://www.w3.org/2000/svg"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
|
||||
<?php echo esc_html__( 'When to use Saved Layouts', 'visual-portfolio' ); ?>
|
||||
</h3>
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses_post(
|
||||
sprintf(
|
||||
// translators: %1$s - url to documentation.
|
||||
// translators: %2$s - plugin name.
|
||||
__( 'If you are using the Gutenberg page builder for your pages and posts, you should <strong>avoid using Saved Layouts</strong>. See here more info about <a href="%1$s" target="_blank">%2$s Blocks</a>.', 'visual-portfolio' ),
|
||||
'https://visualportfolio.co/docs/portfolio-blocks/',
|
||||
visual_portfolio()->plugin_name
|
||||
)
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
// translators: %s - url to documentation.
|
||||
echo wp_kses_post( sprintf( __( 'To reuse blocks, you can use the built-in Gutenberg feature - <a href="%s" target="_blank">Reusable Blocks</a>.', 'visual-portfolio' ), 'https://www.wpbeginner.com/beginners-guide/how-to-create-a-reusable-block-in-wordpress/' ) );
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
// translators: %s - url to documentation.
|
||||
echo wp_kses_post( sprintf( __( 'Saved Layouts may be only used for 3rd-party builders (such as Elementor, WPBakery Page Builder, etc.), <a href="%s" target="_blank">read more info in documentation</a>. Since WordPress moved from Shortcodes to Blocks system, we prepared for you advanced blocks.', 'visual-portfolio' ), 'https://visualportfolio.co/docs/saved-layouts-and-shortcodes/' ) );
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Add icons and shortcode columns in vp_lists admin.
|
||||
*
|
||||
* @param array $columns columns of the table.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_vp_lists_custom_columns( $columns = array() ) {
|
||||
// Icon column.
|
||||
$column_icon = array(
|
||||
'vp_lists_post_icon' => esc_html__( 'Icon', 'visual-portfolio' ),
|
||||
);
|
||||
|
||||
// insert after first column.
|
||||
$columns = array_slice( $columns, 0, 1, true ) + $column_icon + array_slice( $columns, 1, null, true );
|
||||
|
||||
// Shortcode column.
|
||||
$column_shortcode = array(
|
||||
'vp_lists_post_shortcode' => esc_html__( 'Shortcode', 'visual-portfolio' ),
|
||||
);
|
||||
|
||||
// insert before last column.
|
||||
$columns = array_slice( $columns, 0, count( $columns ) - 1, true ) + $column_shortcode + array_slice( $columns, count( $columns ) - 1, null, true );
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add icons and shortcode columns in vp_lists admin.
|
||||
*
|
||||
* @param bool $column_name column name.
|
||||
*/
|
||||
public function manage_vp_lists_custom_columns( $column_name = false ) {
|
||||
if ( 'vp_lists_post_icon' === $column_name ) {
|
||||
$all_layouts = Visual_Portfolio_Get::get_all_layouts();
|
||||
$opts = Visual_Portfolio_Get::get_options( array( 'id' => get_the_ID() ) );
|
||||
$layout = isset( $opts['layout'] ) ? $opts['layout'] : false;
|
||||
$icon = '';
|
||||
|
||||
if ( $layout ) {
|
||||
foreach ( $all_layouts as $name => $data ) {
|
||||
if ( $name === $layout && isset( $data['icon'] ) ) {
|
||||
$icon = $data['icon'];
|
||||
}
|
||||
}
|
||||
|
||||
echo '<a href="' . esc_url( get_edit_post_link() ) . '" class="vp-portfolio-list__icon">';
|
||||
echo wp_kses( $icon, 'vp_svg' );
|
||||
echo '</a>';
|
||||
}
|
||||
}
|
||||
|
||||
if ( 'vp_lists_post_shortcode' === $column_name ) {
|
||||
echo '<code class="vp-onclick-selection" role="button" tabIndex="0" aria-hidden="true">';
|
||||
echo '[visual_portfolio id="' . get_the_ID() . '"]';
|
||||
echo '</code>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom filtering selects for vp_lists admin screen.
|
||||
*/
|
||||
public function restrict_manage_posts_vp_lists() {
|
||||
global $typenow;
|
||||
|
||||
if ( 'vp_lists' === $typenow ) {
|
||||
$all_layouts = Visual_Portfolio_Get::get_all_layouts();
|
||||
$all_items_styles = Visual_Portfolio_Get::get_all_items_styles();
|
||||
$all_content_sources = array(
|
||||
'post-based' => esc_html__( 'Posts', 'visual-portfolio' ),
|
||||
'images' => esc_html__( 'Images', 'visual-portfolio' ),
|
||||
'social-stream' => esc_html__( 'Social', 'visual-portfolio' ),
|
||||
);
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$selected_layout = isset( $_GET['vp_layout'] ) ? sanitize_text_field( wp_unslash( $_GET['vp_layout'] ) ) : '';
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$selected_items_style = isset( $_GET['vp_items_style'] ) ? sanitize_text_field( wp_unslash( $_GET['vp_items_style'] ) ) : '';
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$selected_content_source = isset( $_GET['vp_content_source'] ) ? sanitize_text_field( wp_unslash( $_GET['vp_content_source'] ) ) : '';
|
||||
|
||||
?>
|
||||
<select name="vp_layout" id="filter-by-vp_layout">
|
||||
<option value="0"><?php echo esc_html__( 'All layouts', 'visual-portfolio' ); ?></option>
|
||||
<?php
|
||||
foreach ( $all_layouts as $name => $data ) {
|
||||
?>
|
||||
<option value="<?php echo esc_attr( $name ); ?>" <?php echo $name === $selected_layout ? 'selected="selected"' : ''; ?>><?php echo esc_html( $data['title'] ); ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<select name="vp_items_style" id="filter-by-vp_items_style">
|
||||
<option value="0"><?php echo esc_html__( 'All styles', 'visual-portfolio' ); ?></option>
|
||||
<?php
|
||||
foreach ( $all_items_styles as $name => $data ) {
|
||||
?>
|
||||
<option value="<?php echo esc_attr( $name ); ?>" <?php echo $name === $selected_items_style ? 'selected="selected"' : ''; ?>><?php echo esc_html( $data['title'] ); ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<select name="vp_content_source" id="filter-by-vp_content_source">
|
||||
<option value="0"><?php echo esc_html__( 'All sources', 'visual-portfolio' ); ?></option>
|
||||
<?php
|
||||
foreach ( $all_content_sources as $name => $title ) {
|
||||
?>
|
||||
<option value="<?php echo esc_attr( $name ); ?>" <?php echo $name === $selected_content_source ? 'selected="selected"' : ''; ?>><?php echo esc_html( $title ); ?></option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom filtering for vp_lists admin screen.
|
||||
*
|
||||
* @param object $query - current query data.
|
||||
*/
|
||||
public function parse_query_vp_lists( $query ) {
|
||||
global $pagenow;
|
||||
|
||||
$q_vars = &$query->query_vars;
|
||||
|
||||
if ( 'edit.php' === $pagenow && isset( $q_vars['post_type'] ) && 'vp_lists' === $q_vars['post_type'] ) {
|
||||
$meta_query = array();
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$filter_layout = isset( $_GET['vp_layout'] ) ? sanitize_text_field( wp_unslash( $_GET['vp_layout'] ) ) : '';
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$filter_items_style = isset( $_GET['vp_items_style'] ) ? sanitize_text_field( wp_unslash( $_GET['vp_items_style'] ) ) : '';
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
$filter_content_source = isset( $_GET['vp_content_source'] ) ? sanitize_text_field( wp_unslash( $_GET['vp_content_source'] ) ) : '';
|
||||
|
||||
if ( $filter_layout ) {
|
||||
$meta_query[] = array(
|
||||
'key' => 'vp_layout',
|
||||
'value' => $filter_layout,
|
||||
);
|
||||
}
|
||||
if ( $filter_items_style ) {
|
||||
$meta_query[] = array(
|
||||
'key' => 'vp_items_style',
|
||||
'value' => $filter_items_style,
|
||||
);
|
||||
}
|
||||
if ( $filter_content_source ) {
|
||||
$meta_query[] = array(
|
||||
'key' => 'vp_content_source',
|
||||
'value' => $filter_content_source,
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $meta_query ) ) {
|
||||
// phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
|
||||
$q_vars['meta_query'] = $meta_query;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowed blocks for vp_lists post type.
|
||||
*
|
||||
* @param array $allowed_block_types - blocks.
|
||||
* @param object $editor_context - editor context.
|
||||
* @return array
|
||||
*/
|
||||
public function vp_lists_allowed_block_types_all( $allowed_block_types, $editor_context ) {
|
||||
if ( empty( $editor_context->post ) || 'vp_lists' !== $editor_context->post->post_type ) {
|
||||
return $allowed_block_types;
|
||||
}
|
||||
|
||||
return array( 'visual-portfolio/saved-editor' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add admin dropdown menu with all used Layouts on the current page.
|
||||
*/
|
||||
public function wp_before_admin_bar_render() {
|
||||
global $wp_admin_bar;
|
||||
|
||||
if ( ! is_super_admin() || ! is_admin_bar_showing() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add all nodes of all Slider.
|
||||
$layouts = Visual_Portfolio_Get::get_all_used_layouts();
|
||||
$layouts = array_unique( $layouts );
|
||||
|
||||
if ( ! empty( $layouts ) ) {
|
||||
$wp_admin_bar->add_node(
|
||||
array(
|
||||
'parent' => false,
|
||||
'id' => 'visual_portfolio',
|
||||
'title' => visual_portfolio()->plugin_name,
|
||||
'href' => admin_url( 'edit.php?post_type=vp_lists' ),
|
||||
)
|
||||
);
|
||||
|
||||
// get visual-portfolio post types by IDs.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408 .
|
||||
$vp_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
'post__in' => $layouts,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
foreach ( $vp_query as $post ) {
|
||||
$wp_admin_bar->add_node(
|
||||
array(
|
||||
'parent' => 'visual_portfolio',
|
||||
'id' => 'vp_list_' . esc_html( $post->ID ),
|
||||
'title' => esc_html( $post->post_title ),
|
||||
'href' => admin_url( 'post.php?post=' . $post->ID ) . '&action=edit',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force set Gutenberg editor for 'vp_lists' in Classic Editor plugin.
|
||||
*
|
||||
* @param array $editors Associative array of the editors and whether they are enabled for the post type.
|
||||
* @param string $post_type The post type.
|
||||
*/
|
||||
public function vp_lists_classic_plugin_force_gutenberg( $editors, $post_type ) {
|
||||
if ( 'vp_lists' !== $post_type ) {
|
||||
return $editors;
|
||||
}
|
||||
|
||||
return array(
|
||||
'classic_editor' => false,
|
||||
'block_editor' => true,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Force set Gutenberg editor for 'vp_lists' in Classic Editor plugin.
|
||||
*
|
||||
* @param boolean $use_block_editor Use block editor.
|
||||
* @param string $post_type The post type.
|
||||
*/
|
||||
public function vp_lists_classic_plugin_force_gutenberg_2( $use_block_editor, $post_type ) {
|
||||
if ( 'vp_lists' !== $post_type ) {
|
||||
return $use_block_editor;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force set Gutenberg editor for 'vp_lists' in 3rd-party plugins/themes, that uses their own builders.
|
||||
*
|
||||
* @param boolean $use_block_editor Use block editor.
|
||||
* @param object $post The post object.
|
||||
*/
|
||||
public function vp_lists_classic_plugin_force_gutenberg_3( $use_block_editor, $post ) {
|
||||
if ( isset( $post->post_type ) && 'vp_lists' === $post->post_type ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $use_block_editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force enable Gutenberg in 'vp_lists' for users with disabled option "Visual Editor".
|
||||
*
|
||||
* @param boolean $enabled Rich edit enabled.
|
||||
*/
|
||||
public function vp_lists_user_can_richedit_force( $enabled ) {
|
||||
global $post_type;
|
||||
|
||||
if ( isset( $post_type ) && 'vp_lists' !== $post_type ) {
|
||||
return $enabled;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Admin Page
|
||||
*/
|
||||
public function admin_menu() {
|
||||
// Remove Add New submenu item.
|
||||
remove_submenu_page( self::get_menu_slug(), 'post-new.php?post_type=portfolio' );
|
||||
|
||||
// Documentation menu link.
|
||||
add_submenu_page(
|
||||
self::get_menu_slug(),
|
||||
esc_html__( 'Documentation', 'visual-portfolio' ),
|
||||
esc_html__( 'Documentation', 'visual-portfolio' ),
|
||||
'manage_options',
|
||||
Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'sub_path' => 'docs/getting-started',
|
||||
'utm_campaign' => 'docs',
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Proofing Admin Page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_proofing_admin_menu() {
|
||||
// Proofing menu link.
|
||||
add_submenu_page(
|
||||
self::get_menu_slug(),
|
||||
esc_html__( 'Proofing', 'visual-portfolio' ),
|
||||
esc_html__( 'Proofing', 'visual-portfolio' ),
|
||||
'manage_options',
|
||||
'vpf_proofing_page',
|
||||
array( $this, 'go_proofing_pro_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Proofing.
|
||||
* Render of proofing page.
|
||||
*/
|
||||
public function go_proofing_pro_page() {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( ! isset( $_GET['page'] ) || empty( $_GET['page'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification
|
||||
if ( 'vpf_proofing_page' === $_GET['page'] ) {
|
||||
$pro_url = Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'utm_medium' => 'settings_page',
|
||||
'utm_campaign' => 'proofing',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<table class="form-table" role="presentation">
|
||||
<tbody>
|
||||
<tr class="pro_info vpf-setting-type-html">
|
||||
<td>
|
||||
<div class="vpf-pro-note vpf-settings-info-pro">
|
||||
<h3>
|
||||
<?php echo esc_html__( 'Premium Only', 'visual-portfolio' ); ?>
|
||||
</h3>
|
||||
<div>
|
||||
<p class="vpf-pro-note-description"><?php echo esc_html__( 'Send a collection of photographs to your client for approval.', 'visual-portfolio' ); ?></p>
|
||||
<a class="vpf-pro-note-button" target="_blank" rel="noopener noreferrer" href="<?php echo esc_url( $pro_url ); ?>">
|
||||
<?php echo esc_html__( 'Go Pro', 'visual-portfolio' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Custom_Post_Type();
|
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/**
|
||||
* Checks if another version of Visual Portfolio/Visual Portfolio Pro is active and deactivates it.
|
||||
*
|
||||
* @package visual-portfolio/deactivate-duplicate-plugin
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Deactivate_Duplicate_Plugin
|
||||
*/
|
||||
class Visual_Portfolio_Deactivate_Duplicate_Plugin {
|
||||
/**
|
||||
* Visual_Portfolio_Deactivate_Duplicate_Plugin constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'activated_plugin', array( $this, 'deactivate_other_instances' ) );
|
||||
add_action( 'pre_current_active_plugins', array( $this, 'plugin_deactivated_notice' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if another version of Visual Portfolio/Visual Portfolio Pro is active and deactivates it.
|
||||
* Hooked on `activated_plugin` so other plugin is deactivated when current plugin is activated.
|
||||
*
|
||||
* @param string $plugin The plugin being activated.
|
||||
*/
|
||||
public function deactivate_other_instances( $plugin ) {
|
||||
if ( ! in_array( $plugin, array( 'visual-portfolio/class-visual-portfolio.php', 'visual-portfolio-pro/class-visual-portfolio-pro.php' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$plugin_to_deactivate = 'visual-portfolio/class-visual-portfolio.php';
|
||||
$deactivated_notice_id = 1;
|
||||
|
||||
// If we just activated the free version, deactivate the Pro version.
|
||||
if ( $plugin === $plugin_to_deactivate ) {
|
||||
$plugin_to_deactivate = 'visual-portfolio-pro/class-visual-portfolio-pro.php';
|
||||
$deactivated_notice_id = 2;
|
||||
}
|
||||
|
||||
if ( is_multisite() && is_network_admin() ) {
|
||||
$active_plugins = (array) get_site_option( 'active_sitewide_plugins', array() );
|
||||
$active_plugins = array_keys( $active_plugins );
|
||||
} else {
|
||||
$active_plugins = (array) get_option( 'active_plugins', array() );
|
||||
}
|
||||
|
||||
foreach ( $active_plugins as $plugin_basename ) {
|
||||
if ( $plugin_to_deactivate === $plugin_basename ) {
|
||||
set_transient( 'vp_deactivated_notice_id', $deactivated_notice_id, 1 * HOUR_IN_SECONDS );
|
||||
deactivate_plugins( $plugin_basename );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a notice when either Visual Portfolio or Visual Portfolio Pro is automatically deactivated.
|
||||
*/
|
||||
public function plugin_deactivated_notice() {
|
||||
$deactivated_notice_id = (int) get_transient( 'vp_deactivated_notice_id' );
|
||||
if ( ! in_array( $deactivated_notice_id, array( 1, 2 ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = __( "Visual Portfolio and Visual Portfolio Pro should not be active at the same time. We've automatically deactivated Visual Portfolio.", 'visual-portfolio' );
|
||||
if ( 2 === $deactivated_notice_id ) {
|
||||
$message = __( "Visual Portfolio and Visual Portfolio Pro should not be active at the same time. We've automatically deactivated Visual Portfolio Pro.", 'visual-portfolio' );
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="notice notice-warning">
|
||||
<p><?php echo esc_html( $message ); ?></p>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
delete_transient( 'vp_deactivated_notice_id' );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Deactivate_Duplicate_Plugin();
|
418
wp-content/plugins/visual-portfolio/classes/class-deprecated.php
Normal file
418
wp-content/plugins/visual-portfolio/classes/class-deprecated.php
Normal file
@ -0,0 +1,418 @@
|
||||
<?php
|
||||
/**
|
||||
* Deprecations.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Deprecations
|
||||
*/
|
||||
class Visual_Portfolio_Deprecations {
|
||||
/**
|
||||
* The list of all deprecated hooks.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $hooks = array();
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Deprecations constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Deprecated filters since v2.9.0.
|
||||
$this->add_deprecated_filter( 'vpf_print_layout_control_args', '2.9.0', 'vpf_registered_control_args' );
|
||||
$this->add_deprecated_filter( 'vpf_get_layout_option', '2.9.0', 'vpf_control_value' );
|
||||
$this->add_deprecated_filter( 'vpf_extend_popup_image', '2.9.0', 'vpf_popup_image_data' );
|
||||
$this->add_deprecated_filter( 'vpf_extend_custom_popup_image', '2.9.0', 'vpf_popup_custom_image_data' );
|
||||
$this->add_deprecated_filter( 'vpf_print_popup_data', '2.9.0', 'vpf_popup_output' );
|
||||
$this->add_deprecated_filter( 'vpf_wp_get_attachment_image_extend', '2.9.0', 'vpf_wp_get_attachment_image' );
|
||||
|
||||
// Deprecated some builtin_controls for skins v3.0.0.
|
||||
add_filter( 'vpf_items_style_builtin_controls_options', array( $this, 'deprecated_vpf_items_style_builtin_controls_options' ), 20 );
|
||||
add_filter( 'vpf_items_style_builtin_controls', array( $this, 'deprecated_vpf_items_style_builtin_controls' ), 20, 4 );
|
||||
add_filter( 'vpf_get_options', array( $this, 'deprecated_items_styles_attributes' ), 20, 2 );
|
||||
|
||||
// Deprecated image args for wp kses since v2.10.4.
|
||||
// Since v2.20.0 we are using the `vp_image` kses.
|
||||
add_filter( 'vpf_image_item_args', array( $this, 'deprecated_image_kses_args' ), 9 );
|
||||
add_filter( 'vpf_post_item_args', array( $this, 'deprecated_image_kses_args' ), 9 );
|
||||
|
||||
// Deprecated image noscript argument since v2.6.0.
|
||||
add_filter( 'vpf_each_item_args', array( $this, 'deprecated_noscript_args' ), 9 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Deprecated Filter
|
||||
*
|
||||
* @param string $deprecated The deprecated hook.
|
||||
* @param string $version The version this hook was deprecated.
|
||||
* @param string $replacement The replacement hook.
|
||||
*/
|
||||
public function add_deprecated_filter( $deprecated, $version, $replacement ) {
|
||||
// Store replacement data.
|
||||
$this->hooks[] = array(
|
||||
'type' => 'filter',
|
||||
'deprecated' => $deprecated,
|
||||
'replacement' => $replacement,
|
||||
'version' => $version,
|
||||
);
|
||||
|
||||
// Add generic handler.
|
||||
// Use a priority of 10, and accepted args of 10 (ignored by WP).
|
||||
add_filter( $replacement, array( $this, 'apply_deprecated_hook' ), 10, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Deprecated Action
|
||||
*
|
||||
* @param string $deprecated The deprecated hook.
|
||||
* @param string $version The version this hook was deprecated.
|
||||
* @param string $replacement The replacement hook.
|
||||
*/
|
||||
public function add_deprecated_action( $deprecated, $version, $replacement ) {
|
||||
// Store replacement data.
|
||||
$this->hooks[] = array(
|
||||
'type' => 'action',
|
||||
'deprecated' => $deprecated,
|
||||
'replacement' => $replacement,
|
||||
'version' => $version,
|
||||
);
|
||||
|
||||
// Add generic handler.
|
||||
// Use a priority of 10, and accepted args of 10 (ignored by WP).
|
||||
add_action( $replacement, array( $this, 'apply_deprecated_hook' ), 10, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply Deprecated Hook
|
||||
*
|
||||
* Apply a deprecated filter during apply_filters() or do_action().
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function apply_deprecated_hook() {
|
||||
// Get current hook.
|
||||
$hook_name = current_filter();
|
||||
|
||||
// Get args provided to function.
|
||||
$args = func_get_args();
|
||||
|
||||
foreach ( $this->hooks as $hook_data ) {
|
||||
if ( $hook_name !== $hook_data['replacement'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if anyone is hooked into this deprecated hook.
|
||||
if ( has_filter( $hook_data['deprecated'] ) ) {
|
||||
// Log warning.
|
||||
// Most probably we will add it later.
|
||||
//
|
||||
// _deprecated_hook( $hook_data['deprecated'], $hook_data['version'], $hook_name ); .
|
||||
|
||||
// Apply filters.
|
||||
if ( 'filter' === $hook_data['type'] ) {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
|
||||
$args[0] = apply_filters_ref_array( $hook_data['deprecated'], $args );
|
||||
|
||||
// Or do action.
|
||||
} else {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.DynamicHooknameFound
|
||||
do_action_ref_array( $hook_data['deprecated'], $args );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return first arg.
|
||||
return $args[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore some old builtin_controls for skins.
|
||||
*
|
||||
* @param array $builtin_controls - builtin default controls.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function deprecated_vpf_items_style_builtin_controls_options( $builtin_controls ) {
|
||||
return array_merge(
|
||||
$builtin_controls,
|
||||
array(
|
||||
'images_rounded_corners' => true,
|
||||
'show_title' => true,
|
||||
'show_categories' => true,
|
||||
'show_date' => true,
|
||||
'show_author' => true,
|
||||
'show_comments_count' => true,
|
||||
'show_views_count' => true,
|
||||
'show_reading_time' => true,
|
||||
'show_excerpt' => true,
|
||||
'show_icons' => true,
|
||||
'align' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore some old builtin_controls for skins.
|
||||
*
|
||||
* @param array $fields - builtin fields.
|
||||
* @param string $option_name - option name.
|
||||
* @param array $options - builtin field options.
|
||||
* @param string $style_name - items style name.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function deprecated_vpf_items_style_builtin_controls( $fields, $option_name, $options, $style_name ) {
|
||||
switch ( $option_name ) {
|
||||
case 'images_rounded_corners':
|
||||
$fields[] = array(
|
||||
'type' => 'range',
|
||||
'label' => esc_html__( 'Images Rounded Corners', 'visual-portfolio' ),
|
||||
'name' => 'images_rounded_corners',
|
||||
'min' => 0,
|
||||
'max' => 100,
|
||||
'default' => 0,
|
||||
'style' => array(
|
||||
array(
|
||||
'element' => '.vp-portfolio__items-style-' . $style_name,
|
||||
'property' => '--vp-items-style-' . $style_name . '--image__border-radius',
|
||||
'mask' => '$px',
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'show_title':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Title', 'visual-portfolio' ),
|
||||
'name' => 'show_title',
|
||||
'default' => true,
|
||||
);
|
||||
break;
|
||||
case 'show_categories':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Categories', 'visual-portfolio' ),
|
||||
'name' => 'show_categories',
|
||||
'group' => 'items_style_categories',
|
||||
'default' => true,
|
||||
);
|
||||
$fields[] = array(
|
||||
'type' => 'range',
|
||||
'label' => esc_html__( 'Categories Count', 'visual-portfolio' ),
|
||||
'name' => 'categories_count',
|
||||
'group' => 'items_style_categories',
|
||||
'min' => 1,
|
||||
'max' => 20,
|
||||
'default' => 1,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => 'show_categories',
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'show_date':
|
||||
$fields[] = array(
|
||||
'type' => 'radio',
|
||||
'label' => esc_html__( 'Display Date', 'visual-portfolio' ),
|
||||
'name' => 'show_date',
|
||||
'group' => 'items_style_date',
|
||||
'default' => 'false',
|
||||
'options' => array(
|
||||
'false' => esc_html__( 'Hide', 'visual-portfolio' ),
|
||||
'true' => esc_html__( 'Default', 'visual-portfolio' ),
|
||||
'human' => esc_html__( 'Human Format', 'visual-portfolio' ),
|
||||
),
|
||||
);
|
||||
$fields[] = array(
|
||||
'type' => 'text',
|
||||
'name' => 'date_format',
|
||||
'group' => 'items_style_date',
|
||||
'default' => 'F j, Y',
|
||||
'description' => esc_attr__( 'Date format example: F j, Y', 'visual-portfolio' ),
|
||||
'wpml' => true,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => 'show_date',
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'show_author':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Author', 'visual-portfolio' ),
|
||||
'name' => 'show_author',
|
||||
'default' => false,
|
||||
);
|
||||
break;
|
||||
case 'show_comments_count':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Comments Count', 'visual-portfolio' ),
|
||||
'name' => 'show_comments_count',
|
||||
'default' => false,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => 'GLOBAL_content_source',
|
||||
'value' => 'post-based',
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'show_views_count':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Views Count', 'visual-portfolio' ),
|
||||
'name' => 'show_views_count',
|
||||
'default' => false,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => 'GLOBAL_content_source',
|
||||
'value' => 'post-based',
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'show_reading_time':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Reading Time', 'visual-portfolio' ),
|
||||
'name' => 'show_reading_time',
|
||||
'default' => false,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => 'GLOBAL_content_source',
|
||||
'value' => 'post-based',
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'show_excerpt':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Excerpt', 'visual-portfolio' ),
|
||||
'name' => 'show_excerpt',
|
||||
'group' => 'items_style_excerpt',
|
||||
'default' => false,
|
||||
);
|
||||
$fields[] = array(
|
||||
'type' => 'number',
|
||||
'label' => esc_html__( 'Excerpt Words Count', 'visual-portfolio' ),
|
||||
'name' => 'excerpt_words_count',
|
||||
'group' => 'items_style_excerpt',
|
||||
'default' => 15,
|
||||
'min' => 1,
|
||||
'max' => 200,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => 'show_excerpt',
|
||||
),
|
||||
),
|
||||
);
|
||||
break;
|
||||
case 'show_icons':
|
||||
$fields[] = array(
|
||||
'type' => 'checkbox',
|
||||
'alongside' => esc_html__( 'Display Icon', 'visual-portfolio' ),
|
||||
'name' => 'show_icon',
|
||||
'default' => false,
|
||||
);
|
||||
break;
|
||||
case 'align':
|
||||
$fields[] = array(
|
||||
'type' => 'align',
|
||||
'label' => esc_html__( 'Caption Align', 'visual-portfolio' ),
|
||||
'name' => 'align',
|
||||
'default' => 'center',
|
||||
'extended' => 'extended' === $options,
|
||||
);
|
||||
break;
|
||||
// no default.
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add attributes to block rendering as a fallback
|
||||
* to prevent errors in changed templates.
|
||||
*
|
||||
* @param array $options - block options.
|
||||
* @param array $attrs - block attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function deprecated_items_styles_attributes( $options, $attrs ) {
|
||||
$styles = array( 'default', 'fade', 'fly', 'emerge' );
|
||||
|
||||
foreach ( $styles as $style ) {
|
||||
// Restore align option.
|
||||
if ( ! isset( $options[ 'items_style_' . $style . '__align' ] ) ) {
|
||||
$options[ 'items_style_' . $style . '__align' ] = $attrs[ 'items_style_' . $style . '__align' ] ?? 'center';
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allowed attributes for wp_kses used in vp images.
|
||||
*
|
||||
* @param array $args vp item args.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function deprecated_image_kses_args( $args ) {
|
||||
if ( ! isset( $args['image_allowed_html'] ) ) {
|
||||
$args['image_allowed_html'] = array();
|
||||
}
|
||||
if ( ! isset( $args['image_allowed_html']['img'] ) ) {
|
||||
$args['image_allowed_html']['img'] = array();
|
||||
}
|
||||
|
||||
$args['image_allowed_html']['noscript'] = array();
|
||||
$args['image_allowed_html']['img'] = array_merge(
|
||||
$args['image_allowed_html']['img'],
|
||||
array(
|
||||
'src' => array(),
|
||||
'srcset' => array(),
|
||||
'sizes' => array(),
|
||||
'alt' => array(),
|
||||
'class' => array(),
|
||||
'width' => array(),
|
||||
'height' => array(),
|
||||
|
||||
// Lazy loading attributes.
|
||||
'loading' => array(),
|
||||
'data-src' => array(),
|
||||
'data-sizes' => array(),
|
||||
'data-srcset' => array(),
|
||||
'data-no-lazy' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add noscript string to prevent errors in old templates.
|
||||
*
|
||||
* @param array $args vp item args.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function deprecated_noscript_args( $args ) {
|
||||
$args['image_noscript'] = '';
|
||||
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Deprecations();
|
2828
wp-content/plugins/visual-portfolio/classes/class-get-portfolio.php
Normal file
2828
wp-content/plugins/visual-portfolio/classes/class-get-portfolio.php
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* Gutenberg block.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Gutenberg_Saved_Block
|
||||
*/
|
||||
class Visual_Portfolio_Gutenberg_Saved_Block {
|
||||
/**
|
||||
* Registered controls, that will be used in Gutenberg block.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $registered_controls = array();
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Gutenberg_Saved_Block constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'register_block' ), 11 );
|
||||
add_action( 'admin_init', array( $this, 'register_block_layouts_editor' ), 11 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Block.
|
||||
*/
|
||||
public function register_block() {
|
||||
if ( ! function_exists( 'register_block_type_from_metadata' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
register_block_type_from_metadata(
|
||||
visual_portfolio()->plugin_path . 'gutenberg/block-saved',
|
||||
array(
|
||||
'render_callback' => array( $this, 'block_render' ),
|
||||
)
|
||||
);
|
||||
|
||||
// Fallback.
|
||||
register_block_type_from_metadata(
|
||||
'nk/visual-portfolio',
|
||||
array(
|
||||
'render_callback' => array( $this, 'block_render' ),
|
||||
'attributes' => array(
|
||||
'id' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'align' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'className' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'anchor' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Block for Layouts Editor.
|
||||
*/
|
||||
public function register_block_layouts_editor() {
|
||||
global $pagenow;
|
||||
|
||||
if (
|
||||
'post.php' === $pagenow && isset( $_GET['post'] ) && 'vp_lists' === get_post_type( $_GET['post'] ) ||
|
||||
'post-new.php' === $pagenow && isset( $_GET['post_type'] ) && 'vp_lists' === $_GET['post_type']
|
||||
) {
|
||||
register_block_type_from_metadata(
|
||||
visual_portfolio()->plugin_path . 'gutenberg/layouts-editor/block'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block output
|
||||
*
|
||||
* @param array $attributes - block attributes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function block_render( $attributes ) {
|
||||
$attributes = array_merge(
|
||||
array(
|
||||
'id' => '',
|
||||
'align' => '',
|
||||
'className' => '',
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
|
||||
if ( ! $attributes['id'] ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// WPML support.
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
|
||||
$attributes['id'] = apply_filters( 'wpml_object_id', $attributes['id'], 'vp_lists', true );
|
||||
|
||||
$class_name = 'wp-block-visual-portfolio';
|
||||
|
||||
$wrapper_attributes = get_block_wrapper_attributes(
|
||||
array(
|
||||
'class' => $class_name,
|
||||
)
|
||||
);
|
||||
|
||||
return sprintf( '<div %1$s>%2$s</div>', $wrapper_attributes, Visual_Portfolio_Get::get( array( 'id' => $attributes['id'] ) ) );
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_Gutenberg_Saved_Block();
|
254
wp-content/plugins/visual-portfolio/classes/class-gutenberg.php
Normal file
254
wp-content/plugins/visual-portfolio/classes/class-gutenberg.php
Normal file
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
/**
|
||||
* Gutenberg block.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Gutenberg_Block
|
||||
*/
|
||||
class Visual_Portfolio_Gutenberg_Block {
|
||||
/**
|
||||
* Cached block attributes, we will use it when register block in PHP and in JS.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cached_attributes = array();
|
||||
|
||||
/**
|
||||
* Registered controls, that will be used in Gutenberg block.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $registered_controls = array();
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Gutenberg_Block constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'register_block' ), 11 );
|
||||
add_action( 'enqueue_block_assets', array( $this, 'enqueue_block_editor_assets' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get block attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_block_attributes() {
|
||||
if ( ! empty( $this->cached_attributes ) ) {
|
||||
return $this->cached_attributes;
|
||||
}
|
||||
|
||||
// Default attributes.
|
||||
$attributes = array(
|
||||
'block_id' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'align' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'className' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'anchor' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
);
|
||||
|
||||
// Add dynamic attributes from registered controls.
|
||||
$controls = Visual_Portfolio_Controls::get_registered_array();
|
||||
|
||||
foreach ( $controls as $control ) {
|
||||
if ( isset( $attributes[ $control['name'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
'html' === $control['type'] ||
|
||||
'notice' === $control['type'] ||
|
||||
'pro_note' === $control['type'] ||
|
||||
'category_tabs' === $control['type'] ||
|
||||
'category_toggle_group' === $control['type'] ||
|
||||
'category_collapse' === $control['type'] ||
|
||||
'category_navigator' === $control['type']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attribute_data = apply_filters(
|
||||
'vpf_register_block_attribute_data',
|
||||
array(
|
||||
'type' => 'string',
|
||||
),
|
||||
$control
|
||||
);
|
||||
|
||||
if ( ! $attribute_data ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributes[ $control['name'] ] = $attribute_data;
|
||||
|
||||
switch ( $control['type'] ) {
|
||||
case 'checkbox':
|
||||
case 'toggle':
|
||||
$attributes[ $control['name'] ]['type'] = 'boolean';
|
||||
break;
|
||||
case 'number':
|
||||
case 'range':
|
||||
$attributes[ $control['name'] ]['type'] = 'number';
|
||||
break;
|
||||
case 'select':
|
||||
case 'select2':
|
||||
if ( $control['multiple'] ) {
|
||||
$attributes[ $control['name'] ]['type'] = 'array';
|
||||
$attributes[ $control['name'] ]['items'] = array(
|
||||
'type' => 'string',
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'sortable':
|
||||
$attributes[ $control['name'] ]['type'] = 'array';
|
||||
$attributes[ $control['name'] ]['items'] = array(
|
||||
'type' => 'string',
|
||||
);
|
||||
break;
|
||||
case 'gallery':
|
||||
$attributes[ $control['name'] ]['type'] = 'array';
|
||||
$attributes[ $control['name'] ]['items'] = array(
|
||||
'type' => 'object',
|
||||
);
|
||||
break;
|
||||
case 'elements_selector':
|
||||
$attributes[ $control['name'] ]['type'] = 'object';
|
||||
$attributes[ $control['name'] ]['items'] = array(
|
||||
'type' => 'object',
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( isset( $control['default'] ) ) {
|
||||
$attributes[ $control['name'] ]['default'] = $control['default'];
|
||||
}
|
||||
}
|
||||
|
||||
$attributes = apply_filters(
|
||||
'vpf_register_block_attributes',
|
||||
$attributes,
|
||||
$controls
|
||||
);
|
||||
|
||||
$this->cached_attributes = $attributes;
|
||||
|
||||
return $this->cached_attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Block.
|
||||
*/
|
||||
public function register_block() {
|
||||
if ( ! function_exists( 'register_block_type_from_metadata' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = $this->get_block_attributes();
|
||||
|
||||
register_block_type_from_metadata(
|
||||
visual_portfolio()->plugin_path . 'gutenberg/block',
|
||||
array(
|
||||
'render_callback' => array( $this, 'block_render' ),
|
||||
'attributes' => $attributes,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Block output
|
||||
*
|
||||
* @param array $attributes - block attributes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function block_render( $attributes ) {
|
||||
$attributes = array_merge(
|
||||
array(
|
||||
'align' => '',
|
||||
'className' => '',
|
||||
),
|
||||
$attributes
|
||||
);
|
||||
|
||||
$class_name = 'wp-block-visual-portfolio';
|
||||
|
||||
$wrapper_attributes = get_block_wrapper_attributes(
|
||||
array(
|
||||
'class' => $class_name,
|
||||
)
|
||||
);
|
||||
|
||||
return sprintf( '<div %1$s>%2$s</div>', $wrapper_attributes, Visual_Portfolio_Get::get( $attributes ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue script for Gutenberg editor
|
||||
*/
|
||||
public function enqueue_block_editor_assets() {
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$attributes = $this->get_block_attributes();
|
||||
|
||||
// Block.
|
||||
Visual_Portfolio_Assets::enqueue_script(
|
||||
'visual-portfolio-gutenberg',
|
||||
'build/gutenberg/index',
|
||||
array( 'masonry' )
|
||||
);
|
||||
Visual_Portfolio_Assets::enqueue_style(
|
||||
'visual-portfolio-gutenberg',
|
||||
'build/gutenberg/index'
|
||||
);
|
||||
wp_style_add_data( 'visual-portfolio-gutenberg', 'rtl', 'replace' );
|
||||
wp_style_add_data( 'visual-portfolio-gutenberg', 'suffix', '.min' );
|
||||
|
||||
wp_localize_script(
|
||||
'visual-portfolio-gutenberg',
|
||||
'VPGutenbergVariables',
|
||||
array(
|
||||
'nonce' => wp_create_nonce( 'vp-ajax-nonce' ),
|
||||
'plugin_version' => VISUAL_PORTFOLIO_VERSION,
|
||||
'plugin_name' => visual_portfolio()->plugin_name,
|
||||
'plugin_url' => visual_portfolio()->plugin_url,
|
||||
'admin_url' => get_admin_url(),
|
||||
'attributes' => $attributes,
|
||||
'controls' => Visual_Portfolio_Controls::get_registered_array(),
|
||||
'controls_categories' => Visual_Portfolio_Controls::get_registered_categories(),
|
||||
'items_count_notice' => get_option( 'visual_portfolio_items_count_notice_state', 'show' ),
|
||||
'items_count_notice_limit' => 40,
|
||||
)
|
||||
);
|
||||
|
||||
// Meta.
|
||||
Visual_Portfolio_Assets::enqueue_script(
|
||||
'visual-portfolio-gutenberg-custom-post-meta',
|
||||
'build/gutenberg/custom-post-meta'
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'visual-portfolio-gutenberg-custom-post-meta',
|
||||
'VPGutenbergMetaVariables',
|
||||
array(
|
||||
'nonce' => wp_create_nonce( 'vp-ajax-nonce' ),
|
||||
'plugin_name' => visual_portfolio()->plugin_name,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_Gutenberg_Block();
|
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
/**
|
||||
* Image placeholder.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Image_Placeholder
|
||||
*/
|
||||
class Visual_Portfolio_Image_Placeholder {
|
||||
/**
|
||||
* Visual_Portfolio_Image_Placeholder constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( is_admin() ) {
|
||||
add_action( 'admin_init', array( $this, 'create_placeholder_image' ), 3 );
|
||||
} else {
|
||||
add_action( 'wp', array( $this, 'create_placeholder_image' ), 3 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a placeholder image in the media library.
|
||||
* For code thanks to WooCommerce.
|
||||
*/
|
||||
public function create_placeholder_image() {
|
||||
// Run only on first plugin install.
|
||||
// This option added in Migration class.
|
||||
if ( get_option( 'vpf_db_version' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$general_settings = get_option( 'vp_general' );
|
||||
if ( ! is_array( $general_settings ) ) {
|
||||
$general_settings = array();
|
||||
}
|
||||
|
||||
// Don't run when already added placeholder.
|
||||
if ( isset( $general_settings['no_image'] ) && $general_settings['no_image'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Upload placeholder image to Media Library.
|
||||
$upload_dir = wp_upload_dir();
|
||||
$source = visual_portfolio()->plugin_path . '/assets/images/placeholder.png';
|
||||
$filename = $upload_dir['basedir'] . '/visual-portfolio/placeholder.png';
|
||||
|
||||
// try to move to /visual-portfolio/ directory.
|
||||
if ( ! file_exists( $upload_dir['basedir'] . '/visual-portfolio' ) ) {
|
||||
// phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
|
||||
@mkdir( $upload_dir['basedir'] . '/visual-portfolio', 0755, true );
|
||||
}
|
||||
if ( ! file_exists( $upload_dir['basedir'] . '/visual-portfolio' ) ) {
|
||||
$filename = $upload_dir['basedir'] . '/visual-portfolio-placeholder.png';
|
||||
}
|
||||
|
||||
if ( ! file_exists( $filename ) ) {
|
||||
copy( $source, $filename );
|
||||
}
|
||||
|
||||
if ( ! file_exists( $filename ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$filetype = wp_check_filetype( basename( $filename ), null );
|
||||
$attachment = array(
|
||||
'guid' => $upload_dir['url'] . '/' . basename( $filename ),
|
||||
'post_mime_type' => $filetype['type'],
|
||||
'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
|
||||
'post_content' => '',
|
||||
'post_status' => 'inherit',
|
||||
);
|
||||
$attach_id = wp_insert_attachment( $attachment, $filename );
|
||||
|
||||
// Update settings.
|
||||
$general_settings['no_image'] = $attach_id;
|
||||
update_option( 'vp_general', $general_settings );
|
||||
|
||||
// Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
|
||||
// Generate the metadata for the attachment, and update the database record.
|
||||
$attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
|
||||
wp_update_attachment_metadata( $attach_id, $attach_data );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Image_Placeholder();
|
641
wp-content/plugins/visual-portfolio/classes/class-images.php
Normal file
641
wp-content/plugins/visual-portfolio/classes/class-images.php
Normal file
@ -0,0 +1,641 @@
|
||||
<?php
|
||||
/**
|
||||
* Prepare placeholder and lazy load.
|
||||
*
|
||||
* @package visual-portfolio/images
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Images
|
||||
*/
|
||||
class Visual_Portfolio_Images {
|
||||
/**
|
||||
* When image process in progress with method get_attachment_image, this variable will be 'true'.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $image_processing = false;
|
||||
|
||||
/**
|
||||
* Allow Visual Portfolio images to use lazyload.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $allow_vp_lazyload = false;
|
||||
|
||||
/**
|
||||
* Allow WordPress images to use lazyload.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $allow_wp_lazyload = false;
|
||||
|
||||
/**
|
||||
* The list of exclusions from the plugin settings.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $lazyload_user_exclusions = array();
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Images constructor.
|
||||
*/
|
||||
public static function construct() {
|
||||
add_action( 'wp', 'Visual_Portfolio_Images::init_lazyload' );
|
||||
add_action( 'after_setup_theme', 'Visual_Portfolio_Images::add_image_sizes' );
|
||||
add_filter( 'image_size_names_choose', 'Visual_Portfolio_Images::image_size_names_choose' );
|
||||
|
||||
/**
|
||||
* Allow `data:` inside image src attribute.
|
||||
* Don't place this hook inside the `wp` hook.
|
||||
*
|
||||
* @link https://wordpress.org/support/topic/lazy-load-404-error-with-image-like-png/#post-16439422
|
||||
*/
|
||||
add_filter( 'kses_allowed_protocols', 'Visual_Portfolio_Images::kses_allowed_protocols', 15 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add image sizes.
|
||||
*/
|
||||
public static function add_image_sizes() {
|
||||
$sm = Visual_Portfolio_Settings::get_option( 'sm', 'vp_images' );
|
||||
$md = Visual_Portfolio_Settings::get_option( 'md', 'vp_images' );
|
||||
$lg = Visual_Portfolio_Settings::get_option( 'lg', 'vp_images' );
|
||||
$xl = Visual_Portfolio_Settings::get_option( 'xl', 'vp_images' );
|
||||
$sm_popup = Visual_Portfolio_Settings::get_option( 'sm_popup', 'vp_images' );
|
||||
$md_popup = Visual_Portfolio_Settings::get_option( 'md_popup', 'vp_images' );
|
||||
$xl_popup = Visual_Portfolio_Settings::get_option( 'xl_popup', 'vp_images' );
|
||||
|
||||
// custom image sizes.
|
||||
add_image_size( 'vp_sm', $sm, 9999 );
|
||||
add_image_size( 'vp_md', $md, 9999 );
|
||||
add_image_size( 'vp_lg', $lg, 9999 );
|
||||
add_image_size( 'vp_xl', $xl, 9999 );
|
||||
add_image_size( 'vp_sm_popup', $sm_popup, 9999 );
|
||||
add_image_size( 'vp_md_popup', $md_popup, 9999 );
|
||||
add_image_size( 'vp_xl_popup', $xl_popup, 9999 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom image sizes
|
||||
*
|
||||
* @param array $sizes - registered image sizes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function image_size_names_choose( $sizes ) {
|
||||
return array_merge(
|
||||
$sizes,
|
||||
array(
|
||||
'vp_sm' => esc_html__( 'Small (VP)', 'visual-portfolio' ),
|
||||
'vp_md' => esc_html__( 'Medium (VP)', 'visual-portfolio' ),
|
||||
'vp_lg' => esc_html__( 'Large (VP)', 'visual-portfolio' ),
|
||||
'vp_xl' => esc_html__( 'Extra Large (VP)', 'visual-portfolio' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get blocked attributes to prevent our images lazy loading.
|
||||
*/
|
||||
public static function get_image_blocked_attributes() {
|
||||
$blocked_attributes = array(
|
||||
'data-skip-lazy',
|
||||
'data-no-lazy',
|
||||
'data-src',
|
||||
'data-srcset',
|
||||
'data-lazy-original',
|
||||
'data-lazy-src',
|
||||
'data-lazysrc',
|
||||
'data-lazyload',
|
||||
'data-bgposition',
|
||||
'data-envira-src',
|
||||
'fullurl',
|
||||
'lazy-slider-img',
|
||||
);
|
||||
|
||||
/**
|
||||
* Allow plugins and themes to tell lazy images to skip an image with a given attribute.
|
||||
*/
|
||||
return apply_filters( 'vpf_lazyload_images_blocked_attributes', $blocked_attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init Lazyload
|
||||
*/
|
||||
public static function init_lazyload() {
|
||||
// Don't lazy load for feeds, previews and admin side.
|
||||
if ( is_feed() || is_preview() || is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't add on AMP endpoint.
|
||||
if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable using filter.
|
||||
// Same filter used in `class-assets.php`.
|
||||
if ( ! apply_filters( 'vpf_images_lazyload', true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::$allow_vp_lazyload = ! ! Visual_Portfolio_Settings::get_option( 'lazy_loading', 'vp_images' );
|
||||
self::$allow_wp_lazyload = 'full' === Visual_Portfolio_Settings::get_option( 'lazy_loading', 'vp_images' );
|
||||
|
||||
// Check for plugin settings.
|
||||
if ( ! self::$allow_vp_lazyload && ! self::$allow_wp_lazyload ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$lazyload_exclusions = Visual_Portfolio_Settings::get_option( 'lazy_loading_excludes', 'vp_images' );
|
||||
if ( $lazyload_exclusions ) {
|
||||
self::$lazyload_user_exclusions = explode( "\n", $lazyload_exclusions );
|
||||
|
||||
add_filter( 'vpf_lazyload_skip_image_with_attributes', 'Visual_Portfolio_Images::add_lazyload_exclusions', 10, 2 );
|
||||
}
|
||||
|
||||
if ( self::$allow_wp_lazyload ) {
|
||||
add_filter( 'the_content', 'Visual_Portfolio_Images::add_image_placeholders', 9999 );
|
||||
add_filter( 'post_thumbnail_html', 'Visual_Portfolio_Images::add_image_placeholders', 9999 );
|
||||
add_filter( 'get_avatar', 'Visual_Portfolio_Images::add_image_placeholders', 9999 );
|
||||
add_filter( 'widget_text', 'Visual_Portfolio_Images::add_image_placeholders', 9999 );
|
||||
add_filter( 'get_image_tag', 'Visual_Portfolio_Images::add_image_placeholders', 9999 );
|
||||
}
|
||||
|
||||
add_action( 'wp_kses_allowed_html', 'Visual_Portfolio_Images::allow_lazy_attributes' );
|
||||
add_action( 'wp_head', 'Visual_Portfolio_Images::add_nojs_fallback' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL of an image attachment.
|
||||
*
|
||||
* @param int $attachment_id Image attachment ID.
|
||||
* @param string|array $size Optional. Image size to retrieve. Accepts any valid image size, or an array
|
||||
* of width and height values in pixels (in that order). Default 'thumbnail'.
|
||||
* @param bool $icon Optional. Whether the image should be treated as an icon. Default false.
|
||||
*
|
||||
* @return string|false Attachment URL or false if no image is available.
|
||||
*/
|
||||
public static function wp_get_attachment_image_url( $attachment_id, $size = 'thumbnail', $icon = false ) {
|
||||
$mime_type = get_post_mime_type( $attachment_id );
|
||||
|
||||
// Prevent usage of resized GIFs, since GIFs animated only in full size.
|
||||
if ( $mime_type && 'image/gif' === $mime_type ) {
|
||||
$size = 'full';
|
||||
}
|
||||
|
||||
return wp_get_attachment_image_url( $attachment_id, $size, $icon );
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow attributes of Lazy Load for wp_kses.
|
||||
*
|
||||
* @param array $allowed_tags The allowed tags and their attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function allow_lazy_attributes( $allowed_tags ) {
|
||||
if ( ! isset( $allowed_tags['img'] ) ) {
|
||||
return $allowed_tags;
|
||||
}
|
||||
|
||||
// But, if images are allowed, ensure that our attributes are allowed!
|
||||
$img_attributes = array_merge(
|
||||
$allowed_tags['img'],
|
||||
array(
|
||||
'data-src' => 1,
|
||||
'data-sizes' => 1,
|
||||
'data-srcset' => 1,
|
||||
'data-no-lazy' => 1,
|
||||
'loading' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
$allowed_tags['img'] = $img_attributes;
|
||||
|
||||
return $allowed_tags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix img src attribute correction in wp_kses.
|
||||
*
|
||||
* @param array $protocols protocols array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function kses_allowed_protocols( $protocols ) {
|
||||
$protocols[] = 'data';
|
||||
return $protocols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add image placeholders.
|
||||
*
|
||||
* @param string $content Content.
|
||||
* @return string
|
||||
*/
|
||||
public static function add_image_placeholders( $content ) {
|
||||
// This is a pretty simple regex, but it works.
|
||||
//
|
||||
// 1. Find <img> tags
|
||||
// 2. Exclude tags, placed inside <noscript>.
|
||||
$content = preg_replace_callback( '#(?<!noscript\>)<(img)([^>]+?)(>(.*?)</\\1>|[\/]?>)#si', 'Visual_Portfolio_Images::process_image', $content );
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when a given array of attributes contains attributes or class signifying lazy images.
|
||||
* should not process the image.
|
||||
*
|
||||
* @param array $attributes all available image attributes.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function should_skip_image_with_blocked_attributes( $attributes ) {
|
||||
// Check for blocked classes.
|
||||
if ( ! empty( $attributes['class'] ) ) {
|
||||
$blocked_classes = array(
|
||||
'lazy',
|
||||
'lazyload',
|
||||
'lazy-load',
|
||||
'skip-lazy',
|
||||
'no-lazy',
|
||||
'gazette-featured-content-thumbnail',
|
||||
);
|
||||
|
||||
/**
|
||||
* Allow plugins and themes to tell lazy images to skip an image with a given class.
|
||||
*/
|
||||
$blocked_classes = apply_filters( 'vpf_lazyload_images_blocked_classes', $blocked_classes );
|
||||
|
||||
if ( is_array( $blocked_classes ) && ! empty( $blocked_classes ) ) {
|
||||
foreach ( $blocked_classes as $class ) {
|
||||
if ( false !== strpos( $attributes['class'], $class ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for blocked src.
|
||||
if ( ! empty( $attributes['src'] ) ) {
|
||||
$blocked_src = array(
|
||||
'/wpcf7_captcha/',
|
||||
'timthumb.php?src',
|
||||
);
|
||||
|
||||
/**
|
||||
* Allow plugins and themes to tell lazy images to skip an image with a given class.
|
||||
*/
|
||||
$blocked_src = apply_filters( 'vpf_lazyload_images_blocked_src', $blocked_src );
|
||||
|
||||
if ( is_array( $blocked_src ) && ! empty( $blocked_src ) ) {
|
||||
foreach ( $blocked_src as $src ) {
|
||||
if ( false !== strpos( $attributes['src'], $src ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$blocked_attributes = self::get_image_blocked_attributes();
|
||||
|
||||
foreach ( $blocked_attributes as $attr ) {
|
||||
if ( isset( $attributes[ $attr ] ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow plugins and themes to conditionally skip processing an image via its attributes.
|
||||
*/
|
||||
if ( apply_filters( 'vpf_lazyload_skip_image_with_attributes', false, $attributes ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip lazy loading using exclusion settings.
|
||||
*
|
||||
* @param boolean $return - default return value.
|
||||
* @param array $attributes - image attributes.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static function add_lazyload_exclusions( $return, $attributes ) {
|
||||
if ( ! empty( self::$lazyload_user_exclusions ) && ! empty( $attributes ) ) {
|
||||
$full_attributes_string = '';
|
||||
|
||||
foreach ( $attributes as $k => $attr ) {
|
||||
$full_attributes_string .= ' ' . $k . '="' . $attr . '"';
|
||||
}
|
||||
|
||||
foreach ( self::$lazyload_user_exclusions as $exclusion ) {
|
||||
if ( $exclusion && false !== strpos( $full_attributes_string, $exclusion ) ) {
|
||||
// `true` means - exclude this image from lazy loading.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes images in content by acting as the preg_replace_callback.
|
||||
*
|
||||
* @param array $matches Matches.
|
||||
*
|
||||
* @return string The image with updated lazy attributes.
|
||||
*/
|
||||
public static function process_image( $matches ) {
|
||||
$old_attributes_str = $matches[2];
|
||||
$old_attributes_kses_hair = wp_kses_hair( $old_attributes_str, wp_allowed_protocols() );
|
||||
|
||||
$fallback = $matches[0];
|
||||
|
||||
if ( empty( $old_attributes_kses_hair['src'] ) ) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$old_attributes = self::flatten_kses_hair_data( $old_attributes_kses_hair );
|
||||
|
||||
// Return original image if image is already lazy loaded.
|
||||
if ( ! empty( $old_attributes['class'] ) && false !== strpos( $old_attributes['class'], 'vp-lazyload' ) ) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
$new_attributes = self::process_image_attributes( $old_attributes );
|
||||
|
||||
// Return original image if new attributes does not contains the lazyload class.
|
||||
if ( empty( $new_attributes['class'] ) || false === strpos( $new_attributes['class'], 'vp-lazyload' ) ) {
|
||||
return $fallback;
|
||||
}
|
||||
|
||||
// Skip 3rd-party lazy loading from noscript img tag.
|
||||
$fallback = str_replace( ' src="', ' data-skip-lazy src="', $fallback );
|
||||
|
||||
$new_attributes_str = self::build_attributes_string( $new_attributes );
|
||||
|
||||
return sprintf( '<noscript>%1$s</noscript><img %2$s>', $fallback, $new_attributes_str );
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of image attributes, updates the `src`, `srcset`, and `sizes` attributes so
|
||||
* that they load lazily.
|
||||
*
|
||||
* @param array $attributes Attributes.
|
||||
*
|
||||
* @return array The updated image attributes array with lazy load attributes.
|
||||
*/
|
||||
public static function process_image_attributes( $attributes ) {
|
||||
// Skip lazy load from VPF images if option disabled.
|
||||
if ( ! self::$allow_vp_lazyload && self::$image_processing ) {
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
// Skip lazy load from WordPress images if option disabled.
|
||||
if ( ! self::$allow_wp_lazyload && ! self::$image_processing ) {
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
if ( empty( $attributes['src'] ) ) {
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
if ( self::should_skip_image_with_blocked_attributes( $attributes ) ) {
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
// Default Placeholder.
|
||||
$placeholder = false;
|
||||
$placeholder_w = isset( $attributes['width'] ) ? $attributes['width'] : false;
|
||||
$placeholder_h = isset( $attributes['height'] ) ? $attributes['height'] : false;
|
||||
|
||||
// Trying to get image size from metadata.
|
||||
if ( ! $placeholder_w || ! $placeholder_h ) {
|
||||
$image_id = self::attributes_to_image_id( $attributes );
|
||||
$metadata = get_post_meta( $image_id, '_wp_attachment_metadata', true );
|
||||
|
||||
if ( isset( $metadata['width'] ) && isset( $metadata['height'] ) ) {
|
||||
$placeholder_w = $metadata['width'];
|
||||
$placeholder_h = $metadata['height'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( $placeholder_w && $placeholder_h ) {
|
||||
$placeholder = self::get_image_placeholder( $placeholder_w, $placeholder_h );
|
||||
}
|
||||
|
||||
$attributes['data-src'] = $attributes['src'];
|
||||
|
||||
if ( ! empty( $attributes['srcset'] ) ) {
|
||||
$attributes['data-srcset'] = $attributes['srcset'];
|
||||
|
||||
if ( $placeholder ) {
|
||||
$attributes['srcset'] = $placeholder;
|
||||
} else {
|
||||
unset( $attributes['srcset'] );
|
||||
}
|
||||
|
||||
// In case if the image doesn't have `srcset`, we need to add placeholder to `src`.
|
||||
} elseif ( $placeholder ) {
|
||||
$attributes['src'] = $placeholder;
|
||||
}
|
||||
|
||||
if ( isset( $attributes['sizes'] ) ) {
|
||||
unset( $attributes['sizes'] );
|
||||
}
|
||||
|
||||
$attributes['data-sizes'] = 'auto';
|
||||
|
||||
// Prevent Native lazy loading.
|
||||
$attributes['loading'] = 'eager';
|
||||
|
||||
// Add custom classname.
|
||||
$attributes['class'] = empty( $attributes['class'] ) ? '' : ( $attributes['class'] . ' ' );
|
||||
$attributes['class'] .= 'vp-lazyload';
|
||||
|
||||
/**
|
||||
* Allow plugins and themes to override the attributes on the image before the content is updated.
|
||||
*
|
||||
* One potential use of this filter is for themes that set `height:auto` on the `img` tag.
|
||||
* With this filter, the theme could get the width and height attributes from the
|
||||
* $attributes array and then add a style tag that sets those values as well, which could
|
||||
* minimize reflow as images load.
|
||||
*/
|
||||
return apply_filters( 'vpf_lazyload_images_new_attributes', $attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attachment image wrapper.
|
||||
*
|
||||
* @param string|int $attachment_id attachment image id.
|
||||
* @param string|array $size image size.
|
||||
* @param bool $icon icon.
|
||||
* @param string|array $attr image attributes.
|
||||
* @param bool $lazyload DEPRECATED use lazyload tags.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_attachment_image( $attachment_id, $size = 'thumbnail', $icon = false, $attr = '', $lazyload = true ) {
|
||||
$mime_type = get_post_mime_type( $attachment_id );
|
||||
|
||||
// Prevent usage of resized GIFs, since GIFs animated only in full size.
|
||||
if ( $mime_type && 'image/gif' === $mime_type ) {
|
||||
$size = 'full';
|
||||
}
|
||||
|
||||
self::$image_processing = true;
|
||||
|
||||
$image = apply_filters( 'vpf_wp_get_attachment_image', false, $attachment_id, $size, $attr, $lazyload );
|
||||
|
||||
if ( ! $image && false === strripos( $attachment_id, 'vpf_pro_social' ) ) {
|
||||
if ( ! is_array( $attr ) ) {
|
||||
$attr = array();
|
||||
}
|
||||
if ( ! isset( $attr['class'] ) ) {
|
||||
$attr['class'] = '';
|
||||
}
|
||||
|
||||
// Add class `wp-image-ID` to allow parsers to get current image ID and make manipulations.
|
||||
// For example, this class is used in our lazyloading script to determine the image ID.
|
||||
$attr['class'] .= ( $attr['class'] ? ' ' : '' ) . 'wp-image-' . $attachment_id;
|
||||
|
||||
$image = wp_get_attachment_image( $attachment_id, $size, $icon, $attr );
|
||||
}
|
||||
|
||||
// Maybe prepare lazy load output.
|
||||
if ( self::$allow_vp_lazyload ) {
|
||||
$image = self::add_image_placeholders( $image );
|
||||
}
|
||||
|
||||
self::$image_processing = false;
|
||||
|
||||
return $image;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generation placeholder.
|
||||
*
|
||||
* @param int $width Width of image.
|
||||
* @param int $height Height of image.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_image_placeholder( $width = 1, $height = 1 ) {
|
||||
if ( ! (int) $width || ! (int) $height ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We need to use base64 to prevent rare cases when users use plugins
|
||||
// that replaces http to https in xmlns attribute.
|
||||
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
||||
$placeholder = base64_encode( '<svg width="' . $width . '" height="' . $height . '" viewBox="0 0 ' . $width . ' ' . $height . '" fill="none" xmlns="http://www.w3.org/2000/svg"></svg>' );
|
||||
|
||||
$escape_search = array( '<', '>', '#', '"' );
|
||||
$escape_replace = array( '%3c', '%3e', '%23', '\'' );
|
||||
|
||||
return apply_filters(
|
||||
'vpf_lazyload_image_placeholder',
|
||||
'data:image/svg+xml;base64,' . str_replace( $escape_search, $escape_replace, $placeholder )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flatter KSES hair data.
|
||||
*
|
||||
* @param array $attributes Attributes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function flatten_kses_hair_data( $attributes ) {
|
||||
$flattened_attributes = array();
|
||||
|
||||
foreach ( $attributes as $name => $attribute ) {
|
||||
$flattened_attributes[ $name ] = $attribute['value'];
|
||||
}
|
||||
|
||||
return $flattened_attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build attributes string.
|
||||
*
|
||||
* @param array $attributes Attributes.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build_attributes_string( $attributes ) {
|
||||
$string = array();
|
||||
|
||||
foreach ( $attributes as $name => $value ) {
|
||||
if ( '' === $value ) {
|
||||
$string[] = sprintf( '%s', $name );
|
||||
} else {
|
||||
$string[] = sprintf( '%s="%s"', $name, esc_attr( $value ) );
|
||||
}
|
||||
}
|
||||
|
||||
return implode( ' ', $string );
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to convert an attachment IMG attr into a post object.
|
||||
*
|
||||
* @param array $attributes image attributes.
|
||||
*
|
||||
* @return int|bool
|
||||
*/
|
||||
private static function attributes_to_image_id( $attributes ) {
|
||||
$img_id = false;
|
||||
|
||||
// Get ID from class.
|
||||
if ( isset( $attributes['class'] ) && preg_match( '/wp-image-(\d*)/i', $attributes['class'], $match ) ) {
|
||||
$img_id = $match[1];
|
||||
}
|
||||
|
||||
if ( ! $img_id && isset( $attributes['src'] ) ) {
|
||||
// Remove the thumbnail size.
|
||||
$src = preg_replace( '~-[0-9]+x[0-9]+(?=\..{2,6})~', '', $attributes['src'] );
|
||||
$img_id = attachment_url_to_postid( $src );
|
||||
|
||||
// Sometimes, when the uploaded image larger than max-size, this image scaled and filename changed to `NAME-scaled.EXT`.
|
||||
if ( ! $img_id ) {
|
||||
$src = preg_replace( '~-[0-9]+x[0-9]+(?=\..{2,6})~', '-scaled', $attributes['src'] );
|
||||
$img_id = attachment_url_to_postid( $src );
|
||||
}
|
||||
}
|
||||
|
||||
return $img_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds JavaScript to check if the current browser supports JavaScript as well as some styles to hide lazy
|
||||
* images when the browser does not support JavaScript.
|
||||
*/
|
||||
public static function add_nojs_fallback() {
|
||||
?>
|
||||
<style type="text/css">
|
||||
/* If html does not have either class, do not show lazy loaded images. */
|
||||
html:not(.vp-lazyload-enabled):not(.js) .vp-lazyload {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
document.documentElement.classList.add(
|
||||
'vp-lazyload-enabled'
|
||||
);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
Visual_Portfolio_Images::construct();
|
354
wp-content/plugins/visual-portfolio/classes/class-migration.php
Normal file
354
wp-content/plugins/visual-portfolio/classes/class-migration.php
Normal file
@ -0,0 +1,354 @@
|
||||
<?php
|
||||
/**
|
||||
* Migrations
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Migrations
|
||||
*/
|
||||
class Visual_Portfolio_Migrations {
|
||||
/**
|
||||
* The version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = VISUAL_PORTFOLIO_VERSION;
|
||||
|
||||
/**
|
||||
* Initial version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $initial_version = '1.16.2';
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Migrations constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( is_admin() ) {
|
||||
add_action( 'admin_init', array( $this, 'init' ), 3 );
|
||||
} else {
|
||||
add_action( 'wp', array( $this, 'init' ), 3 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
public function init() {
|
||||
// Migration code added after `$this->initial_version` plugin version.
|
||||
$saved_version = get_option( 'vpf_db_version', $this->initial_version );
|
||||
$current_version = $this->version;
|
||||
|
||||
foreach ( $this->get_migrations() as $migration ) {
|
||||
if ( version_compare( $saved_version, $migration['version'], '<' ) ) {
|
||||
call_user_func( $migration['cb'] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( version_compare( $saved_version, $current_version, '<' ) ) {
|
||||
update_option( 'vpf_db_version', $current_version );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all available migrations.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_migrations() {
|
||||
return array(
|
||||
array(
|
||||
'version' => '3.0.0',
|
||||
'cb' => array( $this, 'v_3_0_0' ),
|
||||
),
|
||||
array(
|
||||
'version' => '2.15.0',
|
||||
'cb' => array( $this, 'v_2_15_0' ),
|
||||
),
|
||||
array(
|
||||
'version' => '2.10.0',
|
||||
'cb' => array( $this, 'v_2_10_0' ),
|
||||
),
|
||||
array(
|
||||
'version' => '2.0.0',
|
||||
'cb' => array( $this, 'v_2_0_0' ),
|
||||
),
|
||||
array(
|
||||
'version' => '1.11.0',
|
||||
'cb' => array( $this, 'v_1_11_0' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add new attributes and values from old attributes.
|
||||
*/
|
||||
public function v_3_0_0() {
|
||||
// Get all available Layouts.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408.
|
||||
$layouts_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
)
|
||||
);
|
||||
|
||||
$attributes_to_change = array(
|
||||
// Align.
|
||||
'items_style_default__align' => 'items_style_default__caption_text_align',
|
||||
'items_style_fade__align' => 'items_style_fade__overlay_text_align',
|
||||
'items_style_fly__align' => 'items_style_fly__overlay_text_align',
|
||||
'items_style_emerge__align' => 'items_style_emerge__caption_text_align',
|
||||
'items_style_caption_move__align' => 'items_style_caption_move__caption_text_align',
|
||||
|
||||
// Color.
|
||||
'items_style_default__bg_color' => 'items_style_default__overlay_bg_color',
|
||||
'items_style_default__text_color' => 'items_style_default__overlay_text_color',
|
||||
'items_style_default__meta_text_color' => 'items_style_default__caption_text_color',
|
||||
'items_style_default__meta_links_color' => 'items_style_default__caption_links_color',
|
||||
'items_style_default__meta_links_hover_color' => 'items_style_default__caption_links_hover_color',
|
||||
'items_style_fade__bg_color' => 'items_style_fade__overlay_bg_color',
|
||||
'items_style_fade__text_color' => 'items_style_fade__overlay_text_color',
|
||||
'items_style_fly__bg_color' => 'items_style_fly__overlay_bg_color',
|
||||
'items_style_fly__text_color' => 'items_style_fly__overlay_text_color',
|
||||
'items_style_emerge__bg_color' => 'items_style_emerge__caption_bg_color',
|
||||
'items_style_emerge__text_color' => 'items_style_emerge__caption_text_color',
|
||||
'items_style_emerge__links_color' => 'items_style_emerge__caption_links_color',
|
||||
'items_style_emerge__links_hover_color' => 'items_style_emerge__caption_links_hover_color',
|
||||
'items_style_emerge__img_overlay_bg_color' => 'items_style_emerge__overlay_bg_color',
|
||||
'items_style_caption-move__bg_color' => 'items_style_caption-move__caption_bg_color',
|
||||
'items_style_caption-move__text_color' => 'items_style_caption-move__caption_text_color',
|
||||
'items_style_caption-move__img_overlay_bg_color' => 'items_style_caption-move__overlay_bg_color',
|
||||
'items_style_caption-move__overlay_text_color' => 'items_style_caption-move__overlay_text_color',
|
||||
|
||||
// Move Under Image.
|
||||
'items_style_fade__move_overlay_under_image' => 'items_style_fade__overlay_under_image',
|
||||
'items_style_fly__move_overlay_under_image' => 'items_style_fly__overlay_under_image',
|
||||
'items_style_emerge__move_overlay_under_image' => 'items_style_emerge__caption_under_image',
|
||||
'items_style_caption-move__move_overlay_under_image' => 'items_style_caption-move__caption_under_image',
|
||||
);
|
||||
|
||||
$attributes_border_radius = array(
|
||||
'items_style_default__images_rounded_corners',
|
||||
'items_style_fade__images_rounded_corners',
|
||||
'items_style_fly__images_rounded_corners',
|
||||
'items_style_emerge__images_rounded_corners',
|
||||
'items_style_caption_move__images_rounded_corners',
|
||||
);
|
||||
|
||||
if ( $layouts_query ) {
|
||||
foreach ( $layouts_query as $post ) {
|
||||
// Change Portfolio content source to Post with custom post type Portfolio.
|
||||
if ( 'portfolio' === get_post_meta( $post->ID, 'vp_content_source', true ) ) {
|
||||
update_post_meta( $post->ID, 'vp_content_source', 'post-based' );
|
||||
update_post_meta( $post->ID, 'vp_posts_source', 'portfolio' );
|
||||
}
|
||||
|
||||
foreach ( $attributes_to_change as $old_attr => $new_attr ) {
|
||||
$old_val = get_post_meta( $post->ID, 'vp_' . $old_attr, true );
|
||||
$new_val = get_post_meta( $post->ID, 'vp_' . $new_attr, true );
|
||||
|
||||
if ( $old_val && ! $new_val ) {
|
||||
update_post_meta( $post->ID, 'vp_' . $new_attr, $old_val );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $attributes_border_radius as $attr_name ) {
|
||||
$attr_val = get_post_meta( $post->ID, 'vp_' . $attr_name, true );
|
||||
|
||||
if ( is_numeric( $attr_val ) ) {
|
||||
update_post_meta( $post->ID, 'vp_' . $attr_name, $attr_val . 'px' );
|
||||
}
|
||||
}
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the old portfolio slug option and create a page with archive page based on it.
|
||||
*/
|
||||
public function v_2_15_0() {
|
||||
// Backward compatible with old slug option.
|
||||
$settings_section = 'vp_general';
|
||||
$option_name = 'portfolio_slug';
|
||||
$options = get_option( $settings_section );
|
||||
|
||||
if ( isset( $options[ $option_name ] ) ) {
|
||||
$custom_slug = $options[ $option_name ];
|
||||
$archive_id = get_option( '_vp_add_archive_page' );
|
||||
|
||||
if ( $archive_id ) {
|
||||
// Update archive slug on page.
|
||||
wp_update_post(
|
||||
array(
|
||||
'ID' => $archive_id,
|
||||
'post_name' => wp_slash( $custom_slug ),
|
||||
)
|
||||
);
|
||||
|
||||
// Rewrite flush rules.
|
||||
visual_portfolio()->defer_flush_rewrite_rules();
|
||||
} else {
|
||||
// Create archive page.
|
||||
Visual_Portfolio_Archive_Mapping::create_archive_page( $custom_slug );
|
||||
}
|
||||
|
||||
// Delete old option.
|
||||
unset( $options[ $option_name ] );
|
||||
update_option( $settings_section, $options );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move popup title and description settings to single Layouts.
|
||||
*/
|
||||
public function v_2_10_0() {
|
||||
$options = get_option( 'vp_images' );
|
||||
|
||||
if ( ! isset( $options['lazy_loading'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'off' === $options['lazy_loading'] || ! $options['lazy_loading'] ) {
|
||||
$options['lazy_loading'] = '';
|
||||
} else {
|
||||
$options['lazy_loading'] = 'vp';
|
||||
}
|
||||
|
||||
update_option( 'vp_images', $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Change Portfolio content source to Post with custom post type Portfolio
|
||||
* 2. Change filters, sort and pagination to layout-elements.
|
||||
*/
|
||||
public function v_2_0_0() {
|
||||
// Get all available Layouts.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408.
|
||||
$layouts_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
)
|
||||
);
|
||||
|
||||
if ( $layouts_query ) {
|
||||
foreach ( $layouts_query as $post ) {
|
||||
// Change Portfolio content source to Post with custom post type Portfolio.
|
||||
if ( 'portfolio' === get_post_meta( $post->ID, 'vp_content_source', true ) ) {
|
||||
update_post_meta( $post->ID, 'vp_content_source', 'post-based' );
|
||||
update_post_meta( $post->ID, 'vp_posts_source', 'portfolio' );
|
||||
}
|
||||
|
||||
// Change filters, sort and pagination to layout-elements.
|
||||
if ( ! get_post_meta( $post->ID, 'vp_layout_elements', true ) ) {
|
||||
$top = array();
|
||||
$bottom = array();
|
||||
$filter = get_post_meta( $post->ID, 'vp_filter', true );
|
||||
$sort = get_post_meta( $post->ID, 'vp_sort', true );
|
||||
$pagination = get_post_meta( $post->ID, 'vp_pagination_style', true );
|
||||
|
||||
// Filter.
|
||||
if ( $filter && 'false' !== $filter && false !== $filter ) {
|
||||
$top[] = 'filter';
|
||||
} else {
|
||||
update_post_meta( $post->ID, 'vp_filter', 'minimal' );
|
||||
}
|
||||
|
||||
// Sort.
|
||||
if ( $sort && 'false' !== $sort && false !== $sort ) {
|
||||
$top[] = 'sort';
|
||||
} else {
|
||||
update_post_meta( $post->ID, 'vp_sort', 'dropdown' );
|
||||
}
|
||||
|
||||
// Pagination.
|
||||
if ( $pagination && 'false' !== $pagination && false !== $pagination ) {
|
||||
$bottom[] = 'pagination';
|
||||
} else {
|
||||
update_post_meta( $post->ID, 'vp_pagination_style', 'minimal' );
|
||||
}
|
||||
|
||||
// Layout Elements.
|
||||
if ( ! empty( $top ) || ! empty( $bottom ) ) {
|
||||
update_post_meta(
|
||||
$post->ID,
|
||||
'vp_layout_elements',
|
||||
array(
|
||||
'top' => array(
|
||||
'elements' => $top,
|
||||
'align' => 'center',
|
||||
),
|
||||
'items' => array(
|
||||
'elements' => array( 'items' ),
|
||||
),
|
||||
'bottom' => array(
|
||||
'elements' => $bottom,
|
||||
'align' => 'center',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Move popup title and description settings to single Layouts.
|
||||
*/
|
||||
public function v_1_11_0() {
|
||||
$options = get_option( 'vp_popup_gallery' );
|
||||
|
||||
if ( ! isset( $options['show_caption'] ) && ! isset( $options['caption_title'] ) && ! isset( $options['caption_description'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$new_show_caption = isset( $options['show_caption'] ) ? 'on' === $options['show_caption'] : true;
|
||||
$new_title_source = $new_show_caption && isset( $options['caption_title'] ) ? $options['caption_title'] : 'none';
|
||||
$new_description_source = $new_show_caption && isset( $options['caption_description'] ) ? $options['caption_description'] : 'none';
|
||||
|
||||
// Get all available Layouts.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408.
|
||||
$layouts_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
)
|
||||
);
|
||||
if ( $layouts_query ) {
|
||||
foreach ( $layouts_query as $post ) {
|
||||
update_post_meta( $post->ID, 'vp_items_click_action_popup_title_source', $new_title_source );
|
||||
update_post_meta( $post->ID, 'vp_items_click_action_popup_description_source', $new_description_source );
|
||||
}
|
||||
wp_reset_postdata();
|
||||
}
|
||||
|
||||
// remove saved old options.
|
||||
if ( isset( $options['show_caption'] ) ) {
|
||||
unset( $options['show_caption'] );
|
||||
}
|
||||
if ( isset( $options['caption_title'] ) ) {
|
||||
unset( $options['caption_title'] );
|
||||
}
|
||||
if ( isset( $options['caption_description'] ) ) {
|
||||
unset( $options['caption_description'] );
|
||||
}
|
||||
|
||||
update_option( 'vp_popup_gallery', $options );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Migrations();
|
@ -0,0 +1,180 @@
|
||||
<?php
|
||||
/**
|
||||
* Parse blocks from content and widgets
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Parse_Blocks
|
||||
*/
|
||||
class Visual_Portfolio_Parse_Blocks {
|
||||
/**
|
||||
* Array of content, that already parsed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $parsed_content = array();
|
||||
|
||||
/**
|
||||
* Array of reusable block IDs, that already parsed.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $parsed_reusable_blocks = array();
|
||||
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
public static function init() {
|
||||
add_action(
|
||||
'wp',
|
||||
function() {
|
||||
// Simple use `render_block` in FSE themes to enqueue assets.
|
||||
if ( current_theme_supports( 'block-templates' ) ) {
|
||||
// Parse all blocks.
|
||||
add_action( 'render_block', 'Visual_Portfolio_Parse_Blocks::render_block', 11, 2 );
|
||||
|
||||
// Parse blocks manually from content and custom locations in Classic themes.
|
||||
} else {
|
||||
// parse blocks from post content.
|
||||
Visual_Portfolio_Parse_Blocks::maybe_parse_blocks_from_content();
|
||||
|
||||
// parse blocks from custom locations, that uses 'the_content' filter.
|
||||
add_filter( 'the_content', 'Visual_Portfolio_Parse_Blocks::maybe_parse_blocks_from_custom_location', 8 );
|
||||
add_filter( 'widget_block_content', 'Visual_Portfolio_Parse_Blocks::maybe_parse_blocks_from_custom_location', 8 );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard callback to parse blocks (mostly solves problem with FSE themes and blocks inside templates).
|
||||
*
|
||||
* @param string $block_content - block content.
|
||||
* @param array $block - block data.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function render_block( $block_content, $block ) {
|
||||
// We don't need to parse inner blocks manually, because `render_block` filter will make it for us.
|
||||
$block['innerBlocks'] = false;
|
||||
|
||||
self::parse_blocks( array( $block ), 'general' );
|
||||
|
||||
return $block_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse blocks from custom locations.
|
||||
*
|
||||
* @param string $content - custom content.
|
||||
*/
|
||||
public static function maybe_parse_blocks_from_custom_location( $content ) {
|
||||
if ( is_admin() ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
if ( isset( $content ) ) {
|
||||
self::maybe_parse_blocks( $content, 'content' );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe parse blocks.
|
||||
*
|
||||
* @param string $content - content.
|
||||
* @param string $location - blocks location [content,widget].
|
||||
*/
|
||||
public static function maybe_parse_blocks( $content, $location = 'content' ) {
|
||||
if (
|
||||
isset( $content ) &&
|
||||
function_exists( 'has_blocks' ) &&
|
||||
function_exists( 'parse_blocks' ) &&
|
||||
$content &&
|
||||
has_blocks( $content )
|
||||
) {
|
||||
$is_parsed = false;
|
||||
|
||||
// check if this content is already parsed.
|
||||
foreach ( self::$parsed_content as $parsed ) {
|
||||
$is_parsed = $is_parsed || $parsed === $content;
|
||||
}
|
||||
|
||||
if ( ! $is_parsed ) {
|
||||
$blocks = parse_blocks( $content );
|
||||
|
||||
self::parse_blocks( $blocks, $location );
|
||||
|
||||
self::$parsed_content[] = $content;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse blocks from content.
|
||||
*/
|
||||
public static function maybe_parse_blocks_from_content() {
|
||||
global $wp_query;
|
||||
|
||||
if ( is_admin() || ! isset( $wp_query->posts ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// parse all posts content.
|
||||
foreach ( $wp_query->posts as $post ) {
|
||||
if (
|
||||
isset( $post->post_content ) &&
|
||||
function_exists( 'has_blocks' ) &&
|
||||
function_exists( 'parse_blocks' ) &&
|
||||
has_blocks( $post )
|
||||
) {
|
||||
$blocks = parse_blocks( $post->post_content );
|
||||
self::parse_blocks( $blocks, 'content' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse blocks including reusable and InnerBlocks and call action `vpf_parse_blocks`.
|
||||
*
|
||||
* @param array $blocks - blocks array.
|
||||
* @param string $location - blocks location [content,widget].
|
||||
* @param boolean $is_reusable - is from reusable block.
|
||||
* @param boolean $is_inner_blocks - is from inner blocks.
|
||||
*/
|
||||
public static function parse_blocks( $blocks, $location = 'content', $is_reusable = false, $is_inner_blocks = false ) {
|
||||
if ( ! is_array( $blocks ) || empty( $blocks ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_action( 'vpf_parse_blocks', $blocks, $location, $is_reusable, $is_inner_blocks );
|
||||
|
||||
foreach ( $blocks as $block ) {
|
||||
// Reusable Blocks.
|
||||
if ( isset( $block['blockName'] ) && 'core/block' === $block['blockName'] && isset( $block['attrs']['ref'] ) ) {
|
||||
// Check if this reusable block already parsed.
|
||||
// Fixes possible error with nested reusable blocks.
|
||||
if ( ! in_array( $block['attrs']['ref'], self::$parsed_reusable_blocks, true ) ) {
|
||||
self::$parsed_reusable_blocks[] = $block['attrs']['ref'];
|
||||
|
||||
$reusable_block = get_post( $block['attrs']['ref'] );
|
||||
|
||||
if ( has_blocks( $reusable_block ) && isset( $reusable_block->post_content ) ) {
|
||||
$post_blocks = parse_blocks( $reusable_block->post_content );
|
||||
self::parse_blocks( $post_blocks, $location, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Inner blocks.
|
||||
if ( isset( $block['innerBlocks'] ) ) {
|
||||
self::parse_blocks( $block['innerBlocks'], $location, $is_reusable, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Visual_Portfolio_Parse_Blocks::init();
|
324
wp-content/plugins/visual-portfolio/classes/class-preview.php
Normal file
324
wp-content/plugins/visual-portfolio/classes/class-preview.php
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
/**
|
||||
* Register fake page for portfolio preview.
|
||||
*
|
||||
* @package visual-portfolio/preview
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Preview
|
||||
*/
|
||||
class Visual_Portfolio_Preview {
|
||||
|
||||
/**
|
||||
* Preview enabled.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $preview_enabled = false;
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Preview constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks.
|
||||
*/
|
||||
public function init_hooks() {
|
||||
add_action( 'init', array( $this, 'is_preview_check' ) );
|
||||
add_filter( 'pre_handle_404', array( $this, 'pre_handle_404' ) );
|
||||
add_filter( 'vpf_get_options', array( $this, 'filter_preview_option' ) );
|
||||
add_action( 'template_redirect', array( $this, 'template_redirect' ) );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ), 11 );
|
||||
|
||||
// Localize script in editor, FSE, and Elementor.
|
||||
add_action( 'enqueue_block_assets', array( $this, 'localize_scripts' ) );
|
||||
add_action( 'wp_print_scripts', array( $this, 'localize_elementor_scripts' ), 9 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare preview URL to use from our preview iframe.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_preview_url() {
|
||||
add_filter( 'pre_option_permalink_structure', '__return_empty_string' );
|
||||
|
||||
$preview_url = set_url_scheme(
|
||||
add_query_arg(
|
||||
array(
|
||||
'vp_preview' => 'vp_preview',
|
||||
'vp_preview_time' => time(),
|
||||
),
|
||||
// We used `get_site_url()` before, but it does not work on some hosts,
|
||||
// that have custom URL structure in admin area.
|
||||
//
|
||||
// For example:
|
||||
// * Admin URL: https://mysite.com/wp/
|
||||
// * Front URL: https://mysite.com/
|
||||
//
|
||||
// Use `trailingslashit` to fix some rare servers problems
|
||||
// when preview is not working if no trailing slash in URL.
|
||||
//
|
||||
// For example:
|
||||
// * Error: https://mysite.com/wp
|
||||
// * Success: https://mysite.com/wp/
|
||||
// .
|
||||
trailingslashit( home_url( '/' ) )
|
||||
)
|
||||
);
|
||||
|
||||
remove_filter( 'pre_option_permalink_structure', '__return_empty_string' );
|
||||
|
||||
return $preview_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize scripts with preview URL.
|
||||
*/
|
||||
public function localize_scripts() {
|
||||
if ( ! is_admin() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$preview_url = $this->get_preview_url();
|
||||
|
||||
// Localize scripts.
|
||||
wp_localize_script(
|
||||
'visual-portfolio-gutenberg',
|
||||
'VPAdminGutenbergVariables',
|
||||
array(
|
||||
'preview_url' => $preview_url,
|
||||
'nonce' => wp_create_nonce( 'vp-ajax-nonce' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Localize scripts with preview URL for Elementor.
|
||||
*/
|
||||
public function localize_elementor_scripts() {
|
||||
if ( ! wp_script_is( 'visual-portfolio-elementor', 'registered' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$preview_url = $this->get_preview_url();
|
||||
|
||||
// Localize scripts.
|
||||
wp_localize_script(
|
||||
'visual-portfolio-elementor',
|
||||
'VPAdminElementorVariables',
|
||||
array(
|
||||
'preview_url' => $preview_url,
|
||||
'nonce' => wp_create_nonce( 'vp-ajax-nonce' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the page is preview.
|
||||
*/
|
||||
public function is_preview_check() {
|
||||
$frame = false;
|
||||
if ( isset( $_GET['vp_preview'] ) && isset( $_REQUEST['vp_preview_nonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['vp_preview_nonce'] ), 'vp-ajax-nonce' ) ) {
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
$frame = isset( $_POST['vp_preview_frame'] ) ? Visual_Portfolio_Security::sanitize_boolean( $_POST['vp_preview_frame'] ) : false;
|
||||
$id = isset( $_POST['vp_preview_frame_id'] ) ? sanitize_text_field( wp_unslash( $_POST['vp_preview_frame_id'] ) ) : false;
|
||||
|
||||
// Elementor preview.
|
||||
if ( ! $frame && ! $id && isset( $_REQUEST['vp_preview_type'] ) && 'elementor' === $_REQUEST['vp_preview_type'] ) {
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
||||
$frame = isset( $_REQUEST['vp_preview_frame'] ) ? Visual_Portfolio_Security::sanitize_boolean( $_REQUEST['vp_preview_frame'] ) : false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->preview_enabled = $frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent 404 headers if it is vp_preview page.
|
||||
*
|
||||
* @param bool $val - handle 404 headers.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function pre_handle_404( $val ) {
|
||||
return $this->preview_enabled ? true : $val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable infinite loading in preview.
|
||||
*
|
||||
* @param array $options - options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filter_preview_option( $options ) {
|
||||
if ( $this->preview_enabled && isset( $options['pagination'] ) && 'infinite' === $options['pagination'] ) {
|
||||
$options['pagination'] = 'load-more';
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display preview frame
|
||||
* Available by requesting:
|
||||
* SITE/?vp_preview=vp_preview with POST data: `vp_preview_frame=true&vp_preview_frame_id=10`
|
||||
*/
|
||||
public function template_redirect() {
|
||||
if ( is_admin() || ! $this->preview_enabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->print_template();
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue scripts action.
|
||||
*/
|
||||
public function wp_enqueue_scripts() {
|
||||
// Dequeue WooCommerce Geolocation script, since it reloads our preview iframe.
|
||||
// Thanks to https://wordpress.org/support/topic/in-editor-the-normal-preview-replaced-with-a-smaller-website-load/ .
|
||||
if ( $this->preview_enabled && wp_script_is( 'wc-geolocation', 'enqueued' ) ) {
|
||||
wp_dequeue_script( 'wc-geolocation' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do not cache.
|
||||
*
|
||||
* Tell WordPress cache plugins not to cache this request.
|
||||
*/
|
||||
public function do_not_cache() {
|
||||
// Disable cache plugins.
|
||||
if ( ! defined( 'DONOTCACHEPAGE' ) ) {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
|
||||
define( 'DONOTCACHEPAGE', true );
|
||||
}
|
||||
|
||||
if ( ! defined( 'DONOTCACHEDB' ) ) {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
|
||||
define( 'DONOTCACHEDB', true );
|
||||
}
|
||||
|
||||
if ( ! defined( 'DONOTMINIFY' ) ) {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
|
||||
define( 'DONOTMINIFY', true );
|
||||
}
|
||||
|
||||
if ( ! defined( 'DONOTCDN' ) ) {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
|
||||
define( 'DONOTCDN', true );
|
||||
}
|
||||
|
||||
if ( ! defined( 'DONOTCACHEOBJECT' ) ) {
|
||||
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
|
||||
define( 'DONOTCACHEOBJECT', true );
|
||||
}
|
||||
|
||||
// Set the headers to prevent caching for the different browsers.
|
||||
nocache_headers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Template of preview page.
|
||||
*/
|
||||
public function print_template() {
|
||||
do_action( 'vpf_preview_template' );
|
||||
|
||||
// Tell to WP Cache plugins do not cache this request.
|
||||
$this->do_not_cache();
|
||||
|
||||
// Don't redirect to permalink.
|
||||
remove_action( 'template_redirect', 'redirect_canonical' );
|
||||
|
||||
// Compatibility with Yoast SEO plugin when 'Removes unneeded query variables from the URL' enabled.
|
||||
if ( class_exists( 'WPSEO_Frontend' ) ) {
|
||||
remove_action( 'template_redirect', array( \WPSEO_Frontend::get_instance(), 'clean_permalink' ), 1 );
|
||||
}
|
||||
|
||||
// Disable the WP admin bar.
|
||||
add_filter( 'show_admin_bar', '__return_false' );
|
||||
|
||||
// Avoid Cloudflare's Rocket Loader lazy load the editor iframe.
|
||||
// TODO: we also need an additional filter, which is not available in the WP yet:
|
||||
// https://github.com/WordPress/wordpress-develop/pull/1759 .
|
||||
add_filter( 'script_loader_tag', array( $this, 'rocket_loader_filter' ) );
|
||||
|
||||
// Enqueue assets.
|
||||
Visual_Portfolio_Assets::enqueue_script( 'iframe-resizer-content', 'assets/vendor/iframe-resizer/js/iframeResizer.contentWindow.min', array(), '4.3.7' );
|
||||
Visual_Portfolio_Assets::enqueue_script( 'visual-portfolio-preview', 'build/assets/js/preview', array( 'iframe-resizer-content' ) );
|
||||
// Post data for script.
|
||||
wp_localize_script(
|
||||
'visual-portfolio-preview',
|
||||
'vp_preview_post_data',
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
isset( $_POST ) && ! empty( $_POST ) ? Visual_Portfolio_Security::sanitize_attributes( $_POST ) : array()
|
||||
);
|
||||
|
||||
$class_name = 'vp-preview-wrapper';
|
||||
|
||||
// preview type.
|
||||
$type = isset( $_POST['vp_preview_type'] ) ? sanitize_text_field( wp_unslash( $_POST['vp_preview_type'] ) ) : false;
|
||||
|
||||
if ( $type ) {
|
||||
$class_name .= ' vp-preview-type-' . $type;
|
||||
}
|
||||
|
||||
// Prepare portfolio post options.
|
||||
$options = array();
|
||||
if ( isset( $_POST ) && ! empty( $_POST ) ) {
|
||||
foreach ( $_POST as $name => $val ) {
|
||||
if ( strpos( $name, 'vp_' ) === 0 ) {
|
||||
$options[ preg_replace( '/^vp_/', '', $name ) ] = $val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Elementor widget preview.
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['vp_preview_type'] ) && 'elementor' === $_REQUEST['vp_preview_type'] && isset( $_REQUEST['vp_preview_frame_id'] ) ) {
|
||||
$options['id'] = sanitize_text_field( wp_unslash( $_REQUEST['vp_preview_frame_id'] ) );
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
$options = Visual_Portfolio_Security::sanitize_attributes( $options );
|
||||
|
||||
// Register assets.
|
||||
Visual_Portfolio_Assets::enqueue( $options );
|
||||
|
||||
// Custom styles.
|
||||
visual_portfolio()->include_template_style( 'visual-portfolio-preview', 'preview/style', array(), VISUAL_PORTFOLIO_VERSION );
|
||||
|
||||
// Output template.
|
||||
visual_portfolio()->include_template(
|
||||
'preview/preview',
|
||||
array(
|
||||
'options' => $options,
|
||||
'class_name' => $class_name,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable rocket loader in preview.
|
||||
*
|
||||
* @param String $tag - tag string.
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
public function rocket_loader_filter( $tag ) {
|
||||
return str_replace( '<script', '<script data-cfasync="false"', $tag );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Preview();
|
264
wp-content/plugins/visual-portfolio/classes/class-rest.php
Normal file
264
wp-content/plugins/visual-portfolio/classes/class-rest.php
Normal file
@ -0,0 +1,264 @@
|
||||
<?php
|
||||
/**
|
||||
* Rest API functions
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Rest
|
||||
*/
|
||||
class Visual_Portfolio_Rest extends WP_REST_Controller {
|
||||
/**
|
||||
* Namespace.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'visual-portfolio/v';
|
||||
|
||||
/**
|
||||
* Version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $version = '1';
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Rest constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Register rest routes.
|
||||
*/
|
||||
public function register_routes() {
|
||||
$namespace = $this->namespace . $this->version;
|
||||
|
||||
// Get layouts list.
|
||||
register_rest_route(
|
||||
$namespace,
|
||||
'/get_layouts/',
|
||||
array(
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => array( $this, 'get_layouts' ),
|
||||
'permission_callback' => array( $this, 'get_layouts_permission' ),
|
||||
)
|
||||
);
|
||||
|
||||
// Update layout data.
|
||||
register_rest_route(
|
||||
$namespace,
|
||||
'/update_layout/',
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'update_layout' ),
|
||||
'permission_callback' => array( $this, 'update_layout_permission' ),
|
||||
)
|
||||
);
|
||||
|
||||
// Update gallery items count notice state.
|
||||
register_rest_route(
|
||||
$namespace,
|
||||
'/update_gallery_items_count_notice_state/',
|
||||
array(
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => array( $this, 'update_gallery_items_count_notice_state' ),
|
||||
'permission_callback' => array( $this, 'update_gallery_items_count_notice_state_permission' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get layout data permission.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_layouts_permission() {
|
||||
if ( current_user_can( 'edit_posts' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ( get_post_types( array( 'show_in_rest' => true ), 'objects' ) as $post_type ) {
|
||||
if ( current_user_can( $post_type->cap->edit_posts ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->error( 'not_allowed', esc_html__( 'Sorry, you are not allowed to get list of saved layouts.', 'visual-portfolio' ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get layout data.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_layouts() {
|
||||
// get all visual-portfolio post types.
|
||||
// Don't use WP_Query on the admin side https://core.trac.wordpress.org/ticket/18408 .
|
||||
$layouts = array();
|
||||
$vp_query = get_posts(
|
||||
array(
|
||||
'post_type' => 'vp_lists',
|
||||
'posts_per_page' => -1,
|
||||
'paged' => -1,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
foreach ( $vp_query as $post ) {
|
||||
$layouts[] = array(
|
||||
'id' => $post->ID,
|
||||
'title' => $post->post_title,
|
||||
'edit_url' => admin_url( 'post.php?post=' . $post->ID ) . '&action=edit',
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $layouts ) ) {
|
||||
return $this->success( $layouts );
|
||||
} else {
|
||||
return $this->error( 'no_layouts_found', __( 'Layouts not found.', 'visual-portfolio' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update layout data permission.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
public function update_layout_permission( $request ) {
|
||||
$post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0;
|
||||
|
||||
if ( ! $post_id ) {
|
||||
return $this->error( 'post_id_required', esc_html__( 'Post ID is required for this request.', 'visual-portfolio' ), true );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) {
|
||||
return $this->error( 'not_allowed', esc_html__( 'Sorry, you are not allowed to edit saved layouts data.', 'visual-portfolio' ), true );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update layout data.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function update_layout( $request ) {
|
||||
$post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0;
|
||||
$data = isset( $request['data'] ) ? $request['data'] : false;
|
||||
|
||||
if ( $post_id && $data ) {
|
||||
$meta = array_keys( Visual_Portfolio_Get::get_options( array( 'id' => $post_id ) ) );
|
||||
|
||||
foreach ( $meta as $name ) {
|
||||
// Save with prefix.
|
||||
$prefixed_name = 'vp_' . $name;
|
||||
|
||||
if ( isset( $data[ $prefixed_name ] ) ) {
|
||||
if (
|
||||
'vp_images' === $prefixed_name ||
|
||||
'vp_layout_elements' === $prefixed_name ||
|
||||
'vp_custom_css' === $prefixed_name
|
||||
) {
|
||||
$result = $data[ $prefixed_name ];
|
||||
} elseif ( is_array( $data[ $prefixed_name ] ) ) {
|
||||
$result = array_map( 'sanitize_text_field', wp_unslash( $data[ $prefixed_name ] ) );
|
||||
} else {
|
||||
$result = sanitize_text_field( wp_unslash( $data[ $prefixed_name ] ) );
|
||||
}
|
||||
|
||||
update_post_meta( $post_id, $prefixed_name, $result );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update gallery items count notice state permission.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return true|WP_Error
|
||||
*/
|
||||
public function update_gallery_items_count_notice_state_permission( $request ) {
|
||||
$post_id = isset( $request['post_id'] ) ? intval( $request['post_id'] ) : 0;
|
||||
|
||||
if ( ! $post_id || ! current_user_can( 'manage_options' ) ) {
|
||||
return $this->error( 'user_dont_have_permission', esc_html__( 'User don\'t have permissions to change options.', 'visual-portfolio' ), true );
|
||||
}
|
||||
|
||||
if ( ! current_user_can( 'edit_post', $post_id ) ) {
|
||||
return $this->error( 'user_dont_have_permission', esc_html__( 'User don\'t have permissions to change options.', 'visual-portfolio' ), true );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update layout data.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
*
|
||||
* @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
|
||||
*/
|
||||
public function update_gallery_items_count_notice_state( $request ) {
|
||||
update_option( 'visual_portfolio_items_count_notice_state', $request->get_param( 'notice_state' ) );
|
||||
|
||||
return $this->success( true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Success rest.
|
||||
*
|
||||
* @param mixed $response response data.
|
||||
* @return mixed
|
||||
*/
|
||||
public function success( $response ) {
|
||||
return new WP_REST_Response(
|
||||
array(
|
||||
'success' => true,
|
||||
'response' => $response,
|
||||
),
|
||||
200
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Error rest.
|
||||
*
|
||||
* @param mixed $code error code.
|
||||
* @param mixed $response response data.
|
||||
* @param boolean $true_error use true error response to stop the code processing.
|
||||
* @return mixed
|
||||
*/
|
||||
public function error( $code, $response, $true_error = false ) {
|
||||
if ( $true_error ) {
|
||||
return new WP_Error( $code, $response, array( 'status' => 401 ) );
|
||||
}
|
||||
|
||||
return new WP_REST_Response(
|
||||
array(
|
||||
'error' => true,
|
||||
'success' => false,
|
||||
'error_code' => $code,
|
||||
'response' => $response,
|
||||
),
|
||||
401
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Rest();
|
499
wp-content/plugins/visual-portfolio/classes/class-security.php
Normal file
499
wp-content/plugins/visual-portfolio/classes/class-security.php
Normal file
@ -0,0 +1,499 @@
|
||||
<?php
|
||||
/**
|
||||
* Security sanitization and validation of data
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Security
|
||||
*/
|
||||
class Visual_Portfolio_Security {
|
||||
/**
|
||||
* Visual_Portfolio_Security constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_vp_popup' ), 9, 2 );
|
||||
add_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_vp_svg' ), 9, 2 );
|
||||
add_filter( 'wp_kses_allowed_html', array( $this, 'wp_kses_vp_image' ), 9, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns allowed HTML tags and attributes for Popup.
|
||||
*
|
||||
* @param string|array $allowedtags - Allow Tags for current context.
|
||||
* @param string|array $context - tags context.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function wp_kses_vp_popup( $allowedtags, $context ) {
|
||||
if ( 'vp_popup' === $context ) {
|
||||
$kses_defaults = wp_kses_allowed_html( 'post' );
|
||||
|
||||
$kses_popup = array(
|
||||
'template' => array(
|
||||
'class' => true,
|
||||
'style' => true,
|
||||
|
||||
// Most data for the popup is saved in the data attributes.
|
||||
'data-*' => true,
|
||||
),
|
||||
'div' => array(
|
||||
'class' => true,
|
||||
'style' => true,
|
||||
|
||||
// Most data for the popup is saved in the data attributes.
|
||||
'data-*' => true,
|
||||
),
|
||||
);
|
||||
|
||||
return array_merge( $allowedtags, $kses_defaults, $kses_popup );
|
||||
}
|
||||
|
||||
return $allowedtags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns allowed HTML tags and attributes for Svg.
|
||||
*
|
||||
* @param string|array $allowedtags - Allow Tags for current context.
|
||||
* @param string|array $context - tags context.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function wp_kses_vp_svg( $allowedtags, $context ) {
|
||||
if ( 'vp_svg' === $context ) {
|
||||
$kses_svg_attrs = array(
|
||||
'x' => true,
|
||||
'y' => true,
|
||||
'd' => true,
|
||||
'r' => true,
|
||||
'width' => true,
|
||||
'height' => true,
|
||||
'rx' => true,
|
||||
'cx' => true,
|
||||
'cy' => true,
|
||||
'stroke' => true,
|
||||
'stroke-width' => true,
|
||||
'fill' => true,
|
||||
'transform' => true,
|
||||
'stroke-linecap' => true,
|
||||
'stroke-linejoin' => true,
|
||||
);
|
||||
|
||||
$kses_svg = array(
|
||||
'svg' => array(
|
||||
'class' => true,
|
||||
'aria-hidden' => true,
|
||||
'aria-labelledby' => true,
|
||||
'role' => true,
|
||||
'xmlns' => true,
|
||||
'width' => true,
|
||||
'height' => true,
|
||||
'viewbox' => true,
|
||||
),
|
||||
'g' => $kses_svg_attrs,
|
||||
'path' => $kses_svg_attrs,
|
||||
'rect' => $kses_svg_attrs,
|
||||
'circle' => $kses_svg_attrs,
|
||||
'title' => array(
|
||||
'title' => true,
|
||||
),
|
||||
);
|
||||
|
||||
return $kses_svg;
|
||||
}
|
||||
|
||||
return $allowedtags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns allowed HTML tags and attributes for Svg.
|
||||
*
|
||||
* @param string|array $allowedtags - Allow Tags for current context.
|
||||
* @param string|array $context - tags context.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function wp_kses_vp_image( $allowedtags, $context ) {
|
||||
if ( 'vp_image' === $context ) {
|
||||
$kses_image = array(
|
||||
'noscript' => true,
|
||||
'img' => array(
|
||||
'alt' => true,
|
||||
'align' => true,
|
||||
'border' => true,
|
||||
'class' => true,
|
||||
'height' => true,
|
||||
'hspace' => true,
|
||||
'loading' => true,
|
||||
'longdesc' => true,
|
||||
'vspace' => true,
|
||||
'src' => true,
|
||||
'srcset' => true,
|
||||
'sizes' => true,
|
||||
'usemap' => true,
|
||||
'width' => true,
|
||||
|
||||
// Lazy loading data is saved in the data attributes.
|
||||
'data-*' => true,
|
||||
),
|
||||
'figure' => array(
|
||||
'align' => true,
|
||||
),
|
||||
'figcaption' => array(
|
||||
'align' => true,
|
||||
),
|
||||
);
|
||||
|
||||
return $kses_image;
|
||||
}
|
||||
|
||||
return $allowedtags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize hidden attribute.
|
||||
*
|
||||
* @param string|bool $attribute - Unclear Hidden Attribute.
|
||||
* @return string|bool
|
||||
*/
|
||||
public static function sanitize_hidden( $attribute ) {
|
||||
$value = false;
|
||||
|
||||
if ( is_bool( $attribute ) ) {
|
||||
$value = (bool) $attribute;
|
||||
} elseif ( is_string( $attribute ) ) {
|
||||
$value = strtolower( $attribute );
|
||||
if ( in_array( $value, array( 'false', '0' ), true ) ) {
|
||||
$value = false;
|
||||
}
|
||||
if ( in_array( $value, array( 'true', '1' ), true ) ) {
|
||||
$value = true;
|
||||
}
|
||||
|
||||
$value = is_bool( $value ) ? (bool) $value : sanitize_text_field( wp_unslash( $attribute ) );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize Boolean.
|
||||
*
|
||||
* @param string|bool $attribute - Unclear Boolean Attribute.
|
||||
* @return bool
|
||||
*/
|
||||
public static function sanitize_boolean( $attribute ) {
|
||||
$value = false;
|
||||
|
||||
if ( is_bool( $attribute ) ) {
|
||||
$value = (bool) $attribute;
|
||||
} elseif ( is_string( $attribute ) ) {
|
||||
$value = strtolower( $attribute );
|
||||
if ( in_array( $value, array( 'false', '0' ), true ) ) {
|
||||
$value = false;
|
||||
}
|
||||
if ( in_array( $value, array( 'true', '1' ), true ) ) {
|
||||
$value = true;
|
||||
}
|
||||
|
||||
$value = (bool) wp_unslash( $value );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize selector attribute.
|
||||
*
|
||||
* @param int|float|string $attribute - Unclear Selector Attribute.
|
||||
* @return int|float|string
|
||||
*/
|
||||
public static function sanitize_selector( $attribute ) {
|
||||
if ( is_numeric( $attribute ) ) {
|
||||
if ( false === strpos( $attribute, '.' ) ) {
|
||||
$attribute = intval( $attribute );
|
||||
} else {
|
||||
$attribute = (float) $attribute;
|
||||
}
|
||||
} else {
|
||||
$attribute = sanitize_text_field( wp_unslash( $attribute ) );
|
||||
}
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize number attribute.
|
||||
*
|
||||
* @param string|int|float $attribute - Unclear Number Attribute.
|
||||
* @return int|float
|
||||
*/
|
||||
public static function sanitize_number( $attribute ) {
|
||||
$attribute = preg_replace( '/[^0-9.-]/', '', wp_unslash( $attribute ) );
|
||||
|
||||
// We should keep an empty string, because we allow resetting certain attributes.
|
||||
if ( '' === $attribute ) {
|
||||
$attribute = '';
|
||||
} elseif ( false === strpos( $attribute, '.' ) ) {
|
||||
$attribute = intval( $attribute );
|
||||
} else {
|
||||
$attribute = (float) $attribute;
|
||||
}
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize Element Selector.
|
||||
*
|
||||
* @param array $attribute - Unclear Element Selector Attribute.
|
||||
* @return array
|
||||
*/
|
||||
public static function sanitize_elements_selector( $attribute ) {
|
||||
$key = 'layout_elements';
|
||||
if ( ! empty( $attribute ) && is_array( $attribute ) ) {
|
||||
$controls = Visual_Portfolio_Controls::get_registered_array();
|
||||
$hight_level_allowed_locations = array_keys( $controls[ $key ]['locations'] );
|
||||
foreach ( $attribute as $locations_key => $locations ) {
|
||||
if (
|
||||
false !== array_search( $locations_key, $hight_level_allowed_locations, true ) &&
|
||||
! empty( $locations ) &&
|
||||
is_array( $locations )
|
||||
) {
|
||||
|
||||
$low_level_allowed_locations = array( 'elements' );
|
||||
|
||||
if (
|
||||
isset( $controls[ $key ]['locations'][ $locations_key ]['align'] ) &&
|
||||
! empty( $controls[ $key ]['locations'][ $locations_key ]['align'] )
|
||||
) {
|
||||
$low_level_allowed_locations = array_merge(
|
||||
$low_level_allowed_locations,
|
||||
array( 'align' )
|
||||
);
|
||||
$allowed_align_protocol = $controls[ $key ]['locations'][ $locations_key ]['align'];
|
||||
}
|
||||
|
||||
foreach ( $locations as $location_key => $location ) {
|
||||
if (
|
||||
false !== array_search( $location_key, $low_level_allowed_locations, true )
|
||||
) {
|
||||
if (
|
||||
'align' === $location_key &&
|
||||
isset( $allowed_align_protocol ) &&
|
||||
false !== array_search( $location, $allowed_align_protocol, true )
|
||||
) {
|
||||
$attribute[ $locations_key ][ $location_key ] = sanitize_text_field( wp_unslash( $location ) );
|
||||
} elseif (
|
||||
'elements' === $location_key &&
|
||||
is_array( $location )
|
||||
) {
|
||||
foreach ( $location as $item_key => $item ) {
|
||||
if (
|
||||
false !== array_search( $locations_key, $controls[ $key ]['options'][ $item ]['allowed_locations'], true ) &&
|
||||
isset( $controls[ $key ]['options'][ $item ]['allowed_locations'] )
|
||||
) {
|
||||
$attribute[ $locations_key ][ $location_key ][ $item_key ] = sanitize_text_field( wp_unslash( $item ) );
|
||||
} else {
|
||||
unset( $attribute[ $locations_key ][ $location_key ][ $item_key ] );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unset( $attribute[ $locations_key ][ $location_key ] );
|
||||
}
|
||||
} else {
|
||||
unset( $attribute[ $locations_key ][ $location_key ] );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unset( $attribute[ $locations_key ] );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$attribute = array();
|
||||
}
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize Gallery.
|
||||
*
|
||||
* @param array $attribute - Unclear Gallery Attribute.
|
||||
* @return array
|
||||
*/
|
||||
public static function sanitize_gallery( $attribute ) {
|
||||
if ( isset( $attribute ) && ! empty( $attribute ) ) {
|
||||
foreach ( $attribute as $key => $gallery_item ) {
|
||||
if ( isset( $gallery_item ) && ! empty( $gallery_item ) ) {
|
||||
foreach ( $gallery_item as $attribute_key => $media_attribute ) {
|
||||
switch ( $attribute_key ) {
|
||||
case 'imgUrl':
|
||||
case 'imgThumbnailUrl':
|
||||
case 'video_url':
|
||||
case 'author_url':
|
||||
case 'post_url':
|
||||
case 'url':
|
||||
$attribute[ $key ][ $attribute_key ] = esc_url_raw( wp_unslash( $media_attribute ) );
|
||||
break;
|
||||
case 'hover_image_focal_point':
|
||||
case 'focalPoint':
|
||||
if ( isset( $media_attribute ) && ! empty( $media_attribute ) ) {
|
||||
foreach ( $media_attribute as $focal_key => $focal_point ) {
|
||||
$attribute[ $key ][ $attribute_key ][ $focal_key ] = self::sanitize_number( $focal_point );
|
||||
}
|
||||
} else {
|
||||
$attribute[ $key ][ $attribute_key ] = null;
|
||||
}
|
||||
break;
|
||||
case 'custom_popup_image':
|
||||
case 'hover_image':
|
||||
$attribute[ $key ][ $attribute_key ] = self::sanitize_number( $media_attribute );
|
||||
break;
|
||||
case 'categories':
|
||||
if ( isset( $media_attribute ) && ! empty( $media_attribute ) ) {
|
||||
foreach ( $media_attribute as $category_key => $category ) {
|
||||
$attribute[ $key ][ $attribute_key ][ $category_key ] = sanitize_text_field( wp_unslash( $category ) );
|
||||
}
|
||||
} else {
|
||||
$attribute[ $key ][ $attribute_key ] = null;
|
||||
}
|
||||
break;
|
||||
case 'title':
|
||||
case 'description':
|
||||
$attribute[ $key ][ $attribute_key ] = wp_kses_post( wp_unslash( $media_attribute ) );
|
||||
break;
|
||||
case 'id':
|
||||
case 'author':
|
||||
case 'format':
|
||||
case 'deep_link_pid':
|
||||
default:
|
||||
$attribute[ $key ][ $attribute_key ] = sanitize_text_field( wp_unslash( $media_attribute ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$attribute = array();
|
||||
}
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize Attributes.
|
||||
*
|
||||
* @param array $attributes - Attributes.
|
||||
* @return array
|
||||
*/
|
||||
public static function sanitize_attributes( $attributes = array() ) {
|
||||
if ( ! empty( $attributes ) ) {
|
||||
$controls = Visual_Portfolio_Controls::get_registered_array();
|
||||
foreach ( $attributes as $key => $attribute ) {
|
||||
if ( 0 === strpos( $key, 'vp_' ) ) {
|
||||
$key = preg_replace( '/^vp_/', '', $key );
|
||||
$mode = 'preview';
|
||||
$attributes[ $key ] = $attribute;
|
||||
unset( $attributes[ 'vp_' . $key ] );
|
||||
}
|
||||
$sanitize_callback = $controls[ $key ]['sanitize_callback'] ?? false;
|
||||
if ( $sanitize_callback ) {
|
||||
$finding_class = is_string( $sanitize_callback ) && strripos( $sanitize_callback, '::' );
|
||||
|
||||
if ( false === $finding_class && is_callable( array( __CLASS__, $sanitize_callback ) ) ) {
|
||||
$attributes[ $key ] = call_user_func( array( __CLASS__, $sanitize_callback ), $attribute );
|
||||
} else {
|
||||
$attributes[ $key ] = call_user_func( $sanitize_callback, $attribute );
|
||||
}
|
||||
} else {
|
||||
$type = $controls[ $key ]['type'] ?? false;
|
||||
switch ( $type ) {
|
||||
case 'hidden':
|
||||
case 'checkbox':
|
||||
$attributes[ $key ] = self::sanitize_hidden( $attribute );
|
||||
break;
|
||||
case 'icons_selector':
|
||||
case 'text':
|
||||
case 'radio':
|
||||
case 'align':
|
||||
case 'buttons':
|
||||
$attributes[ $key ] = sanitize_text_field( wp_unslash( $attribute ) );
|
||||
break;
|
||||
case 'textarea':
|
||||
$attributes[ $key ] = sanitize_textarea_field( wp_unslash( $attribute ) );
|
||||
break;
|
||||
case 'aspect_ratio':
|
||||
$attributes[ $key ] = preg_replace( '/[^0-9:]/', '', wp_unslash( $attribute ) );
|
||||
break;
|
||||
case 'number':
|
||||
case 'range':
|
||||
$attributes[ $key ] = self::sanitize_number( $attribute );
|
||||
break;
|
||||
case 'tiles_selector':
|
||||
$attributes[ $key ] = preg_replace( '/[^0-9.,|]/', '', wp_unslash( $attribute ) );
|
||||
break;
|
||||
case 'select':
|
||||
$multiple = isset( $controls[ $key ]['multiple'] ) && ! empty( $controls[ $key ]['multiple'] ) ? $controls[ $key ]['multiple'] : false;
|
||||
|
||||
if ( $multiple ) {
|
||||
$attributes[ $key ] = $attributes[ $key ] ?? $controls[ $key ]['default'] ?? array();
|
||||
|
||||
if ( is_array( $attributes[ $key ] ) && ! empty( $attributes[ $key ] ) ) {
|
||||
foreach ( $attributes[ $key ] as $attribute_key => $value ) {
|
||||
$attributes[ $key ][ $attribute_key ] = self::sanitize_selector( $value );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$attributes[ $key ] = self::sanitize_selector( $attributes[ $key ] );
|
||||
}
|
||||
break;
|
||||
case 'elements_selector':
|
||||
$attributes[ $key ] = self::sanitize_elements_selector( $attribute );
|
||||
break;
|
||||
case 'code_editor':
|
||||
// Clear CSS. Maybe there will be an SVG validation error.
|
||||
$attributes[ $key ] = preg_replace( '#</?\w+#', '', wp_unslash( $attribute ) );
|
||||
break;
|
||||
case 'sortable':
|
||||
if ( is_array( $attribute ) && ! empty( $attribute ) ) {
|
||||
foreach ( $attribute as $attribute_key => $value ) {
|
||||
$attributes[ $key ][ $attribute_key ] = sanitize_text_field( wp_unslash( $value ) );
|
||||
}
|
||||
} else {
|
||||
$attributes[ $key ] = array();
|
||||
}
|
||||
break;
|
||||
case 'gallery':
|
||||
$attributes[ $key ] = self::sanitize_gallery( $attribute );
|
||||
break;
|
||||
case false:
|
||||
if ( 'block_id' === $key ) {
|
||||
$attributes[ $key ] = preg_replace( '/[^a-zA-Z0-9_-]/', '', wp_unslash( $attribute ) );
|
||||
} else {
|
||||
$attributes[ $key ] = sanitize_text_field( wp_unslash( $attribute ) );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$attributes[ $key ] = sanitize_text_field( wp_unslash( $attribute ) );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $mode ) && 'preview' === $mode ) {
|
||||
foreach ( $attributes as $key => $attribute ) {
|
||||
$attributes[ 'vp_' . $key ] = $attribute;
|
||||
unset( $attributes[ $key ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $attributes;
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_Security();
|
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
/**
|
||||
* Seo Optimization.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_SEO_Optimization
|
||||
*/
|
||||
class Visual_Portfolio_SEO_Optimization {
|
||||
/**
|
||||
* Visual_Portfolio_SEO_Optimization constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'init' ), 9 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize archive.
|
||||
*
|
||||
* @see __construct
|
||||
*/
|
||||
public function init() {
|
||||
add_filter( 'get_canonical_url', array( $this, 'optimize_canonical_url' ), 10, 2 );
|
||||
add_filter( 'get_shortlink', array( $this, 'optimize_shortlink' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize canonical URL.
|
||||
*
|
||||
* @param string $canonical_url - Canonical URL.
|
||||
* @param object $post - Current Post Object.
|
||||
* @return string
|
||||
*/
|
||||
public function optimize_canonical_url( $canonical_url, $post ) {
|
||||
return $this->optimize_url( $canonical_url, $post->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize shortlink.
|
||||
*
|
||||
* @param string $shortlink - Shortlink URL.
|
||||
* @param int $id - Post ID, or 0 for the current post.
|
||||
* @param string $context - The context for the link. One of 'post' or 'query'.
|
||||
* @return string
|
||||
*/
|
||||
public function optimize_shortlink( $shortlink, $id, $context ) {
|
||||
return 0 === $id && 'query' === $context ? $this->optimize_url( $shortlink, get_queried_object_id() ) : $shortlink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optimize url by supported GET variables: vp_page, vp_filter, vp_sort and vp_search.
|
||||
*
|
||||
* @param string $url - Not optimized URL.
|
||||
* @param int $post_id - Post ID.
|
||||
* @return string
|
||||
*/
|
||||
public function optimize_url( $url, $post_id ) {
|
||||
if (
|
||||
! Visual_Portfolio_Archive_Mapping::is_archive(
|
||||
array(
|
||||
'content_source' => 'post-based',
|
||||
'posts_source' => 'current_query',
|
||||
),
|
||||
$post_id
|
||||
) &&
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
isset( $_GET ) && ! empty( $_GET )
|
||||
) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
foreach ( $_GET as $key => $value ) {
|
||||
if ( 'vp_page' === $key || 'vp_filter' === $key || 'vp_sort' === $key || 'vp_search' === $key ) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$url = add_query_arg( array_map( 'sanitize_text_field', wp_unslash( array( $key => $value ) ) ), $url );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_SEO_Optimization();
|
914
wp-content/plugins/visual-portfolio/classes/class-settings.php
Normal file
914
wp-content/plugins/visual-portfolio/classes/class-settings.php
Normal file
@ -0,0 +1,914 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Settings
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
require_once visual_portfolio()->plugin_path . 'vendors/class-settings-api.php';
|
||||
|
||||
/**
|
||||
* Visual Portfolio Settings Class
|
||||
*/
|
||||
class Visual_Portfolio_Settings {
|
||||
/**
|
||||
* Settings API instance
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public static $settings_api;
|
||||
|
||||
/**
|
||||
* Cached settings fields. We call settings fields method a lot of times to get default values.
|
||||
* So, for performance reasons we need to cache the output.
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
public static $cached_settings_fields;
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Settings constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
self::init_actions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Option Value
|
||||
*
|
||||
* @param string $option - option name.
|
||||
* @param string $section - section name.
|
||||
* @param string $deprecated_default - default option value.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
// phpcs:ignore
|
||||
public static function get_option( $option, $section, $deprecated_default = '' ) {
|
||||
$options = get_option( $section );
|
||||
$result = '';
|
||||
|
||||
if ( isset( $options[ $option ] ) ) {
|
||||
$result = $options[ $option ];
|
||||
} else {
|
||||
// find default.
|
||||
$fields = self::get_settings_fields();
|
||||
|
||||
if ( isset( $fields[ $section ] ) && is_array( $fields[ $section ] ) ) {
|
||||
foreach ( $fields[ $section ] as $field_data ) {
|
||||
if ( $option === $field_data['name'] && isset( $field_data['default'] ) ) {
|
||||
$result = $field_data['default'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 'off' === $result ? false : ( 'on' === $result ? true : $result );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Option Value
|
||||
*
|
||||
* @param string $option - option name.
|
||||
* @param string $section - section name.
|
||||
* @param string $value - new option value.
|
||||
*/
|
||||
public static function update_option( $option, $section, $value ) {
|
||||
$options = get_option( $section );
|
||||
|
||||
if ( ! is_array( $options ) ) {
|
||||
$options = array();
|
||||
}
|
||||
|
||||
$options[ $option ] = $value;
|
||||
|
||||
update_option( $section, $options );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init actions
|
||||
*/
|
||||
public static function init_actions() {
|
||||
self::$settings_api = new Visual_Portfolio_Settings_API();
|
||||
|
||||
add_action( 'admin_init', array( __CLASS__, 'admin_init' ) );
|
||||
add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ), 11 );
|
||||
|
||||
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'wp_ajax_vp_get_pages_list', array( __CLASS__, 'get_posts_ajax_callback' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the settings
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function admin_init() {
|
||||
self::redirect_if_toggle_unregistered_portfolio_post_type();
|
||||
// set the settings.
|
||||
self::$settings_api->set_sections( self::get_settings_sections() );
|
||||
self::$settings_api->set_fields( self::get_settings_fields() );
|
||||
|
||||
// initialize settings.
|
||||
self::$settings_api->admin_init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the admin settings menu
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function admin_menu() {
|
||||
remove_submenu_page( 'visual-portfolio-settings', 'visual-portfolio-settings' );
|
||||
add_submenu_page(
|
||||
Visual_Portfolio_Custom_Post_Type::get_menu_slug(),
|
||||
esc_html__( 'Settings', 'visual-portfolio' ),
|
||||
esc_html__( 'Settings', 'visual-portfolio' ),
|
||||
'manage_options',
|
||||
'visual-portfolio-settings',
|
||||
array( __CLASS__, 'print_settings_page' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to actual admin page if unregistered portfolio post type.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function redirect_if_toggle_unregistered_portfolio_post_type() {
|
||||
global $pagenow;
|
||||
$register_portfolio_post_type = Visual_Portfolio_Custom_Post_Type::portfolio_post_type_is_registered();
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if (
|
||||
$register_portfolio_post_type &&
|
||||
'admin.php' === $pagenow &&
|
||||
isset( $_GET['page'] ) &&
|
||||
'visual-portfolio-settings' === $_GET['page']
|
||||
) {
|
||||
wp_safe_redirect( admin_url( '/edit.php?post_type=portfolio&page=visual-portfolio-settings' ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
if (
|
||||
! $register_portfolio_post_type &&
|
||||
'edit.php' === $pagenow &&
|
||||
isset( $_GET['page'] ) &&
|
||||
'visual-portfolio-settings' === $_GET['page'] &&
|
||||
isset( $_GET['post_type'] ) &&
|
||||
'portfolio' === $_GET['post_type']
|
||||
) {
|
||||
wp_safe_redirect( admin_url( '/admin.php?page=visual-portfolio-settings' ) );
|
||||
exit;
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue archive select2 ajax script.
|
||||
*
|
||||
* @param string $page - Current admin page.
|
||||
* @return void
|
||||
*/
|
||||
public static function admin_enqueue_scripts( $page ) {
|
||||
if ( 'portfolio_page_visual-portfolio-settings' === $page || 'toplevel_page_visual-portfolio-settings' === $page ) {
|
||||
$data_init = array(
|
||||
'nonce' => wp_create_nonce( 'vp-ajax-nonce' ),
|
||||
);
|
||||
|
||||
Visual_Portfolio_Assets::enqueue_script( 'visual-portfolio-archive-page-selector', 'build/assets/admin/js/archive-page-selector', array( 'select2' ) );
|
||||
|
||||
wp_localize_script( 'visual-portfolio-archive-page-selector', 'VPAdminVariables', $data_init );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Plugin settings sections
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_settings_sections() {
|
||||
$sections = array(
|
||||
array(
|
||||
'id' => 'vp_general',
|
||||
'title' => esc_html__( 'General', 'visual-portfolio' ),
|
||||
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4" /></svg>',
|
||||
),
|
||||
array(
|
||||
'id' => 'vp_images',
|
||||
'title' => esc_html__( 'Images', 'visual-portfolio' ),
|
||||
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" /></svg>',
|
||||
),
|
||||
array(
|
||||
'id' => 'vp_popup_gallery',
|
||||
'title' => esc_html__( 'Popup & Lightbox', 'visual-portfolio' ),
|
||||
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11H5m14 0a2 2 0 012 2v6a2 2 0 01-2 2H5a2 2 0 01-2-2v-6a2 2 0 012-2m14 0V9a2 2 0 00-2-2M5 11V9a2 2 0 012-2m0 0V5a2 2 0 012-2h6a2 2 0 012 2v2M7 7h10"></path></svg>',
|
||||
),
|
||||
array(
|
||||
'id' => 'vp_watermarks',
|
||||
'title' => esc_html__( 'Watermarks', 'visual-portfolio' ),
|
||||
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z" /></svg>',
|
||||
),
|
||||
array(
|
||||
'id' => 'vp_social_integrations',
|
||||
'title' => esc_html__( 'Social Feeds', 'visual-portfolio' ),
|
||||
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9a9 9 0 01-9-9m9 9c1.657 0 3-4.03 3-9s-1.343-9-3-9m0 18c-1.657 0-3-4.03-3-9s1.343-9 3-9m-9 9a9 9 0 019-9" /></svg>',
|
||||
),
|
||||
array(
|
||||
'id' => 'vp_white_label',
|
||||
'title' => esc_html__( 'White Label', 'visual-portfolio' ),
|
||||
'icon' => '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4M7.835 4.697a3.42 3.42 0 001.946-.806 3.42 3.42 0 014.438 0 3.42 3.42 0 001.946.806 3.42 3.42 0 013.138 3.138 3.42 3.42 0 00.806 1.946 3.42 3.42 0 010 4.438 3.42 3.42 0 00-.806 1.946 3.42 3.42 0 01-3.138 3.138 3.42 3.42 0 00-1.946.806 3.42 3.42 0 01-4.438 0 3.42 3.42 0 00-1.946-.806 3.42 3.42 0 01-3.138-3.138 3.42 3.42 0 00-.806-1.946 3.42 3.42 0 010-4.438 3.42 3.42 0 00.806-1.946 3.42 3.42 0 013.138-3.138z" /></svg>',
|
||||
),
|
||||
);
|
||||
|
||||
return apply_filters( 'vpf_settings_sections', $sections );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the settings fields
|
||||
*
|
||||
* @return array settings fields
|
||||
*/
|
||||
public static function get_settings_fields() {
|
||||
if ( ! empty( self::$cached_settings_fields ) ) {
|
||||
return self::$cached_settings_fields;
|
||||
}
|
||||
|
||||
$default_breakpoints = Visual_Portfolio_Breakpoints::get_default_breakpoints();
|
||||
$go_pro_links = array(
|
||||
'watermarks' => Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'utm_medium' => 'settings_page',
|
||||
'utm_campaign' => 'watermarks',
|
||||
)
|
||||
),
|
||||
'social' => Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'utm_medium' => 'settings_page',
|
||||
'utm_campaign' => 'social_feeds',
|
||||
)
|
||||
),
|
||||
'white_label' => Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'utm_medium' => 'settings_page',
|
||||
'utm_campaign' => 'white_label',
|
||||
)
|
||||
),
|
||||
);
|
||||
|
||||
$settings_fields = array(
|
||||
'vp_general' => array(
|
||||
array(
|
||||
'name' => 'register_portfolio_post_type',
|
||||
'label' => esc_html__( 'Register Portfolio Post Type', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Add custom post type `portfolio` to showcase your works.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
array(
|
||||
'name' => 'portfolio_archive_page',
|
||||
'label' => esc_html__( 'Archive Page', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Base page of your portfolio, where will be placed your works archive.', 'visual-portfolio' ),
|
||||
'type' => 'select',
|
||||
'options' => self::get_pages_list(),
|
||||
'sanitize_callback' => array( 'Visual_Portfolio_Archive_Mapping', 'save_archive_page_option' ),
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[type="checkbox"][name="vp_general[register_portfolio_post_type]"]',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => 'archive_page_items_per_page',
|
||||
'label' => esc_html__( 'Archive Page Items Per Page', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'min' => -1,
|
||||
'max' => 9999,
|
||||
'default' => 6,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[type="checkbox"][name="vp_general[register_portfolio_post_type]"]',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => 'filter_taxonomies',
|
||||
'label' => esc_html__( 'Filter Taxonomies', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'You can show custom taxonomies in the portfolio Filter. Enter some taxonomies by "," separating values. Example: "product_cat,product_tag"', 'visual-portfolio' ),
|
||||
'type' => 'text',
|
||||
'default' => '',
|
||||
),
|
||||
array(
|
||||
'name' => 'no_image',
|
||||
'label' => esc_html__( 'Placeholder Image', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'This image used on items in layouts where image is not specified.', 'visual-portfolio' ),
|
||||
'type' => 'image',
|
||||
'default' => '',
|
||||
'options' => array(
|
||||
'button_label' => esc_html__( 'Choose image', 'visual-portfolio' ),
|
||||
),
|
||||
),
|
||||
|
||||
// AJAX Caching and Preloading.
|
||||
array(
|
||||
'name' => 'ajax_caching',
|
||||
'label' => esc_html__( 'AJAX Cache and Preload', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Reduce AJAX calls request time.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => class_exists( 'Visual_Portfolio_Pro' ) ? 'on' : 'off',
|
||||
'is_pro' => true,
|
||||
),
|
||||
|
||||
// Breakpoints.
|
||||
array(
|
||||
'name' => 'breakpoints_title',
|
||||
'label' => esc_html__( 'Responsive Breakpoints', 'visual-portfolio' ),
|
||||
'type' => 'section_title',
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'breakpoint_xl',
|
||||
'label' => esc_html__( 'Extra Large', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'min' => (float) $default_breakpoints['lg'] + 1,
|
||||
'max' => 3840,
|
||||
'placeholder' => (string) $default_breakpoints['xl'],
|
||||
'default' => (float) $default_breakpoints['xl'],
|
||||
// translators: %1$s - default breakpoint.
|
||||
'desc' => sprintf( esc_html__( 'Sets the breakpoint on extra large screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['xl'] ),
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'breakpoint_lg',
|
||||
'label' => esc_html__( 'Large', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'min' => (float) $default_breakpoints['md'] + 1,
|
||||
'max' => (float) $default_breakpoints['xl'] - 1,
|
||||
'placeholder' => (string) $default_breakpoints['lg'],
|
||||
'default' => (float) $default_breakpoints['lg'],
|
||||
// translators: %1$s - default breakpoint.
|
||||
'desc' => sprintf( esc_html__( 'Sets the breakpoint on large screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['lg'] ),
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'breakpoint_md',
|
||||
'label' => esc_html__( 'Medium', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'min' => (float) $default_breakpoints['sm'] + 1,
|
||||
'max' => (float) $default_breakpoints['lg'] - 1,
|
||||
'placeholder' => (string) $default_breakpoints['md'],
|
||||
'default' => (float) $default_breakpoints['md'],
|
||||
// translators: %1$s - default breakpoint.
|
||||
'desc' => sprintf( esc_html__( 'Sets the breakpoint on medium screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['md'] ),
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'breakpoint_sm',
|
||||
'label' => esc_html__( 'Small', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'min' => (float) $default_breakpoints['xs'] + 1,
|
||||
'max' => (float) $default_breakpoints['md'] - 1,
|
||||
'placeholder' => (string) $default_breakpoints['sm'],
|
||||
'default' => (float) $default_breakpoints['sm'],
|
||||
// translators: %1$s - default breakpoint.
|
||||
'desc' => sprintf( esc_html__( 'Sets the breakpoint on small screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['sm'] ),
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'breakpoint_xs',
|
||||
'label' => esc_html__( 'Extra Small', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'min' => 1,
|
||||
'max' => (float) $default_breakpoints['sm'] - 1,
|
||||
'placeholder' => (string) $default_breakpoints['xs'],
|
||||
'default' => (float) $default_breakpoints['xs'],
|
||||
// translators: %1$s - default breakpoint.
|
||||
'desc' => sprintf( esc_html__( 'Sets the breakpoint on extra small screen sizes (Default: %1$spx).', 'visual-portfolio' ), $default_breakpoints['xs'] ),
|
||||
'is_pro' => true,
|
||||
),
|
||||
),
|
||||
'vp_images' => array(
|
||||
array(
|
||||
'name' => 'lazy_loading',
|
||||
'label' => esc_html__( 'Lazy Loading', 'visual-portfolio' ),
|
||||
// translators: %s - plugin brand name.
|
||||
'desc' => sprintf( esc_html__( 'Enable lazy loading for %s layouts only or for the whole website.', 'visual-portfolio' ), visual_portfolio()->plugin_name ),
|
||||
'type' => 'select',
|
||||
'default' => 'vp',
|
||||
'options' => array(
|
||||
'' => esc_html__( 'Disabled', 'visual-portfolio' ),
|
||||
// translators: %s - plugin brand name.
|
||||
'vp' => sprintf( esc_html__( '%s Only', 'visual-portfolio' ), visual_portfolio()->plugin_name ),
|
||||
'full' => esc_html__( 'All images', 'visual-portfolio' ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => 'lazy_loading_excludes',
|
||||
'label' => esc_html__( 'Lazy Loading Excludes', 'visual-portfolio' ),
|
||||
// translators: %s - doc url.
|
||||
// translators: %s - link text.
|
||||
'desc' => sprintf( __( 'Listed images will not be lazy loaded. Both full URLs and partial strings can be used. One per line. <a href="%1$s">%2$s</a>', 'visual-portfolio' ), 'https://visualportfolio.co/docs/settings/images/', esc_html__( 'More info', 'visual-portfolio' ) ),
|
||||
'type' => 'textarea',
|
||||
'placeholder' => "image-example.webp\nslider-image-classname",
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[name="vp_images[lazy_loading]"]',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
array(
|
||||
'name' => 'images_layouts_title',
|
||||
'label' => esc_html__( 'Layouts Image Sizes', 'visual-portfolio' ),
|
||||
'desc' => __( 'Image sizes used in portfolio layouts.', 'visual-portfolio' ),
|
||||
'type' => 'section_title',
|
||||
),
|
||||
array(
|
||||
'name' => 'sm',
|
||||
'label' => esc_html__( 'Small', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'placeholder' => '500',
|
||||
'default' => 500,
|
||||
),
|
||||
array(
|
||||
'name' => 'md',
|
||||
'label' => esc_html__( 'Medium', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'placeholder' => '800',
|
||||
'default' => 800,
|
||||
),
|
||||
array(
|
||||
'name' => 'lg',
|
||||
'label' => esc_html__( 'Large', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'placeholder' => '1280',
|
||||
'default' => 1280,
|
||||
),
|
||||
array(
|
||||
'name' => 'xl',
|
||||
'label' => esc_html__( 'Extra Large', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'placeholder' => '1920',
|
||||
'default' => 1920,
|
||||
),
|
||||
array(
|
||||
'name' => 'images_popup_title',
|
||||
'label' => esc_html__( 'Lightbox Image Sizes', 'visual-portfolio' ),
|
||||
'desc' => __( 'Image sizes used in lightbox images.', 'visual-portfolio' ),
|
||||
'type' => 'section_title',
|
||||
),
|
||||
array(
|
||||
'name' => 'sm_popup',
|
||||
'label' => esc_html__( 'Small', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'placeholder' => '500',
|
||||
'default' => 500,
|
||||
),
|
||||
array(
|
||||
'name' => 'md_popup',
|
||||
'label' => esc_html__( 'Medium', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'placeholder' => '800',
|
||||
'default' => 800,
|
||||
),
|
||||
array(
|
||||
'name' => 'xl_popup',
|
||||
'label' => esc_html__( 'Large', 'visual-portfolio' ),
|
||||
'type' => 'number',
|
||||
'placeholder' => '1920',
|
||||
'default' => 1920,
|
||||
),
|
||||
array(
|
||||
'name' => 'images_sizes_note',
|
||||
// translators: %s: regenerate thumbnails url.
|
||||
'desc' => sprintf( __( 'After publishing your changes, new image sizes may not be shown until you <a href="%s" target="_blank">Regenerate Thumbnails</a>.', 'visual-portfolio' ), 'https://wordpress.org/plugins/regenerate-thumbnails/' ),
|
||||
'type' => 'html',
|
||||
),
|
||||
),
|
||||
'vp_popup_gallery' => array(
|
||||
// Vendor.
|
||||
array(
|
||||
'name' => 'vendor',
|
||||
'label' => esc_html__( 'Vendor Script', 'visual-portfolio' ),
|
||||
'type' => 'select',
|
||||
'options' => array(
|
||||
'fancybox' => esc_html__( 'Fancybox', 'visual-portfolio' ),
|
||||
'photoswipe' => esc_html__( 'PhotoSwipe', 'visual-portfolio' ),
|
||||
),
|
||||
'default' => 'fancybox',
|
||||
),
|
||||
|
||||
// Default WordPress Images.
|
||||
array(
|
||||
'name' => 'enable_on_wordpress_images',
|
||||
'label' => esc_html__( 'Lightbox for WordPress Images', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Enable lightbox for WordPress native galleries and images.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'off',
|
||||
),
|
||||
|
||||
// Section divider.
|
||||
array(
|
||||
'name' => 'popup_general_divider_title',
|
||||
'type' => 'section_title',
|
||||
),
|
||||
|
||||
// Deeplinking.
|
||||
array(
|
||||
'name' => 'deep_linking',
|
||||
'label' => esc_html__( 'Deep Linking', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Makes URL automatically change to reflect the current opened popup, and you can easily link directly to that image or video.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => class_exists( 'Visual_Portfolio_Pro' ) ? 'on' : 'off',
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'deep_linking_url_to_share_images',
|
||||
'label' => esc_html__( 'Use Deep Linking URL to Share Images', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Check to share Deep Linking URLs when sharing images. When disabled, all galleries will share direct links to image files.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => class_exists( 'Visual_Portfolio_Pro' ) ? 'on' : 'off',
|
||||
'is_pro' => true,
|
||||
),
|
||||
|
||||
// Loop.
|
||||
array(
|
||||
'name' => 'loop',
|
||||
'label' => esc_html__( 'Loop', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
'is_pro' => true,
|
||||
),
|
||||
|
||||
// Click to Zoom.
|
||||
array(
|
||||
'name' => 'click_to_zoom',
|
||||
'label' => esc_html__( 'Click to Zoom', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
|
||||
// Restore Focus.
|
||||
array(
|
||||
'name' => 'restore_focus',
|
||||
'label' => esc_html__( 'Restore Focus', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Restore focus on the last active item after Popup is closed.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
|
||||
// UI Elements.
|
||||
array(
|
||||
'name' => 'popup_ui_elements_title',
|
||||
'label' => esc_html__( 'UI Elements', 'visual-portfolio' ),
|
||||
'type' => 'section_title',
|
||||
),
|
||||
array(
|
||||
'name' => 'show_arrows',
|
||||
'label' => esc_html__( 'Display Arrows', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Arrows to navigate between images.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
array(
|
||||
'name' => 'show_counter',
|
||||
'label' => esc_html__( 'Display Images Counter', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'On the top left corner will be showed images counter.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
array(
|
||||
'name' => 'show_zoom_button',
|
||||
'label' => esc_html__( 'Display Zoom Button', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
array(
|
||||
'name' => 'show_fullscreen_button',
|
||||
'label' => esc_html__( 'Display Fullscreen Button', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
array(
|
||||
'name' => 'show_share_button',
|
||||
'label' => esc_html__( 'Display Share Button', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
array(
|
||||
'name' => 'show_close_button',
|
||||
'label' => esc_html__( 'Display Close Button', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
),
|
||||
|
||||
// Fancybox Popup Settings.
|
||||
array(
|
||||
'name' => 'show_thumbs',
|
||||
'label' => esc_html__( 'Display Thumbnails', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[name="vp_popup_gallery[vendor]"]',
|
||||
'operator' => '===',
|
||||
'value' => 'fancybox',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => 'thumbs_auto_start',
|
||||
'label' => esc_html__( 'Thumbnails Opened At Startup', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'off',
|
||||
'is_pro' => true,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[type="checkbox"][name="vp_popup_gallery[show_thumbs]"]',
|
||||
),
|
||||
array(
|
||||
'control' => '[name="vp_popup_gallery[vendor]"]',
|
||||
'operator' => '===',
|
||||
'value' => 'fancybox',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => 'thumbs_position',
|
||||
'label' => esc_html__( 'Thumbnails Position', 'visual-portfolio' ),
|
||||
'type' => 'select',
|
||||
'default' => 'vertical',
|
||||
'options' => array(
|
||||
'vertical' => esc_html__( 'Vertical', 'visual-portfolio' ),
|
||||
'horizontal' => esc_html__( 'Horizontal', 'visual-portfolio' ),
|
||||
),
|
||||
'is_pro' => true,
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[type="checkbox"][name="vp_popup_gallery[show_thumbs]"]',
|
||||
),
|
||||
array(
|
||||
'control' => '[name="vp_popup_gallery[vendor]"]',
|
||||
'operator' => '===',
|
||||
'value' => 'fancybox',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => 'show_download_button',
|
||||
'label' => esc_html__( 'Display Download Button', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'off',
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[name="vp_popup_gallery[vendor]"]',
|
||||
'operator' => '===',
|
||||
'value' => 'fancybox',
|
||||
),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'name' => 'show_slideshow',
|
||||
'label' => esc_html__( 'Display Slideshow', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'off',
|
||||
'condition' => array(
|
||||
array(
|
||||
'control' => '[name="vp_popup_gallery[vendor]"]',
|
||||
'operator' => '===',
|
||||
'value' => 'fancybox',
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Quick View settings.
|
||||
array(
|
||||
'name' => 'popup_quick_view_title',
|
||||
'label' => esc_html__( 'Quick View', 'visual-portfolio' ),
|
||||
'type' => 'section_title',
|
||||
),
|
||||
array(
|
||||
'name' => 'popup_quick_view_show_url_button',
|
||||
'label' => esc_html__( 'Display URL Button', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'Button with page URL will be placed in the popup toolbar.', 'visual-portfolio' ),
|
||||
'type' => 'toggle',
|
||||
'default' => 'on',
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'popup_quick_view_internal_links_target',
|
||||
'label' => esc_html__( 'Internal Links', 'visual-portfolio' ),
|
||||
'type' => 'select',
|
||||
'default' => '_blank',
|
||||
'options' => array(
|
||||
'_blank' => esc_html__( 'Open in New Tab', 'visual-portfolio' ),
|
||||
'_top' => esc_html__( 'Open in Current Tab', 'visual-portfolio' ),
|
||||
'_self' => esc_html__( 'Open in Frame (not recommended)', 'visual-portfolio' ),
|
||||
'prevent-click' => esc_html__( 'Prevent Click', 'visual-portfolio' ),
|
||||
),
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'popup_quick_view_external_links_target',
|
||||
'label' => esc_html__( 'External Links', 'visual-portfolio' ),
|
||||
'type' => 'select',
|
||||
'default' => '_blank',
|
||||
'options' => array(
|
||||
'_blank' => esc_html__( 'Open in New Tab', 'visual-portfolio' ),
|
||||
'_top' => esc_html__( 'Open in Current Tab', 'visual-portfolio' ),
|
||||
'_self' => esc_html__( 'Open in Frame (not recommended)', 'visual-portfolio' ),
|
||||
'prevent-click' => esc_html__( 'Prevent Click', 'visual-portfolio' ),
|
||||
),
|
||||
'is_pro' => true,
|
||||
),
|
||||
array(
|
||||
'name' => 'pages_iframe_custom_css',
|
||||
'label' => esc_html__( 'Custom CSS', 'visual-portfolio' ),
|
||||
'desc' => esc_html__( 'When you display posts and pages in popup iframe, you may not need some page elements like header and footer. Hide it using custom CSS with classname `.vp-popup-iframe`.', 'visual-portfolio' ),
|
||||
'type' => 'textarea',
|
||||
'default' => ! class_exists( 'Visual_Portfolio_Pro' ) ? '' : '
|
||||
/* Hide header and footer in standard themes */
|
||||
.vp-popup-iframe #site-header,
|
||||
.vp-popup-iframe #masthead,
|
||||
.vp-popup-iframe #site-footer,
|
||||
.vp-popup-iframe #colophon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide header and footer in Twenty Twenty-Two theme (Full Site Editing) */
|
||||
.vp-popup-iframe .wp-site-blocks > header.wp-block-template-part,
|
||||
.vp-popup-iframe .wp-site-blocks > footer.wp-block-template-part {
|
||||
display: none;
|
||||
}',
|
||||
'is_pro' => true,
|
||||
),
|
||||
|
||||
// Misc settings.
|
||||
array(
|
||||
'name' => 'popup_misc_title',
|
||||
'label' => esc_html__( 'Misc', 'visual-portfolio' ),
|
||||
'type' => 'section_title',
|
||||
),
|
||||
array(
|
||||
'name' => 'background_color',
|
||||
'label' => esc_html__( 'Background Color', 'visual-portfolio' ),
|
||||
'type' => 'color',
|
||||
'default' => '#1e1e1e',
|
||||
),
|
||||
),
|
||||
'vp_watermarks' => array(
|
||||
array(
|
||||
'name' => 'pro_info',
|
||||
'desc' => '
|
||||
<div class="vpf-pro-note vpf-settings-info-pro">
|
||||
<h3>' . esc_html__( 'Premium Only', 'visual-portfolio' ) . '</h3>
|
||||
<div>
|
||||
<p class="vpf-pro-note-description">' . esc_html__( 'Protect your works using watermarks', 'visual-portfolio' ) . '</p>
|
||||
<a class="vpf-pro-note-button" target="_blank" rel="noopener noreferrer" href="' . esc_url( $go_pro_links['watermarks'] ) . '">' . esc_html__( 'Go Pro', 'visual-portfolio' ) . '</a>
|
||||
</div>
|
||||
</div>
|
||||
',
|
||||
'type' => 'html',
|
||||
),
|
||||
),
|
||||
'vp_social_integrations' => array(
|
||||
array(
|
||||
'name' => 'pro_info',
|
||||
'desc' => '
|
||||
<div class="vpf-pro-note vpf-settings-info-pro">
|
||||
<h3>' . esc_html__( 'Premium Only', 'visual-portfolio' ) . '</h3>
|
||||
<div>
|
||||
<p class="vpf-pro-note-description">' . esc_html__( 'Social feeds such as Instagram, Youtube, Flickr, Twitter, etc...', 'visual-portfolio' ) . '</p>
|
||||
<a class="vpf-pro-note-button" target="_blank" rel="noopener noreferrer" href="' . esc_url( $go_pro_links['social'] ) . '">' . esc_html__( 'Go Pro', 'visual-portfolio' ) . '</a>
|
||||
</div>
|
||||
</div>
|
||||
',
|
||||
'type' => 'html',
|
||||
),
|
||||
),
|
||||
'vp_white_label' => array(
|
||||
array(
|
||||
'name' => 'pro_info',
|
||||
'desc' => '
|
||||
<div class="vpf-pro-note">
|
||||
<h3>' . esc_html__( 'Premium Only', 'visual-portfolio' ) . '</h3>
|
||||
<div>
|
||||
<p class="vpf-pro-note-description">' . esc_html__( 'Remove our plugin brand and logos from Front and Admin areas', 'visual-portfolio' ) . '</p>
|
||||
<a class="vpf-pro-note-button" target="_blank" rel="noopener noreferrer" href="' . esc_url( $go_pro_links['white_label'] ) . '">' . esc_html__( 'Go Pro', 'visual-portfolio' ) . '</a>
|
||||
</div>
|
||||
</div>
|
||||
',
|
||||
'type' => 'html',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
self::$cached_settings_fields = apply_filters( 'vpf_settings_fields', $settings_fields );
|
||||
|
||||
return self::$cached_settings_fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* The plugin page handler
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function print_settings_page() {
|
||||
self::$settings_api->admin_enqueue_scripts();
|
||||
|
||||
echo '<div class="wrap">';
|
||||
echo '<h2>' . esc_html__( 'Settings', 'visual-portfolio' ) . '</h2>';
|
||||
|
||||
self::$settings_api->show_navigation();
|
||||
self::$settings_api->show_forms();
|
||||
|
||||
echo '</div>';
|
||||
|
||||
?>
|
||||
<script>
|
||||
(function( $ ) {
|
||||
// Don't allow adding input number values that > then max attribute and < min attribute.
|
||||
$('form').on('input', '[type="number"]', function(e) {
|
||||
var current = parseFloat( this.value );
|
||||
var min = parseFloat(this.min);
|
||||
var max = parseFloat(this.max);
|
||||
|
||||
if ('' !== this.value) {
|
||||
if (!Number.isNaN(min) && current < min) {
|
||||
this.value = min;
|
||||
}
|
||||
if (!Number.isNaN(max) && current > max) {
|
||||
this.value = max;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
<?php if ( ! class_exists( 'Visual_Portfolio_Pro' ) ) : ?>
|
||||
// disable pro inputs.
|
||||
$('.vpf-settings-control-pro').find('input, textarea').attr('disabled', 'disabled');
|
||||
<?php endif; ?>
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Pages List.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_pages_list() {
|
||||
$options = get_option( 'vp_general' );
|
||||
$archive_page = $options['portfolio_archive_page'] ?? false;
|
||||
$pages_list = array(
|
||||
'' => esc_html__( '-- Select Page --', 'visual-portfolio' ),
|
||||
);
|
||||
if ( $archive_page ) {
|
||||
$archive_title = get_post_field( 'post_title', $archive_page );
|
||||
$pages_list[ $archive_page ] = $archive_title;
|
||||
}
|
||||
return $pages_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Posts for Select2 archive page field by Ajax.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function get_posts_ajax_callback() {
|
||||
if ( isset( $_REQUEST['nonce'] ) && wp_verify_nonce( sanitize_key( $_REQUEST['nonce'] ), 'vp-ajax-nonce' ) ) {
|
||||
$return = array();
|
||||
$query_opts = array(
|
||||
'post_status' => 'publish',
|
||||
'ignore_sticky_posts' => 1,
|
||||
'posts_per_page' => 50,
|
||||
'post_type' => 'page',
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
);
|
||||
|
||||
if ( isset( $_GET['q'] ) && ! empty( $_GET['q'] ) ) {
|
||||
$query_opts['s'] = sanitize_text_field( wp_unslash( $_GET['q'] ) );
|
||||
}
|
||||
|
||||
$search_results = new WP_Query( $query_opts );
|
||||
|
||||
if ( $search_results->have_posts() ) {
|
||||
while ( $search_results->have_posts() ) {
|
||||
$search_results->the_post();
|
||||
$title = ( mb_strlen( $search_results->post->post_title ) > 50 ) ? mb_substr( $search_results->post->post_title, 0, 49 ) . '...' : $search_results->post->post_title;
|
||||
$return[] = array( $search_results->post->ID, $title );
|
||||
}
|
||||
}
|
||||
|
||||
echo wp_json_encode( $return );
|
||||
}
|
||||
|
||||
die;
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Settings();
|
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* Shortcode
|
||||
*
|
||||
* @package visual-portfolio/shortcode
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Shortcode
|
||||
*/
|
||||
class Visual_Portfolio_Shortcode {
|
||||
/**
|
||||
* Visual_Portfolio_Shortcode constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// add shortcode.
|
||||
add_shortcode( 'visual_portfolio', array( $this, 'get_shortcode_out' ) );
|
||||
add_shortcode( 'visual_portfolio_filter', array( $this, 'get_shortcode_filter_out' ) );
|
||||
add_shortcode( 'visual_portfolio_sort', array( $this, 'get_shortcode_sort_out' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode Output
|
||||
*
|
||||
* @param array $atts shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function get_shortcode_out( $atts = array() ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => '',
|
||||
'class' => '',
|
||||
'vc_css' => '',
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
return Visual_Portfolio_Get::get( $atts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode Filter Output
|
||||
*
|
||||
* @param array $atts shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function get_shortcode_filter_out( $atts = array() ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => '',
|
||||
'type' => 'default',
|
||||
'align' => 'center',
|
||||
'show_count' => false,
|
||||
'text_all' => esc_attr__( 'All', 'visual-portfolio' ),
|
||||
'class' => '',
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
return Visual_Portfolio_Get::get_filter( $atts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcode Sort Output
|
||||
*
|
||||
* @param array $atts shortcode attributes.
|
||||
* @return string
|
||||
*/
|
||||
public function get_shortcode_sort_out( $atts = array() ) {
|
||||
$atts = shortcode_atts(
|
||||
array(
|
||||
'id' => '',
|
||||
'type' => 'default',
|
||||
'align' => 'center',
|
||||
'class' => '',
|
||||
),
|
||||
$atts
|
||||
);
|
||||
|
||||
return Visual_Portfolio_Get::get_sort( $atts );
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Shortcode();
|
155
wp-content/plugins/visual-portfolio/classes/class-sitemap.php
Normal file
155
wp-content/plugins/visual-portfolio/classes/class-sitemap.php
Normal file
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/**
|
||||
* Supported Images in Sitemap (SEO).
|
||||
*
|
||||
* @package visual-portfolio/sitemap
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Sitemap class
|
||||
*/
|
||||
class Visual_Portfolio_Sitemap {
|
||||
/**
|
||||
* Visual_Portfolio_Sitemap constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_filter( 'aioseo_sitemap_posts', array( $this, 'add_images_to_aioseo_sitemap' ), 10, 1 );
|
||||
add_filter( 'rank_math/sitemap/urlimages', array( $this, 'add_images_to_sitemap' ), 10, 2 );
|
||||
add_filter( 'wpseo_sitemap_urlimages', array( $this, 'add_images_to_sitemap' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add sitemap entries for All In One SEO.
|
||||
*
|
||||
* @param array $entries - Sitemap entries.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_images_to_aioseo_sitemap( $entries ) {
|
||||
if ( is_array( $entries ) ) {
|
||||
foreach ( $entries as &$entry ) {
|
||||
$post_permalink = $entry['loc'];
|
||||
$post_id = url_to_postid( $post_permalink );
|
||||
$images = isset( $entry['images'] ) ? $entry['images'] : array();
|
||||
|
||||
if ( 0 === $post_id ) {
|
||||
$archive_page = Visual_Portfolio_Settings::get_option( 'portfolio_archive_page', 'vp_general' );
|
||||
|
||||
if ( get_permalink( $archive_page ) === $post_permalink ) {
|
||||
$post_id = $archive_page;
|
||||
}
|
||||
}
|
||||
|
||||
$block_images = $this->parse_images_from_blocks( $post_id );
|
||||
|
||||
if ( ! empty( $block_images ) ) {
|
||||
foreach ( $block_images as $image ) {
|
||||
$images[] = (object) array(
|
||||
'image:loc' => $image['src'],
|
||||
'image:caption' => $image['alt'],
|
||||
'image:title' => $image['title'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$entry['images'] = $images;
|
||||
}
|
||||
}
|
||||
|
||||
return $entries;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add sitemap images for Rank Math and Yoast SEO.
|
||||
*
|
||||
* @param array $images - Sitemap Images for current Post.
|
||||
* @param int $post_id - Post ID.
|
||||
* @return array
|
||||
*/
|
||||
public function add_images_to_sitemap( $images, $post_id ) {
|
||||
$block_images = $this->parse_images_from_blocks( $post_id );
|
||||
if ( ! empty( $block_images ) ) {
|
||||
$images = array_merge( $images, $block_images );
|
||||
}
|
||||
|
||||
return $images;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse block images.
|
||||
*
|
||||
* @param int $post_id - Post ID.
|
||||
* @return array
|
||||
*/
|
||||
private function parse_images_from_blocks( $post_id ) {
|
||||
$block_images = array();
|
||||
if ( $post_id > 0 ) {
|
||||
$post = get_post( $post_id );
|
||||
$content_post = $post->post_content;
|
||||
$parse_blocks = parse_blocks( $content_post );
|
||||
|
||||
if ( ! empty( $parse_blocks ) && is_array( $parse_blocks ) ) {
|
||||
foreach ( $parse_blocks as $block ) {
|
||||
if (
|
||||
'visual-portfolio/block' === $block['blockName'] ||
|
||||
'visual-portfolio/saved' === $block['blockName'] ||
|
||||
'nk/visual-portfolio' === $block['blockName']
|
||||
) {
|
||||
$options = Visual_Portfolio_Get::get_options( $block['attrs'] );
|
||||
switch ( $options['content_source'] ) {
|
||||
case 'post-based':
|
||||
if ( isset( $options['posts_source'] ) ) {
|
||||
$query_opts = Visual_Portfolio_Get::get_query_params( $options, false, $options['id'] );
|
||||
|
||||
$portfolio_query = new WP_Query( $query_opts );
|
||||
|
||||
if ( isset( $portfolio_query ) ) {
|
||||
while ( $portfolio_query->have_posts() ) {
|
||||
$portfolio_query->the_post();
|
||||
|
||||
$image_id = apply_filters( 'vpf_parse_sitemap_image_id_from_blocks', 'attachment' === get_post_type() ? get_the_ID() : get_post_thumbnail_id( get_the_ID() ), get_the_ID() );
|
||||
|
||||
$image_alt = get_post_meta( $image_id, '_wp_attachment_image_alt', true );
|
||||
|
||||
$block_images[] = array(
|
||||
'src' => wp_get_attachment_image_url( $image_id, 'full' ),
|
||||
'alt' => $image_alt,
|
||||
'title' => get_the_title( $image_id ),
|
||||
);
|
||||
}
|
||||
$portfolio_query->reset_postdata();
|
||||
|
||||
// Sometimes, when we use WPBakery Page Builder, without this reset output is wrong.
|
||||
wp_reset_postdata();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'images':
|
||||
if ( isset( $options['images'] ) ) {
|
||||
foreach ( $options['images'] as $image ) {
|
||||
$image_id = $image['id'];
|
||||
|
||||
$image_alt = $image['description'] ?? get_post_meta( $image_id, '_wp_attachment_image_alt', true ) ?? '';
|
||||
|
||||
$image_title = $image['title'] ?? get_the_title( $image_id );
|
||||
|
||||
$image_url = $image['imgUrl'] ?? wp_get_attachment_image_url( $image_id, 'full' );
|
||||
|
||||
$block_images[] = array(
|
||||
'src' => $image_url,
|
||||
'alt' => $image_alt,
|
||||
'title' => $image_title,
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'vpf_parse_sitemap_images_from_blocks', $block_images, $post_id );
|
||||
}
|
||||
}
|
||||
new Visual_Portfolio_Sitemap();
|
@ -0,0 +1,102 @@
|
||||
<?php
|
||||
/**
|
||||
* Supported themes.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Supported_Themes
|
||||
*/
|
||||
class Visual_Portfolio_Supported_Themes {
|
||||
/**
|
||||
* Visual_Portfolio_Supported_Themes constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'wp_enqueue_scripts' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Theme Compatibility Style
|
||||
*/
|
||||
public function get_theme_compatibility_style() {
|
||||
$result = false;
|
||||
|
||||
switch ( get_template() ) {
|
||||
case 'twentytwentytwo':
|
||||
$result = array(
|
||||
'name' => 'vpf-twentytwentytwo',
|
||||
'url' => 'build/assets/css/theme-twentytwentytwo',
|
||||
);
|
||||
break;
|
||||
case 'twentytwentyone':
|
||||
$result = array(
|
||||
'name' => 'vpf-twentytwentyone',
|
||||
'url' => 'build/assets/css/theme-twentytwentyone',
|
||||
);
|
||||
break;
|
||||
case 'twentytwenty':
|
||||
$result = array(
|
||||
'name' => 'vpf-twentytwenty',
|
||||
'url' => 'build/assets/css/theme-twentytwenty',
|
||||
);
|
||||
break;
|
||||
case 'twentynineteen':
|
||||
$result = array(
|
||||
'name' => 'vpf-twentynineteen',
|
||||
'url' => 'build/assets/css/theme-twentynineteen',
|
||||
);
|
||||
break;
|
||||
case 'twentyseventeen':
|
||||
$result = array(
|
||||
'name' => 'vpf-twentyseventeen',
|
||||
'url' => 'build/assets/css/theme-twentyseventeen',
|
||||
);
|
||||
break;
|
||||
case 'twentysixteen':
|
||||
$result = array(
|
||||
'name' => 'vpf-twentysixteen',
|
||||
'url' => 'build/assets/css/theme-twentysixteen',
|
||||
);
|
||||
break;
|
||||
case 'twentyfifteen':
|
||||
$result = array(
|
||||
'name' => 'vpf-twentyfifteen',
|
||||
'url' => 'assets/css/theme-twentyfifteen',
|
||||
);
|
||||
break;
|
||||
case 'airtifact':
|
||||
$result = array(
|
||||
'name' => 'vpf-airtifact',
|
||||
'url' => 'assets/css/theme-airtifact',
|
||||
);
|
||||
break;
|
||||
case 'betheme':
|
||||
$result = array(
|
||||
'name' => 'vpf-betheme',
|
||||
'url' => 'assets/css/theme-betheme',
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue styles
|
||||
*/
|
||||
public function wp_enqueue_scripts() {
|
||||
$theme_compat = $this->get_theme_compatibility_style();
|
||||
if ( $theme_compat ) {
|
||||
Visual_Portfolio_Assets::enqueue_style( $theme_compat['name'], $theme_compat['url'] );
|
||||
wp_style_add_data( $theme_compat['name'], 'rtl', 'replace' );
|
||||
wp_style_add_data( $theme_compat['name'], 'suffix', '.min' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Supported_Themes();
|
121
wp-content/plugins/visual-portfolio/classes/class-templates.php
Normal file
121
wp-content/plugins/visual-portfolio/classes/class-templates.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* Methods to work with templates.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
/**
|
||||
* Visual_Portfolio_Templates
|
||||
*/
|
||||
class Visual_Portfolio_Templates {
|
||||
/**
|
||||
* Include template
|
||||
*
|
||||
* @param string $template_name file name.
|
||||
* @param array $args args for template.
|
||||
*/
|
||||
public static function include_template( $template_name, $args = array() ) {
|
||||
// Allow 3rd party plugin filter template args from their plugin.
|
||||
$args = apply_filters( 'vpf_include_template_args', $args, $template_name );
|
||||
|
||||
if ( ! empty( $args ) && is_array( $args ) ) {
|
||||
// phpcs:ignore WordPress.PHP.DontExtract.extract_extract
|
||||
extract( $args );
|
||||
}
|
||||
|
||||
// template in theme folder.
|
||||
$template = locate_template( array( '/visual-portfolio/' . $template_name . '.php' ) );
|
||||
|
||||
// pro plugin template.
|
||||
if ( ! $template && visual_portfolio()->pro_plugin_path && file_exists( visual_portfolio()->pro_plugin_path . 'templates/' . $template_name . '.php' ) ) {
|
||||
$template = visual_portfolio()->pro_plugin_path . 'templates/' . $template_name . '.php';
|
||||
}
|
||||
|
||||
// default template.
|
||||
if ( ! $template ) {
|
||||
$template = visual_portfolio()->plugin_path . 'templates/' . $template_name . '.php';
|
||||
}
|
||||
|
||||
// Allow 3rd party plugin filter template file from their plugin.
|
||||
$template = apply_filters( 'vpf_include_template', $template, $template_name, $args );
|
||||
|
||||
if ( file_exists( $template ) ) {
|
||||
include $template;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find css template file
|
||||
*
|
||||
* @param string $template_name file name.
|
||||
* @return string
|
||||
*/
|
||||
public static function find_template_styles( $template_name ) {
|
||||
$template = '';
|
||||
$template_version = '';
|
||||
|
||||
if ( file_exists( get_stylesheet_directory() . '/visual-portfolio/' . $template_name . '.css' ) ) {
|
||||
// Child Theme (or just theme).
|
||||
$template = trailingslashit( get_stylesheet_directory_uri() ) . 'visual-portfolio/' . $template_name . '.css';
|
||||
$template_version = filemtime( get_stylesheet_directory() . '/visual-portfolio/' . $template_name . '.css' );
|
||||
} elseif ( file_exists( get_template_directory() . '/visual-portfolio/' . $template_name . '.css' ) ) {
|
||||
// Parent Theme (when parent exists).
|
||||
$template = trailingslashit( get_template_directory_uri() ) . 'visual-portfolio/' . $template_name . '.css';
|
||||
$template_version = filemtime( get_template_directory() . '/visual-portfolio/' . $template_name . '.css' );
|
||||
} elseif ( visual_portfolio()->pro_plugin_path && file_exists( visual_portfolio()->pro_plugin_path . 'templates/' . $template_name . '.css' ) ) {
|
||||
// PRO plugin folder.
|
||||
$template = visual_portfolio()->pro_plugin_url . 'templates/' . $template_name . '.css';
|
||||
$template_version = filemtime( visual_portfolio()->pro_plugin_path . 'templates/' . $template_name . '.css' );
|
||||
} elseif ( file_exists( visual_portfolio()->plugin_path . 'templates/' . $template_name . '.css' ) ) {
|
||||
// Default file in plugin folder.
|
||||
$template = visual_portfolio()->plugin_url . 'templates/' . $template_name . '.css';
|
||||
$template_version = filemtime( visual_portfolio()->plugin_path . 'templates/' . $template_name . '.css' );
|
||||
}
|
||||
|
||||
return array(
|
||||
'path' => $template,
|
||||
'version' => $template_version,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Include template style
|
||||
*
|
||||
* @param string $handle style handle name.
|
||||
* @param string $template_name file name.
|
||||
* @param array $deps dependencies array.
|
||||
* @param string|bool|null $ver version string.
|
||||
* @param string $media media string.
|
||||
*/
|
||||
public static function include_template_style( $handle, $template_name, $deps = array(), $ver = false, $media = 'all' ) {
|
||||
$template = visual_portfolio()->find_template_styles( $template_name );
|
||||
$is_min = false;
|
||||
|
||||
// maybe find minified style.
|
||||
if ( ! $template['path'] ) {
|
||||
$template = visual_portfolio()->find_template_styles( $template_name . '.min' );
|
||||
$is_min = true;
|
||||
}
|
||||
|
||||
// Get dynamic version.
|
||||
if ( ! $ver && $template['version'] ) {
|
||||
$ver = $template['version'];
|
||||
}
|
||||
if ( ! $ver ) {
|
||||
$ver = VISUAL_PORTFOLIO_VERSION;
|
||||
}
|
||||
|
||||
// Allow 3rd party plugin filter template file from their plugin.
|
||||
$template['path'] = apply_filters( 'vpf_include_template_style', $template['path'], $template_name, $deps, $ver, $media );
|
||||
|
||||
if ( $template['path'] ) {
|
||||
wp_enqueue_style( $handle, $template['path'], $deps, $ver, $media );
|
||||
wp_style_add_data( $handle, 'rtl', 'replace' );
|
||||
|
||||
if ( $is_min ) {
|
||||
wp_style_add_data( $handle, 'suffix', '.min' );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,206 @@
|
||||
<?php
|
||||
/**
|
||||
* Welcome Screen.
|
||||
*
|
||||
* @package visual-portfolio
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Visual_Portfolio_Welcome_Screen
|
||||
*/
|
||||
class Visual_Portfolio_Welcome_Screen {
|
||||
/**
|
||||
* Visual_Portfolio_Welcome_Screen constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'admin_init', array( $this, 'redirect_to_welcome_screen' ) );
|
||||
add_action( 'admin_menu', array( $this, 'welcome_screen_page' ) );
|
||||
add_action( 'admin_head', array( $this, 'welcome_screen_remove_page' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirect to Welcome page after activation.
|
||||
*/
|
||||
public function redirect_to_welcome_screen() {
|
||||
// Bail if no activation redirect.
|
||||
if ( ! get_transient( '_visual_portfolio_welcome_screen_activation_redirect' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Delete the redirect transient.
|
||||
delete_transient( '_visual_portfolio_welcome_screen_activation_redirect' );
|
||||
|
||||
// Bail if activating from network, or bulk.
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Redirect to welcome page.
|
||||
wp_safe_redirect( add_query_arg( array( 'page' => 'visual-portfolio-welcome' ), admin_url( Visual_Portfolio_Custom_Post_Type::get_menu_slug() ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add welcome screen page.
|
||||
*/
|
||||
public function welcome_screen_page() {
|
||||
add_submenu_page(
|
||||
Visual_Portfolio_Custom_Post_Type::get_menu_slug(),
|
||||
esc_html__( 'Visual Portfolio Welcome Screen', 'visual-portfolio' ),
|
||||
esc_html__( 'Visual Portfolio Welcome Screen', 'visual-portfolio' ),
|
||||
'manage_options',
|
||||
'visual-portfolio-welcome',
|
||||
array( $this, 'welcome_screen_page_content' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove welcome screen page from admin menu.
|
||||
*/
|
||||
public function welcome_screen_remove_page() {
|
||||
remove_submenu_page( Visual_Portfolio_Custom_Post_Type::get_menu_slug(), 'visual-portfolio-welcome' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add welcome screen page content.
|
||||
*/
|
||||
public function welcome_screen_page_content() {
|
||||
if ( function_exists( 'print_emoji_detection_script' ) ) {
|
||||
print_emoji_detection_script();
|
||||
}
|
||||
$go_pro_links = array(
|
||||
'head' => Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'utm_medium' => 'welcome_page',
|
||||
'utm_campaign' => 'go_pro_head',
|
||||
)
|
||||
),
|
||||
'more_features' => Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'sub_path' => '',
|
||||
'utm_medium' => 'welcome_page',
|
||||
'utm_campaign' => 'more_features',
|
||||
)
|
||||
),
|
||||
'docs' => Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'sub_path' => 'docs/getting-started',
|
||||
'utm_medium' => 'welcome_page',
|
||||
'utm_campaign' => 'docs',
|
||||
)
|
||||
),
|
||||
'foot' => Visual_Portfolio_Admin::get_plugin_site_url(
|
||||
array(
|
||||
'utm_medium' => 'settings_page',
|
||||
'utm_campaign' => 'go_pro_foot',
|
||||
)
|
||||
),
|
||||
);
|
||||
?>
|
||||
<div class="vpf-welcome-screen">
|
||||
<div class="vpf-welcome-head">
|
||||
<img class="vpf-welcome-head-background" src="<?php echo esc_url( visual_portfolio()->plugin_url . 'assets/admin/images/admin-welcome-background.jpg' ); ?>" alt="<?php echo esc_attr__( 'Visual Portfolio', 'visual-portfolio' ); ?>">
|
||||
<h2 class="vpf-welcome-head-logo">
|
||||
<i class="dashicons-visual-portfolio"></i>
|
||||
<?php echo esc_html__( 'Visual Portfolio', 'visual-portfolio' ); ?>
|
||||
</h2>
|
||||
<div class="vpf-welcome-subtitle"><?php echo esc_html__( 'Thank you for choosing Visual Portfolio - The Modern Gallery, Posts Grid and Portfolio Plugin for WordPress.', 'visual-portfolio' ); ?></div>
|
||||
|
||||
<div class="vpf-welcome-head-pro-info">
|
||||
<div><strong><?php echo esc_html__( 'You\'re using free Visual Portfolio plugin. Enjoy! 🙂', 'visual-portfolio' ); ?></strong></div>
|
||||
<div>
|
||||
<?php
|
||||
// translators: %s - pro link.
|
||||
echo sprintf( esc_html__( 'Want to get more power with Pro? Visit %s', 'visual-portfolio' ), '<a target="_blank" rel="noopener noreferrer" href="' . esc_url( $go_pro_links['head'] ) . '">visualportfolio.co/pricing</a>' );
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vpf-welcome-content">
|
||||
<h2 class="vpf-welcome-content-title"><?php echo esc_html__( 'Main Features & Solutions', 'visual-portfolio' ); ?></h2>
|
||||
|
||||
<ul class="vpf-welcome-content-features">
|
||||
<li>
|
||||
<span>🏆</span>
|
||||
<strong><?php echo esc_html__( 'Visual Gallery Builder', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'Build your portfolio and gallery blocks with no coding knowledge. Thanks to Gutenberg page builder you are able to create and customize galleries visually.', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<span>🚀</span>
|
||||
<strong><?php echo esc_html__( 'Optimized to be Fast as Native', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'Due to the modular code structure, all scripts and styles are loaded only when they are needed for the current page that displays your gallery.', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span>📱</span>
|
||||
<strong><?php echo esc_html__( 'Layouts', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'Our gallery plugin shipped with popular layouts such as Masonry and Justified (Flickr).', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<span>🎨</span>
|
||||
<strong><?php echo esc_html__( 'Visual Effects', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'Showcase your projects ang gallery images with clean and beautiful visual styles.', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span>⚙️</span>
|
||||
<strong><?php echo esc_html__( 'Easy to Customize', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'The gallery block with live preview includes a lot of design settings that are point-and-click, no coding knowledge required.', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<span>💎</span>
|
||||
<strong><?php echo esc_html__( 'Posts Query Builder', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'Display posts, portfolios, and any other post types, filter by taxonomies, author, date ranges, and much more options.', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<span>⚡</span>
|
||||
<strong><?php echo esc_html__( 'Powerful Lightbox', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'Visual Portfolio uses scripts for lightboxes that is high performance, mobile optimized and retina-ready.', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
<li>
|
||||
<span>📹</span>
|
||||
<strong><?php echo esc_html__( 'Video and 🎵 Audio Support', 'visual-portfolio' ); ?></strong>
|
||||
<p><?php echo esc_html__( 'Present not only photos, but also audios and videos within a single gallery.', 'visual-portfolio' ); ?></p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="vpf-welcome-content-buttons">
|
||||
<a target="_blank" rel="noopener noreferrer" href="<?php echo esc_url( $go_pro_links['more_features'] ); ?>"><?php echo esc_html__( 'More Features', 'visual-portfolio' ); ?></a>
|
||||
<a target="_blank" rel="noopener noreferrer" href="<?php echo esc_url( $go_pro_links['docs'] ); ?>"><?php echo esc_html__( 'Documentation', 'visual-portfolio' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="vpf-welcome-foot-pro-info">
|
||||
<h2>
|
||||
<?php echo esc_html__( 'Upgrade to Visual Portfolio Pro', 'visual-portfolio' ); ?>
|
||||
<br>
|
||||
<?php echo esc_html__( 'and Get More Power!', 'visual-portfolio' ); ?>
|
||||
</h2>
|
||||
<ul>
|
||||
<li><?php echo esc_html__( 'Social Feeds', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'Stylish Effects', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'Watermarks Protection', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'Age Gate Protection', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'Instagram-like Image Filters', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'Advanced Query Settings', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'Popup for Posts and Pages', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'Popup Deep Linking', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'White Label', 'visual-portfolio' ); ?></li>
|
||||
<li><?php echo esc_html__( 'And much more...', 'visual-portfolio' ); ?></li>
|
||||
</ul>
|
||||
<a target="_blank" rel="noopener noreferrer" href="<?php echo esc_url( $go_pro_links['foot'] ); ?>"><?php echo esc_html__( 'Upgrade to PRO Now', 'visual-portfolio' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
new Visual_Portfolio_Welcome_Screen();
|
Reference in New Issue
Block a user