This commit is contained in:
2026-04-26 23:47:49 +02:00
parent 1b95f03d1e
commit b073e009d8
5288 changed files with 1112699 additions and 55536 deletions

View File

@@ -0,0 +1,46 @@
<?php
/**
* Customizer Builder
* Action Button Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Actionbutton_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'actionbutton';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<button class="sb-control-action-button sb-btn sby-yt-fs sb-btn-grey">
<div v-if="control.buttonIcon" v-html="svgIcons[control.buttonIcon]"></div>
<span class="sb-small-p sb-bold sb-dark-text">{{control.label}}</span>
</button>
<?php
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Customizer Builder
* CheckBox Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Checkbox_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'checkbox';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-checkbox-ctn sby-yt-fs" @click.prevent.default="(control.custom != undefined && control.custom == 'feedtype') ? changeCheckboxSectionValue('type', control.value, 'feedFlyPreview') : changeSwitcherSettingValue(control.id, control.options.enabled, control.options.disabled, control.ajaxAction != undefined ? control.ajaxAction : false)">
<div class="sb-control-checkbox" :data-active="(control.custom != undefined && control.custom == 'feedtype') ? <?php echo $controlEditingTypeModel; ?>['type'].includes(control.value) : <?php echo $controlEditingTypeModel; ?>[control.id] == control.options.enabled"></div>
<div class="sb-control-label">{{control.label}}</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Customizer Builder
* CheckBox List Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Checkboxlist_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'checkboxlist';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-checkbox-ctn sby-yt-fs" v-for="option in control.options" @click.prevent.default="changeCheckboxListValue(control.id, option.value)">
<div class="sb-control-checkbox" :data-active="<?php echo $controlEditingTypeModel; ?>[control.id].includes(option.value)"></div>
<div class="sb-control-label sb-small-p sb-dark-text" v-html="option.label"></div>
</div>
<?php
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* Customizer Builder
* CheckBox Section Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Checkboxsection_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'checkboxsection';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*
* @return HTML
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-checkboxsection-header" v-if="control.header">
<div class="sb-control-checkboxsection-name">
<div v-html="svgIcons['preview']"></div>
<strong class="">{{genericText.name}}</strong>
</div>
<strong>{{genericText.edit}}</strong>
</div>
<div class="sb-control-checkbox-ctn sby-yt-fs" @click.prevent.default="switchNestedSection(control.section.id, control.section)">
<div class="sb-control-checkbox-hover sb-tr-2"></div>
<div class="sb-control-checkbox" @click.stop.prevent.default="changeCheckboxSectionValue(control.id, control.value)" :data-active="checkboxSectionValueExists(control.id, control.value)"></div>
<div class="sby-yt-fs" :data-active="checkboxSectionValueExists(control.id, control.value)">
<strong class="sb-control-label">{{control.label}}</strong>
</div>
<div class="sb-control-checkboxsection-btn"></div>
</div>
<?php
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* Customizer Builder
* Color Override Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Coloroverride_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'coloroverride';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-input-ctn sby-yt-fs sb-control-coloroverride-ctn">
<div class="sb-control-coloroverride-content">
<div class="sb-control-coloroverride-txt" v-html="<?php echo $controlEditingTypeModel; ?>[control.id]"></div>
<div class="sb-control-coloroverride-swatch" :style="'background:'+<?php echo $controlEditingTypeModel; ?>[control.id]"></div>
</div>
<div class="sb-control-colorpicker-btn" @click.prevent.default="resetColorOverride(control.id)">{{genericText.reset}}</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,63 @@
<?php
/**
* Customizer Builder
* Color Picker Field Control
*
* @since 4.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Colorpicker_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 4.0
* @access public
*
* @return string
*/
public function get_type() {
return 'colorpicker';
}
/**
* Output Control
*
*
* @since 4.0
* @access public
*
* @return HTML
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-input-ctn sby-yt-fs sb-control-colorpicker-ctn" :data-picker-style="control.pickerType ? control.pickerType : 'default'" @click.stop="showColorPickerPospup(control.id)" v-on-clickaway="hideColorPickerPopup()">
<!--<sbi-colorpicker :color="<?php echo $controlEditingTypeModel; ?>[control.id]" v-on:change="changeSettingValue(control.id,...arguments)" :control-id="control.id"></sbi-colorpicker>-->
<input class="sb-control-input" placeholder="Select" type="text" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]">
<div class="sb-control-colorpicker-swatch" :style="'background:'+<?php echo $controlEditingTypeModel; ?>[control.id]+';'"></div>
<div class="sb-control-colorpicker-popup" v-show="customizerScreens.activeColorPicker == control.id">
<sketch-picker
@input="updateColorValue(control.id)"
v-model="<?php echo $controlEditingTypeModel; ?>[control.id]"
:value="<?php echo $controlEditingTypeModel; ?>[control.id]"
:preset-colors="['#fff','#000','#e92b2b','#ffc104','#31e92b','#2b4ee9','#a72be9','#e92b82']"
></sketch-picker>
<button class="sb-control-action-button sb-colorpicker-reset-btn sb-btn sby-yt-fs sb-btn-grey" @click.prevent.default="resetColor(control.id)">
<div v-html="svgIcons['update']"></div>
<span>{{genericText.reset}}</span>
</button>
</div>
<div class="sb-control-colorpicker-btn" v-if="control.pickerType == 'reset'">{{genericText.reset}}</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,130 @@
<?php
/**
* Customizer Builder Control Base
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
abstract class SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return '';
}
/**
* Get control info.
*
* Getting the Control information []
*
* @since 2.0
* @access public
*
* @return array
*/
public function get_info() {
return array(
'id' => '',
'type' => '',
'modelname' => '',
'layout' => 'full',
'reverse' => 'false',
'default' => '',
'seperator' => 'none',
'heading' => '',
'description' => '',
'tooltip' => '',
);
}
/**
* Control Output
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {}
/**
* Getting Editing Control Type
*
*
* @since 1.0.0
* @access public
*
* @return String
*/
public function get_control_edit_type( $editingType ) {
switch ( $editingType ) {
case 'settings':
return 'customizerFeedData.settings';
break;
}
}
/**
* Get Control HTML.
*
*
* @since 2.0
* @access public
*
* @return HTML
*/
public function print_control_wrapper( $editingType ) {
$control_type = $this->get_type();
$controlEditingTypeModel = $this->get_control_edit_type( $editingType );
?>
<div class="sb-control-elem-ctn sby-yt-fs" v-if="control.type == '<?php echo $control_type; ?>'"
v-show="isControlShown(control)"
:data-child="control.child ? 'true' : false"
:data-separator="control.separator != undefined ? control.separator : 'none'"
:data-type="control.type" :data-layout="control.layout == undefined ? 'block' : 'half'"
:data-reverse="control.reverse != undefined ? 'true' : 'false'" :data-stacked="control.stacked ? 'true' : 'false'"
:data-heading="control.strongHeading != undefined && control.strongHeading != 'true' ? '' : 'strong'"
:data-disabled="control.disabledInput != undefined ? isControlShown(control) : false"
:data-switcher-top="control.switcherTop != undefined ? 'true' : false"
>
<div class="sb-control-elem-overlay"
v-show="control.condition != undefined || control.checkExtension != undefined || control.checkExtensionDimmed != undefined ? !checkControlCondition(control.condition, control.checkExtension, control.checkExtensionDimmed) : false"
@click.prevent.default="control.checkExtensionPopup != undefined && !checkExtensionActive(control.checkExtensionPopup) ? viewsActive.extensionsPopupElement = control.checkExtensionPopup : false"
:class="control.checkExtensionPopup != undefined && !checkExtensionActive(control.checkExtensionPopup) ? 'sb-cursor-pointer' : ''"
>
</div>
<div class="sb-control-elem-label" v-if="(control.heading == undefined && control.description == undefined) ? false : true && control.type != 'customview'">
<div class="sb-control-elem-label-title sby-yt-fs">
<div v-if="control.icon != undefined" class="sb-control-elem-icon" v-html="svgIcons[control.icon]"></div>
<div class="sb-control-elem-heading sb-small-p sb-dark-text" :data-underline="control.underline" :class="control.enableViewAction != undefined && control.enableViewAction != false ? 'sb-cursor-pointer' : ''" v-html="control.heading" @click.prevent.default="control.enableViewAction != undefined && control.enableViewAction != false ? switchNestedSection(control.enableViewAction, null ) : false"></div>
<div class="sb-control-elem-tltp" v-if="control.tooltip != undefined" @mouseover.prevent.default="toggleElementTooltip(control.tooltip, 'show', control.tooltipAlign ? control.tooltipAlign : 'center' )" @mouseleave.prevent.default="toggleElementTooltip('', 'hide')">
<div class="sb-control-elem-tltp-icon" v-html="svgIcons['info']"></div>
</div>
</div>
<div class="sb-control-elem-description" v-if="control.descriptionPosition != 'bottom'" v-html="control.description"></div>
</div>
<div class="sb-control-elem-output">
<?php $this->get_control_output( $controlEditingTypeModel ); ?>
<div class="sb-control-elem-description" v-if="control.descriptionPosition != undefined && control.descriptionPosition == 'bottom'" v-html="control.description"></div>
</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,234 @@
<?php
/**
* Customizer Builder
* Custom View
* This control will used for custom HTMlL controls like (source, feed type...)
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Customview_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'customview';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
$this->get_control_sources_output( $controlEditingTypeModel );
$this->get_control_shoppable_disabled_output( $controlEditingTypeModel );
$this->get_control_shoppable_enabled_output( $controlEditingTypeModel );
$this->get_control_shoppable_selected_post_output( $controlEditingTypeModel );
$this->get_control_moderation_mode_output( $controlEditingTypeModel );
}
/**
* Shoppable Feed Disabled Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_shoppable_disabled_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-shoppbale-disabled-ctn sb-control-imginfo-ctn" v-if="control.viewId == 'shoppabledisabled'">
<div class="sb-control-imginfo-elem sby-yt-fs">
<div class="sb-control-imginfo-icon sby-yt-fs" v-html="svgIcons['shoppableDisabled']"></div>
<div class="sb-control-imginfo-text sby-yt-fs" data-textalign="left">
<strong class="sb-bold sb-dark-text " v-html="customizeScreensText.shoppableFeedScreen.heading1"></strong>
<span v-html="customizeScreensText.shoppableFeedScreen.description1"></span>
</div>
</div>
</div>
<?php
}
/**
* Shoppable Feed Enabled Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_shoppable_enabled_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-shoppbale-enbaled-ctn sb-control-imginfo-ctn" v-if="control.viewId == 'shoppableenabled'">
<div class="sb-control-imginfo-elem sby-yt-fs">
<div class="sb-control-imginfo-icon sby-yt-fs" v-html="svgIcons['shoppableEnabled']"></div>
<div class="sb-control-imginfo-text sby-yt-fs" data-textalign="center">
<strong class="sb-bold sb-dark-text " v-html="customizeScreensText.shoppableFeedScreen.heading2"></strong>
</div>
</div>
</div>
<?php
}
/**
* Shoppable Feed Selected Post
*
*
* @since 2.0
* @access public
*/
public function get_control_shoppable_selected_post_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-shoppbale-selectedpost-ctn" v-if="control.viewId == 'shoppableselectedpost' && shoppableFeed.postId != null">
<strong v-html="genericText.selectedPost"></strong>
<div class="sb-control-selectedpost-info sby-yt-fs">
<img :src="shoppableFeed.postMedia" alt="Selected Shoppable">
<span v-html="shoppableFeed.postCaption"></span>
</div>
<div class="sb-control-selectedpost-input sby-yt-fs">
<span class="sby-yt-fs" v-html="genericText.productLink"></span>
<input type="text" class="sb-control-input sby-yt-fs" v-model="shoppableFeed.postShoppableUrl" :placeholder="genericText.enterProductLink">
</div>
<div class="sb-control-selectedpost-btns sby-yt-fs">
<button class="sb-shoppable-selectedpost-btn sbi-btn-grey" @click.prevent.default="addPostShoppableFeed()">
<div v-html="svgIcons['checkmark']"></div>
<span v-html="genericText.add"></span>
</button>
<button class="sb-shoppable-selectedpost-btn sbi-btn-grey" @click.prevent.default="cancelPostShoppableFeed()">
<span v-html="genericText.cancel"></span>
</button>
</div>
</div>
<?php
}
/**
* Sources Output Control
*
*
* @since 2.0
* @access public
*
* @return HTML
*/
public function get_control_sources_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-feedtype-ctn" v-if="control.viewId == 'sources'">
<div class="sb-control-feedtype-item sby-yt-fs" v-for="(feedType, feedTypeID) in selectSourceScreen.multipleTypes" v-if="checkMultipleFeedTypeActiveCustomizer(feedTypeID)">
<div class="sb-control-elem-label-title sby-yt-fs">
<div class="sb-control-elem-heading sb-small-p sb-dark-text" v-html="feedType.heading"></div>
<div class="sb-control-elem-tltp" @mouseover.prevent.default="toggleElementTooltip(feedType.description, 'show', 'center' )" @mouseleave.prevent.default="toggleElementTooltip('', 'hide')">
<div class="sb-control-elem-tltp-icon" v-html="svgIcons['info']"></div>
</div>
</div>
<div class="sb-control-feedtype-list sby-yt-fs">
<div class="sb-control-feedtype-list-item" v-for="selectedSource in returnSelectedSourcesByTypeCustomizer(feedTypeID)">
<div class="sb-control-feedtype-list-item-icon" v-html="feedTypeID == 'hashtag' ? svgIcons['hashtag'] : svgIcons['user']"></div>
<span v-html="feedTypeID == 'hashtag' ? selectedSource : selectedSource.username"></span>
</div>
</div>
</div>
<button class="sb-control-action-button sb-btn sb-btn-grey sby-yt-fs" @click.prevent.default="openFeedTypesPopupCustomizer()">
<div v-html="svgIcons['edit']"></div>
<span>{{genericText.editSources}}</span>
</button>
</div>
<?php
}
/**
* Moderation Mode Ouptut
*
*
* @since 2.0
* @access public
*/
public function get_control_moderation_mode_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-moderationmode-ctn" v-if="control.viewId == 'moderationmode'">
<button class="sb-control-moderationmode-btn sb-btn sb-btn-right-icon sb-btn-grey sby-yt-fs" v-if="!viewsActive.moderationMode" @click.prevent.default="openModerationMode()">
<div class="sb-btn-right-txt">
<div v-html="svgIcons['eye1']"></div>
<span>{{genericText.moderateFeed}}</span>
</div>
<div class="sb-btn-right-chevron"></div>
</button>
<div class="sb-control-moderationmode-elements sby-yt-fs" v-if="viewsActive.moderationMode">
<div class="sb-control-switcher-ctn" :data-active="<?php echo $controlEditingTypeModel; ?>[control.switcher.id] === control.switcher.options.enabled" @click.prevent.default="changeSwitcherSettingValue(control.switcher.id, control.switcher.options.enabled, control.switcher.options.disabled, control.switcher.ajaxAction ? control.switcher.ajaxAction : false)">
<div class="sb-control-switcher sb-tr-2"></div>
<div class="sb-control-label" v-if="control.switcher.label" :data-title="control.switcher.labelStrong ? 'true' : false">{{control.switcher.label}}</div>
</div>
<div v-if="<?php echo $controlEditingTypeModel; ?>[control.switcher.id] == control.switcher.options.enabled">
<div class="sb-control-moderatiomode-selement sby-yt-fs sb-control-before-brd">
<div class="sb-control-elem-label-title sby-yt-fs">
<div class="sb-control-elem-heading sb-small-p sb-dark-text">{{genericText.moderationMode}}</div>
</div>
<div class="sb-control-toggle-set-ctn sb-control-toggle-set-desc-ctn sby-yt-fs">
<div class="sb-control-toggle-elm sby-yt-fs sb-tr-2" v-for="(moderationItem, moderationId) in control.moderationTypes " @click.prevent.default="switchModerationListType(moderationId)" :data-active="moderationSettings.list_type_selected == moderationId">
<div class="sb-control-toggle-deco sb-tr-1"></div>
<div class="sb-control-content">
<div class="sb-control-label">{{moderationItem.label}}</div>
<div class="sb-control-toggle-description">{{moderationItem.description}}</div>
</div>
</div>
</div>
</div>
<div class="sb-control-moderatiomode-selement sby-yt-fs sb-control-before-brd">
<div class="sb-control-elem-label-title sby-yt-fs">
<div class="sb-control-elem-heading sb-small-p sb-dark-text">{{genericText.moderationModeEnterPostId}}</div>
</div>
<div class="sby-yt-fs">
<textarea class="sb-control-input-textrea sby-yt-fs" v-model="customBlockModerationlistTemp" :placeholder="genericText.moderationModeTextareaPlaceholder"></textarea>
</div>
</div>
<div class="sb-control-moderationmode-action-btns sb-control-before-brd sby-yt-fs">
<button class="sb-btn sb-btn-blue sby-yt-fs" @click.prevent.default="saveModerationSettings()">
<div class="sbi-fb-icon-success"></div>
{{genericText.moderateFeedSaveExit}}
</button>
<button class="sb-btn sb-btn-grey sby-yt-fs" @click.prevent.default="activateView('moderationMode'); moderationShoppableMode = false;">
<div class="sbi-fb-icon-cancel"></div>
{{genericText.cancel}}
</button>
</div>
</div>
</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Customizer Builder
* Date Picker Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Datepicker_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'datepicker';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-input-ctn sby-yt-fs">
<input type="date" class="sb-control-input sby-yt-fs" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]" @change.prevent.default="changeSettingValue(control.id, false,false, control.ajaxAction ? control.ajaxAction : false)" :placeholder="control.placeholder ? control.placeholder : ''">
</div>
<?php
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* Customizer Builder
* Heading Text Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Heading_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'heading';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Customizer Builder
* Hidden Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Hidden_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'hidden';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-input-ctn sby-yt-fs">
<input type="hidden" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]">
</div>
<?php
}
}

View File

@@ -0,0 +1,55 @@
<?php
/**
* Customizer Builder
* Image Chooser Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Imagechooser_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'imagechooser';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-imagechooser-ctn sby-yt-fs">
<div class="sby-yt-fs">
<input type="text" class="sb-control-imagechooser-input sby-yt-fs" :class="checkNotEmpty(<?php echo $controlEditingTypeModel; ?>[control.id]) ? 'sb-control-imagechooser-padding' : ''" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]" :placeholder="control.placeholder ? control.placeholder : <?php echo $controlEditingTypeModel; ?>[control.id]" disabled>
<div class="sb-control-imagechooser-clear sbi-fb-tltp-parent" v-if="checkNotEmpty(<?php echo $controlEditingTypeModel; ?>[control.id])">
<div class="sb-control-imagechooser-clear-icon" @click.prevent.default="changeSettingValue(control.id, '')"></div>
<div class="sbi-fb-tltp-elem"><span>{{genericText.clear.replace(/ /g,"&nbsp;")}}</span></div>
</div>
</div>
<div class="sb-control-imagechooser-btn" @click.prevent.default="imageChooser( control.id )">
<div v-html="svgIcons['imageChooser']"></div>
<span v-html="checkNotEmpty(<?php echo $controlEditingTypeModel ?>[control.id]) ? genericText.change : genericText.addImage.replace(/ /g,'&nbsp;')"></span>
</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Customizer Builder
* Number Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Number_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'number';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-input-ctn sby-yt-fs" :data-contains-suffix="control.fieldSuffix !== undefined ? 'true' : 'false'">
<div class="sb-control-input-info" :class="control.fieldPrefixAction != undefined ? 'sb-cursor-pointer' : ''" v-if="control.fieldPrefix" @click.prevent.default="control.fieldPrefixAction != undefined ? fieldCustomClickAction(control.fieldPrefixAction) : false">{{control.fieldPrefix.replace(/ /g,"&nbsp;")}}</div>
<input type="number" class="sb-control-input sby-yt-fs" :placeholder="control.placeholder ? control.placeholder : ''" :step="control.step ? control.step : 1" :max="control.max ? control.max : 1000" :min="control.min ? control.min : 0" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]" @change.prevent.default="changeSettingValue(control.id,false,false, control.ajaxAction ? control.ajaxAction : false)">
<div class="sb-control-input-info" :class="control.fieldSuffixAction != undefined ? 'sb-cursor-pointer' : ''" v-if="control.fieldSuffix" @click.prevent.default="control.fieldSuffixAction != undefined ? fieldCustomClickAction(control.fieldSuffixAction) : false">{{control.fieldSuffix.replace(/ /g,"&nbsp;")}}</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Customizer Builder
* Select Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Select_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'select';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-input-ctn sby-yt-fs">
<select class="sb-control-input sby-yt-fs" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]" @change.prevent.default="changeSettingValue(control.id,false,false, control.ajaxAction ? control.ajaxAction : false)">
<option v-for="(opName, opValue) in control.options" :value="opValue">{{opName}}</option>
</select>
</div>
<?php
}
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Customizer Builder
* Separator Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Separator_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'separator';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-elem-separator sby-yt-fs" :style="'margin-top:'+ (control.top ? control.top : 0) +'px;margin-bottom:'+ (control.bottom ? control.bottom : 0) +'px;'"></div>
<?php
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Customizer Builder
* Switcher Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Switcher_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'switcher';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-switcher-ctn" :data-active="<?php echo $controlEditingTypeModel; ?>[control.id] == control.options.enabled" @click.prevent.default="changeSwitcherSettingValue(control.id, control.options.enabled, control.options.disabled, control.ajaxAction ? control.ajaxAction : false)">
<div class="sb-control-switcher sb-tr-2"></div>
<div class="sb-control-label" v-if="control.label" :data-title="control.labelStrong ? 'true' : false">{{control.label}}</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Customizer Builder
* Text Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Text_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'text';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-input-ctn sby-yt-fs">
<div class="sb-control-input-info" v-if="control.fieldPrefix">{{control.fieldPrefix.replace(/ /g,"&nbsp;")}}</div>
<input type="text" class="sb-control-input sby-yt-fs" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]" @change.prevent.default="changeSettingValue(control.id, false,false, control.ajaxAction ? control.ajaxAction : false)" :placeholder="control.placeholder ? control.placeholder : ''">
<div class="sb-control-input-info" v-if="control.fieldSuffix">{{control.fieldSuffix.replace(/ /g,"&nbsp;")}}</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* Customizer Builder
* TextArea Field Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Textarea_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'textarea';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-textarea-ctn sby-yt-fs">
<textarea class="sb-control-input-textrea sby-yt-fs" v-model="<?php echo $controlEditingTypeModel; ?>[control.id]" :placeholder="control.placeholder ? control.placeholder : ''" @focusout.prevent.default="changeSettingValue(false,false,false, control.ajaxAction ? control.ajaxAction : false)"></textarea>
</div>
<?php
}
}

View File

@@ -0,0 +1,49 @@
<?php
/**
* Customizer Builder
* Toggle Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Toggle_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'toggle';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-toggle-ctn sby-yt-fs">
<div class="sb-control-toggle-elm sby-yt-fs sb-tr-2" data-active="true">
<div class="sb-control-toggle-deco sb-tr-1"></div>
<div class="sb-control-toggle-icon" v-if="control.toggle.icon" v-html="svgIcons[control.toggle.icon]"></div>
<div class="sb-control-label">{{control.toggle.label}}</div>
</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,48 @@
<?php
/**
* Customizer Builder
* Toggle Buttons
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Togglebutton_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'togglebutton';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-togglebutton-ctn sby-yt-fs">
<div class="sb-control-togglebutton-elm sby-yt-fs sb-tr-1" v-for="toggle in control.options" :data-active="<?php echo $controlEditingTypeModel; ?>[control.id] == toggle.value" v-show="toggle.condition != undefined ? checkControlCondition(toggle.condition) : true" @click.prevent.default="changeSettingValue(control.id,toggle.value, true)" >
{{toggle.label}}
</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,50 @@
<?php
/**
* Customizer Builder
* Toggle Set Control
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Controls;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Toggleset_Control extends SB_Controls_Base {
/**
* Get control type.
*
* Getting the Control Type
*
* @since 2.0
* @access public
*
* @return string
*/
public function get_type() {
return 'toggleset';
}
/**
* Output Control
*
*
* @since 2.0
* @access public
*/
public function get_control_output( $controlEditingTypeModel ) {
?>
<div class="sb-control-toggle-set-ctn sby-yt-fs">
<div class="sb-control-toggle-elm sby-yt-fs sb-tr-2" v-for="toggle in control.options" :data-active="<?php echo $controlEditingTypeModel; ?>[control.id] == toggle.value" @click.prevent.default="changeSettingValue(control.id,toggle.value, toggle.checkExtension != undefined ? checkExtensionActive(toggle.checkExtension) : true, control.ajaxAction != undefined ? control.ajaxAction : false)" v-show="toggle.condition != undefined ? checkControlCondition(toggle.condition) : true" :data-disabled="toggle.checkExtension != undefined ? !checkExtensionActive(toggle.checkExtension) : false">
<div class="sb-control-toggle-extension-cover" v-show="toggle.checkExtension != undefined && !checkExtensionActive(toggle.checkExtension)"></div>
<div class="sb-control-toggle-deco sb-tr-1"></div>
<div class="sb-control-toggle-icon" v-if="toggle.icon" v-html="svgIcons[toggle.icon]"></div>
<div class="sb-control-label">{{toggle.label}}</div>
</div>
</div>
<?php
}
}

View File

@@ -0,0 +1,935 @@
<?php
/**
* YouTube Feeds Database
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder;
class SBY_Db {
const RESULTS_PER_PAGE = 20;
const RESULTS_PER_CRON_UPDATE = 14;
/**
* Query the sbi_sources table
*
* @param array $args
*
* @return array|bool
*
* @since 2.0
*/
public static function source_query( $args = array() ) {
global $wpdb;
$sources_table_name = $wpdb->prefix . 'sbi_sources';
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$page = 0;
if ( isset( $args['page'] ) ) {
$page = (int) $args['page'] - 1;
unset( $args['page'] );
}
$offset = max( 0, $page * self::RESULTS_PER_PAGE );
if ( empty( $args ) ) {
$limit = (int) self::RESULTS_PER_PAGE;
$sql = "SELECT s.id, s.account_id, s.account_type, s.privilege, s.access_token, s.username, s.info, s.error, s.expires, count(f.id) as used_in
FROM $sources_table_name s
LEFT JOIN $feeds_table_name f ON f.settings LIKE CONCAT('%', s.account_id, '%')
GROUP BY s.id, s.account_id
LIMIT $limit
OFFSET $offset;
";
$results = $wpdb->get_results( $sql, ARRAY_A );
if ( empty( $results ) ) {
return array();
}
$i = 0;
foreach ( $results as $result ) {
if ( (int) $result['used_in'] > 0 ) {
$account_id = sanitize_key( $result['account_id'] );
$sql = "SELECT *
FROM $feeds_table_name
WHERE settings LIKE CONCAT('%', $account_id, '%')
GROUP BY id
LIMIT 100;
";
$results[ $i ]['instances'] = $wpdb->get_results( $sql, ARRAY_A );
}
$i++;
}
return $results;
}
if ( ! empty( $args['expiring'] ) ) {
$sql = $wpdb->prepare(
"
SELECT * FROM $sources_table_name
WHERE account_type = 'personal'
AND expires < %s
AND last_updated < %s
ORDER BY expires ASC
LIMIT 5;
",
gmdate( 'Y-m-d H:i:s', time() + SBI_REFRESH_THRESHOLD_OFFSET ),
gmdate( 'Y-m-d H:i:s', time() - SBI_MINIMUM_INTERVAL )
);
return $wpdb->get_results( $sql, ARRAY_A );
}
if ( ! empty( $args['username'] ) ) {
return $wpdb->get_results(
$wpdb->prepare(
"
SELECT * FROM $sources_table_name
WHERE username = %s;
",
$args['username']
),
ARRAY_A
);
}
if ( isset( $args['access_token'] ) && ! isset( $args['id'] ) ) {
return $wpdb->get_results(
$wpdb->prepare(
"
SELECT * FROM $sources_table_name
WHERE access_token = %s;
",
$args['access_token']
),
ARRAY_A
);
}
if ( ! isset( $args['id'] ) ) {
return false;
}
if ( is_array( $args['id'] ) ) {
$id_array = array();
foreach ( $args['id'] as $id ) {
$id_array[] = esc_sql( $id );
}
} elseif ( strpos( $args['id'], ',' ) !== false ) {
$id_array = explode( ',', str_replace( ' ', '', esc_sql( $args['id'] ) ) );
}
if ( isset( $id_array ) ) {
$id_string = "'" . implode( "' , '", array_map( 'esc_sql', $id_array ) ) . "'";
}
if ( ! empty( $args['all_business'] ) ) {
$id_string = empty( $id_string ) ? '0' : $id_string;
$sql = "
SELECT * FROM $sources_table_name
WHERE account_id IN ($id_string)
OR account_type = 'business'
";
return $wpdb->get_results( $sql, ARRAY_A );
}
$privilege = '';
if ( ! empty( $privilege ) ) {
if ( isset( $id_string ) ) {
$sql = $wpdb->prepare(
"
SELECT * FROM $sources_table_name
WHERE account_id IN ($id_string)
AND privilege = %s;
",
$privilege
);
} else {
$sql = $wpdb->prepare(
"
SELECT * FROM $sources_table_name
WHERE account_id = %s
AND privilege = %s;
",
$args['id'],
$privilege
);
}
} else {
if ( isset( $id_string ) ) {
$sql = "
SELECT * FROM $sources_table_name
WHERE account_id IN ($id_string);
";
} else {
$sql = $wpdb->prepare(
"
SELECT * FROM $sources_table_name
WHERE account_id = %s;
",
$args['id']
);
}
}
return $wpdb->get_results( $sql, ARRAY_A );
}
/**
* Update a source (connected account)
*
* @param array $to_update
* @param array $where_data
*
* @return false|int
*
* @since 2.0
*/
public static function source_update( $to_update, $where_data ) {
global $wpdb;
$sources_table_name = $wpdb->prefix . 'sbi_sources';
$encryption = new \SB_YouTube_Data_Encryption();
$data = array();
$where = array();
$format = array();
$where_format = array();
if ( isset( $to_update['type'] ) ) {
$data['account_type'] = $to_update['type'];
$format[] = '%s';
}
if ( isset( $to_update['privilege'] ) ) {
$data['privilege'] = $to_update['privilege'];
$format[] = '%s';
}
if ( isset( $to_update['id'] ) ) {
$where['account_id'] = $to_update['id'];
$where_format[] = '%s';
}
if ( isset( $to_update['access_token'] ) ) {
$data['access_token'] = $encryption->maybe_encrypt( $to_update['access_token'] );
$format[] = '%s';
}
if ( isset( $to_update['username'] ) ) {
$data['username'] = $to_update['username'];
$format[] = '%s';
}
if ( isset( $to_update['info'] ) ) {
$data['info'] = $encryption->maybe_encrypt( $to_update['info'] );
$format[] = '%s';
}
if ( isset( $to_update['error'] ) ) {
$data['error'] = $to_update['error'];
$format[] = '%s';
}
if ( isset( $to_update['expires'] ) ) {
$data['expires'] = $to_update['expires'];
$format[] = '%s';
}
if ( isset( $to_update['last_updated'] ) ) {
$data['last_updated'] = $to_update['last_updated'];
$format[] = '%s';
}
if ( isset( $to_update['author'] ) ) {
$data['author'] = $to_update['author'];
$format[] = '%d';
}
if ( isset( $where_data['type'] ) ) {
$where['account_type'] = $where_data['type'];
$where_format[] = '%s';
}
if ( isset( $where_data['privilege'] ) ) {
$where['privilege'] = $where_data['privilege'];
$where_format[] = '%s';
}
if ( isset( $where_data['author'] ) ) {
$where['author'] = $where_data['author'];
$where_format[] = '%d';
}
if ( isset( $where_data['id'] ) ) {
$where['account_id'] = $where_data['id'];
$where_format[] = '%s';
}
if ( isset( $where_data['record_id'] ) ) {
$where['id'] = $where_data['record_id'];
$where_format[] = '%d';
}
$affected = $wpdb->update( $sources_table_name, $data, $where, $format, $where_format );
return $affected;
}
/**
* New source (connected account) data is added to the
* sbi_sources table and the new insert ID is returned
*
* @param array $to_insert
*
* @return false|int
*
* @since 2.0
*/
public static function source_insert( $to_insert ) {
global $wpdb;
$sources_table_name = $wpdb->prefix . 'sbi_sources';
$encryption = new \SB_Instagram_Data_Encryption();
$data = array();
$format = array();
if ( isset( $to_insert['id'] ) ) {
$data['account_id'] = $to_insert['id'];
$format[] = '%s';
}
if ( isset( $to_insert['type'] ) ) {
$data['account_type'] = $to_insert['type'];
$format[] = '%s';
} else {
$data['account_type'] = 'page';
$format[] = '%s';
}
if ( isset( $to_insert['privilege'] ) ) {
$data['privilege'] = $to_insert['privilege'];
$format[] = '%s';
}
if ( isset( $to_insert['access_token'] ) ) {
$data['access_token'] = $encryption->maybe_encrypt( $to_insert['access_token'] );
$format[] = '%s';
}
if ( isset( $to_insert['username'] ) ) {
$data['username'] = $to_insert['username'];
$format[] = '%s';
}
if ( isset( $to_insert['info'] ) ) {
$data['info'] = $encryption->maybe_encrypt( $to_insert['info'] );
$format[] = '%s';
}
if ( isset( $to_insert['error'] ) ) {
$data['error'] = $to_insert['error'];
$format[] = '%s';
}
if ( isset( $to_insert['expires'] ) ) {
$data['expires'] = $to_insert['expires'];
$format[] = '%s';
} else {
$data['expires'] = '2100-12-30 00:00:00';
$format[] = '%s';
}
$data['last_updated'] = gmdate( 'Y-m-d H:i:s' );
$format[] = '%s';
if ( isset( $to_insert['author'] ) ) {
$data['author'] = $to_insert['author'];
$format[] = '%d';
} else {
$data['author'] = get_current_user_id();
$format[] = '%d';
}
return $wpdb->insert( $sources_table_name, $data, $format );
}
/**
* Query the to get feeds list for Elementor
*
* @return array
*
* @since 2.0
*/
public static function elementor_feeds_query() {
global $wpdb;
$feeds_elementor = array();
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$feeds_list = $wpdb->get_results(
"
SELECT id, feed_name FROM $feeds_table_name;
"
);
if ( ! empty( $feeds_list ) ) {
foreach ( $feeds_list as $feed ) {
$feeds_elementor[ $feed->id ] = $feed->feed_name;
}
}
return $feeds_elementor;
}
/**
* Count the sby_feeds table
*
* @return int
*
* @since 2.0
*/
public static function feeds_count() {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$results = $wpdb->get_results(
"SELECT COUNT(*) AS num_entries FROM $feeds_table_name",
ARRAY_A
);
return isset( $results[0]['num_entries'] ) ? (int) $results[0]['num_entries'] : 0;
}
/**
* Query the sby_feeds table
*
* @param array $args
*
* @return array|bool
*
* @since 2.0
*/
public static function feeds_query( $args = array() ) {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$page = 0;
if ( isset( $args['page'] ) ) {
$page = (int) $args['page'] - 1;
unset( $args['page'] );
}
$offset = max( 0, $page * self::RESULTS_PER_PAGE );
if ( isset( $args['id'] ) ) {
$sql = $wpdb->prepare(
"
SELECT * FROM $feeds_table_name
WHERE id = %d;
",
$args['id']
);
} else {
$sql = $wpdb->prepare(
"
SELECT * FROM $feeds_table_name
LIMIT %d
OFFSET %d;",
self::RESULTS_PER_PAGE,
$offset
);
}
return $wpdb->get_results( $sql, ARRAY_A );
}
/**
* Update feed data in the sbi_feed table
*
* @param array $to_update
* @param array $where_data
*
* @return false|int
*
* @since 2.0
*/
public static function feeds_update( $to_update, $where_data ) {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$data = array();
$where = array();
$format = array();
foreach ( $to_update as $single_insert ) {
if ( $single_insert['key'] ) {
$data[ $single_insert['key'] ] = $single_insert['values'][0];
$format[] = '%s';
}
}
if ( isset( $where_data['id'] ) ) {
$where['id'] = $where_data['id'];
$where_format = array( '%d' );
} elseif ( isset( $where_data['feed_name'] ) ) {
$where['feed_name'] = $where_data['feed_name'];
$where_format = array( '%s' );
} else {
return false;
}
$data['last_modified'] = gmdate( 'Y-m-d H:i:s' );
$format[] = '%s';
$affected = $wpdb->update( $feeds_table_name, $data, $where, $format, $where_format );
return $affected;
}
/**
* New feed data is added to the sby_feeds table and
* the new insert ID is returned
*
* @param array $to_insert
*
* @return false|int
*
* @since 2.0
*/
public static function feeds_insert( $to_insert ) {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$data = array();
$format = array();
foreach ( $to_insert as $single_insert ) {
if ( $single_insert['key'] ) {
$data[ $single_insert['key'] ] = $single_insert['values'][0];
$format[] = '%s';
}
}
$data['last_modified'] = gmdate( 'Y-m-d H:i:s' );
$format[] = '%s';
$data['author'] = get_current_user_id();
$format[] = '%d';
$wpdb->insert( $feeds_table_name, $data, $format );
return $wpdb->insert_id;
}
/**
* Query the sby_feeds table
* Porcess to define the name of the feed when adding new
*
* @param string $sourcename
*
* @return array|bool
*
* @since 2.0
*/
public static function feeds_query_name( $sourcename ) {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$sql = $wpdb->prepare(
"SELECT * FROM $feeds_table_name
WHERE feed_name LIKE %s;",
$wpdb->esc_like( $sourcename ) . '%'
);
$count = count( $wpdb->get_results( $sql, ARRAY_A ) );
return ( $count === 0 ) ? $sourcename : $sourcename . ' (' . ( $count + 1 ) . ')';
}
/**
* Query to Remove Feeds from Database
*
* @param array $feed_ids_array
*
* @since 2.0
*/
public static function delete_feeds_query( $feed_ids_array ) {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$feed_caches_table_name = $wpdb->prefix . 'sbi_feed_caches';
$feed_ids_array = implode( ',', array_map( 'absint', $feed_ids_array ) );
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $feeds_table_name WHERE id IN ($feed_ids_array)"
)
);
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $feed_caches_table_name WHERE feed_id IN ($feed_ids_array)"
)
);
echo json_encode( SBI_Feed_Builder::get_feed_list() );
wp_die();
}
/**
* Query to Remove Source from Database
*
* @param array $source_id
*
* @since 2.0
*/
public static function delete_source_query( $source_id ) {
global $wpdb;
$sources_table_name = $wpdb->prefix . 'sbi_sources';
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $sources_table_name WHERE id = %d; ",
$source_id
)
);
echo json_encode( SBI_Feed_Builder::get_source_list() );
wp_die();
}
/**
* Query to Remove Source from Database
*
* @param array $source_id
*
* @since 2.0
*/
public static function delete_source_by_account_id( $source_id ) {
global $wpdb;
$sources_table_name = $wpdb->prefix . 'sbi_sources';
$wpdb->query(
$wpdb->prepare(
"DELETE FROM $sources_table_name WHERE account_id = %s; ",
$source_id
)
);
}
/**
* Query to Duplicate a Single Feed
*
* @param int $feed_id
*
* @since 2.0
*/
public static function duplicate_feed_query( $feed_id ) {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$wpdb->query(
$wpdb->prepare(
"INSERT INTO $feeds_table_name (feed_name, settings, author, status)
SELECT CONCAT(feed_name, ' (copy)'), settings, author, status
FROM $feeds_table_name
WHERE id = %d; ",
$feed_id
)
);
echo json_encode( SBI_Feed_Builder::get_feed_list() );
wp_die();
}
/**
* Get cache records in the sbi_feed_caches table
*
* @param array $args
*
* @return array|object|null
*/
public static function feed_caches_query( $args ) {
global $wpdb;
$feed_cache_table_name = $wpdb->prefix . 'sbi_feed_caches';
if ( ! isset( $args['cron_update'] ) ) {
$sql = "
SELECT * FROM $feed_cache_table_name;";
} else {
if ( ! isset( $args['additional_batch'] ) ) {
$sql = $wpdb->prepare(
"
SELECT * FROM $feed_cache_table_name
WHERE cron_update = 'yes'
ORDER BY last_updated ASC
LIMIT %d;",
self::RESULTS_PER_CRON_UPDATE
);
} else {
$sql = $wpdb->prepare(
"
SELECT * FROM $feed_cache_table_name
WHERE cron_update = 'yes'
AND last_updated < %s
ORDER BY last_updated ASC
LIMIT %d;",
gmdate( 'Y-m-d H:i:s', time() - HOUR_IN_SECONDS ),
self::RESULTS_PER_CRON_UPDATE
);
}
}
return $wpdb->get_results( $sql, ARRAY_A );
}
/**
* Creates all database tables used in the new admin area in
* the 6.0 update.
*
* TODO: Add error reporting
*
* @since 2.0
*/
public static function create_tables( $include_charset_collate = true ) {
if ( ! function_exists( 'dbDelta' ) ) {
require_once ABSPATH . '/wp-admin/includes/upgrade.php';
}
global $wpdb;
$max_index_length = 191;
$charset_collate = '';
if ( $include_charset_collate && method_exists( $wpdb, 'get_charset_collate' ) ) { // get_charset_collate introduced in WP 3.5
$charset_collate = $wpdb->get_charset_collate();
}
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
if ( $wpdb->get_var( "show tables like '$feeds_table_name'" ) !== $feeds_table_name ) {
$sql = "
CREATE TABLE $feeds_table_name (
id bigint(20) unsigned NOT NULL auto_increment,
feed_name text NOT NULL default '',
feed_title text NOT NULL default '',
settings longtext NOT NULL default '',
author bigint(20) unsigned NOT NULL default '1',
status varchar(255) NOT NULL default '',
last_modified datetime NOT NULL,
PRIMARY KEY (id),
KEY author (author)
) $charset_collate;
";
$wpdb->query( $sql );
}
$error = $wpdb->last_error;
$query = $wpdb->last_query;
$had_error = false;
if ( $wpdb->get_var( "show tables like '$feeds_table_name'" ) !== $feeds_table_name ) {
$had_error = true;
}
if ( ! $had_error ) {
}
$feed_caches_table_name = $wpdb->prefix . 'sby_feed_caches';
if ( $wpdb->get_var( "show tables like '$feed_caches_table_name'" ) !== $feed_caches_table_name ) {
$sql = '
CREATE TABLE ' . $feed_caches_table_name . " (
id bigint(20) unsigned NOT NULL auto_increment,
feed_id varchar(255) NOT NULL default '',
cache_key varchar(255) NOT NULL default '',
cache_value longtext NOT NULL default '',
cron_update varchar(20) NOT NULL default 'yes',
last_updated datetime NOT NULL,
PRIMARY KEY (id),
KEY feed_id (feed_id($max_index_length))
) $charset_collate;";
$wpdb->query( $sql );
}
$error = $wpdb->last_error;
$query = $wpdb->last_query;
$had_error = false;
if ( $wpdb->get_var( "show tables like '$feed_caches_table_name'" ) !== $feed_caches_table_name ) {
$had_error = true;
}
if ( ! $had_error ) {
}
$sources_table_name = $wpdb->prefix . 'sby_sources';
if ( $wpdb->get_var( "show tables like '$sources_table_name'" ) !== $sources_table_name ) {
$sql = '
CREATE TABLE ' . $sources_table_name . " (
id bigint(20) unsigned NOT NULL auto_increment,
account_id varchar(255) NOT NULL default '',
account_type varchar(255) NOT NULL default '',
privilege varchar(255) NOT NULL default '',
access_token varchar(1000) NOT NULL default '',
username varchar(255) NOT NULL default '',
info text NOT NULL default '',
error text NOT NULL default '',
expires datetime NOT NULL,
last_updated datetime NOT NULL,
author bigint(20) unsigned NOT NULL default '1',
PRIMARY KEY (id),
KEY account_type (account_type($max_index_length)),
KEY author (author)
) $charset_collate;";
$wpdb->query( $sql );
}
$error = $wpdb->last_error;
$query = $wpdb->last_query;
$had_error = false;
if ( $wpdb->get_var( "show tables like '$sources_table_name'" ) !== $sources_table_name ) {
$had_error = true;
}
if ( ! $had_error ) {
}
}
public static function create_sources_database() {
// not needed
}
public static function clear_sbi_feed_caches() {
global $wpdb;
$feed_caches_table_name = $wpdb->prefix . 'sbi_feed_caches';
if ( $wpdb->get_var( "show tables like '$feed_caches_table_name'" ) === $feed_caches_table_name ) {
$wpdb->query( "DELETE FROM $feed_caches_table_name" );
}
}
public static function clear_sbi_sources() {
global $wpdb;
$sources_table_name = $wpdb->prefix . 'sbi_sources';
if ( $wpdb->get_var( "show tables like '$sources_table_name'" ) === $sources_table_name ) {
$wpdb->query( "DELETE FROM $sources_table_name" );
}
}
public static function reset_tables() {
global $wpdb;
$feeds_table_name = $wpdb->prefix . 'sby_feeds';
$wpdb->query( "DROP TABLE IF EXISTS $feeds_table_name" );
$feed_caches_table_name = $wpdb->prefix . 'sbi_feed_caches';
$wpdb->query( "DROP TABLE IF EXISTS $feed_caches_table_name" );
$sources_table_name = $wpdb->prefix . 'sbi_sources';
$wpdb->query( "DROP TABLE IF EXISTS $sources_table_name" );
}
public static function reset_db_update() {
update_option( 'sbi_db_version', 1.9 );
delete_option( 'sbi_legacy_feed_settings' );
// are there existing feeds to toggle legacy onboarding?
$sbi_statuses_option = get_option( 'sbi_statuses', array() );
if ( isset( $sbi_statuses_option['legacy_onboarding'] ) ) {
unset( $sbi_statuses_option['legacy_onboarding'] );
}
if ( isset( $sbi_statuses_option['support_legacy_shortcode'] ) ) {
unset( $sbi_statuses_option['support_legacy_shortcode'] );
}
global $wpdb;
$table_name = $wpdb->prefix . 'usermeta';
$wpdb->query(
"
DELETE
FROM $table_name
WHERE `meta_key` LIKE ('sbi\_%')
"
);
$feed_locator_table_name = $wpdb->prefix . SBI_INSTAGRAM_FEED_LOCATOR;
$results = $wpdb->query(
"
DELETE
FROM $feed_locator_table_name
WHERE feed_id LIKE '*%';"
);
update_option( 'sbi_statuses', $sbi_statuses_option );
}
public static function reset_legacy() {
//Settings
delete_option( 'sbi_statuses' );
delete_option( 'sb_instagram_settings' );
delete_option( 'sbi_ver' );
delete_option( 'sb_expired_tokens' );
delete_option( 'sbi_cron_report' );
delete_option( 'sb_instagram_errors' );
delete_option( 'sb_instagram_ajax_status' );
delete_option( 'sbi_db_version' );
// Clear backup caches
global $wpdb;
$table_name = $wpdb->prefix . 'options';
$wpdb->query(
"
DELETE
FROM $table_name
WHERE `option_name` LIKE ('%!sbi\_%')
"
);
$wpdb->query(
"
DELETE
FROM $table_name
WHERE `option_name` LIKE ('%\_transient\_&sbi\_%')
"
);
$wpdb->query(
"
DELETE
FROM $table_name
WHERE `option_name` LIKE ('%\_transient\_timeout\_&sbi\_%')
"
);
$wpdb->query(
"
DELETE
FROM $table_name
WHERE `option_name` LIKE ('%sb_wlupdated_%')
"
);
//image resizing
$upload = wp_upload_dir();
$posts_table_name = $wpdb->prefix . 'sbi_instagram_posts';
$feeds_posts_table_name = $wpdb->prefix . 'sbi_instagram_feeds_posts';
$image_files = glob( trailingslashit( $upload['basedir'] ) . trailingslashit( SBI_UPLOADS_NAME ) . '*' ); // get all file names
foreach ( $image_files as $file ) { // iterate files
if ( is_file( $file ) ) {
unlink( $file );
} // delete file
}
//global $wp_filesystem;
//$wp_filesystem->delete( trailingslashit( $upload['basedir'] ) . trailingslashit( SBI_UPLOADS_NAME ) , true );
//Delete tables
$wpdb->query( "DROP TABLE IF EXISTS $posts_table_name" );
$wpdb->query( "DROP TABLE IF EXISTS $feeds_posts_table_name" );
$locator_table_name = $wpdb->prefix . SBI_INSTAGRAM_FEED_LOCATOR;
$wpdb->query( "DROP TABLE IF EXISTS $locator_table_name" );
$table_name = $wpdb->prefix . 'options';
$wpdb->query(
"
DELETE
FROM $table_name
WHERE `option_name` LIKE ('%\_transient\_\$sbi\_%')
"
);
$wpdb->query(
"
DELETE
FROM $table_name
WHERE `option_name` LIKE ('%\_transient\_timeout\_\$sbi\_%')
"
);
delete_option( 'sbi_hashtag_ids' );
delete_option( 'sb_instagram_errors' );
delete_option( 'sbi_usage_tracking_config' );
delete_option( 'sbi_usage_tracking' );
delete_option( 'sbi_oembed_token' );
delete_option( 'sbi_top_api_calls' );
delete_option( 'sbi_rating_notice' );
delete_option( 'sbi_refresh_report' );
delete_option( 'sbi_welcome_seen' );
delete_option( 'sbi_notifications' );
delete_option( 'sbi_newuser_notifications' );
global $wp_roles;
$wp_roles->remove_cap( 'administrator', 'manage_instagram_feed_options' );
wp_clear_scheduled_hook( 'sbi_feed_update' );
wp_clear_scheduled_hook( 'sbi_usage_tracking_cron' );
}
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,667 @@
<?php
/**
* YouTube Feed Database
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder;
use SmashBalloon\YouTubeFeed\Customizer\ProxyProvider;
class SBY_Feed_Saver {
/**
* @var int
*
* @since 2.0
*/
private $insert_id;
/**
* @var array
*
* @since 2.0
*/
private $data;
/**
* @var array
*
* @since 2.0
*/
private $sanitized_and_sorted_data;
/**
* @var array
*
* @since 2.0
*/
private $feed_db_data;
/**
* @var string
*
* @since 2.0
*/
private $feed_name;
/**
* @var bool
*
* @since 2.0
*/
private $is_legacy;
/**
* @var ProxyProvider
*/
private $proxy_provider;
/**
* SBY_Feed_Saver constructor.
*
* @param int $insert_id
*
* @since 2.0
*/
public function __construct( $insert_id ) {
$this->proxy_provider = new ProxyProvider;
if ( $insert_id === 'legacy' ) {
$this->is_legacy = true;
$this->insert_id = 0;
} else {
$this->is_legacy = false;
$this->insert_id = $insert_id;
}
}
/**
* Feed insert ID if it exists
*
* @return bool|int
*
* @since 2.0
*/
public function get_feed_id() {
if ( $this->is_legacy ) {
return 'legacy';
}
if ( ! empty( $this->insert_id ) ) {
return $this->insert_id;
} else {
return false;
}
}
/**
* @param array $data
*
* @since 2.0
*/
public function set_data( $data ) {
$this->data = $data;
}
/**
* @param string $feed_name
*
* @since 2.0
*/
public function set_feed_name( $feed_name ) {
$this->feed_name = $feed_name;
}
/**
*
* @return array
*
* @since 2.0
*/
public function get_feed_db_data() {
return $this->feed_db_data;
}
/**
* Adds a new feed if there is no associated feed
* found. Otherwise updates the exiting feed.
*
* @return false|int
*
* @since 2.0
*/
public function update_or_insert() {
$this->sanitize_and_sort_data();
if ( $this->exists_in_database() ) {
return $this->update();
} else {
return $this->insert();
}
}
/**
* Whether or not a feed exists with the
* associated insert ID
*
* @return bool
*
* @since 2.0
*/
public function exists_in_database() {
if ( $this->is_legacy ) {
return true;
}
if ( $this->insert_id === false ) {
return false;
}
$args = array(
'id' => $this->insert_id,
);
$results = SBY_Db::feeds_query( $args );
return isset( $results[0] );
}
/**
* Inserts a new feed from sanitized and sorted data.
* Some data is saved in the sbi_feeds table and some is
* saved in the sbi_feed_settings table.
*
* @return false|int
*
* @since 2.0
*/
public function insert() {
if ( $this->is_legacy ) {
return $this->update();
}
if ( ! isset( $this->sanitized_and_sorted_data ) ) {
return false;
}
$settings_array = self::format_settings( $this->sanitized_and_sorted_data['feed_settings'] );
$this->sanitized_and_sorted_data['feeds'][] = array(
'key' => 'settings',
'values' => array( json_encode( $settings_array ) ),
);
if ( ! empty( $this->feed_name ) ) {
$this->sanitized_and_sorted_data['feeds'][] = array(
'key' => 'feed_name',
'values' => array( $this->feed_name ),
);
}
$this->sanitized_and_sorted_data['feeds'][] = array(
'key' => 'status',
'values' => array( 'publish' ),
);
$insert_id = SBY_Db::feeds_insert( $this->sanitized_and_sorted_data['feeds'] );
if ( $insert_id ) {
$this->insert_id = $insert_id;
return $insert_id;
}
return false;
}
/**
* Updates an existing feed and related settings from
* sanitized and sorted data.
*
* @return false|int
*
* @since 2.0
*/
public function update() {
if ( ! isset( $this->sanitized_and_sorted_data ) ) {
return false;
}
$args = array(
'id' => $this->insert_id,
);
$settings_array = self::format_settings( $this->sanitized_and_sorted_data['feed_settings'] );
if ( $this->is_legacy ) {
$to_save_json = json_encode( $settings_array );
update_option( 'sby_legacy_feed_settings', $to_save_json, false );
return true;
}
$this->sanitized_and_sorted_data['feeds'][] = array(
'key' => 'settings',
'values' => array( json_encode( $settings_array ) ),
);
$this->sanitized_and_sorted_data['feeds'][] = array(
'key' => 'feed_name',
'values' => array( sanitize_text_field( $this->feed_name ) ),
);
$success = SBY_Db::feeds_update( $this->sanitized_and_sorted_data['feeds'], $args );
return $success;
}
/**
* Converts settings that have been sanitized into an associative array
* that can be saved as JSON in the database
*
* @param $raw_settings
*
* @return array
*
* @since 2.0
*/
public static function format_settings( $raw_settings ) {
$settings_array = array();
foreach ( $raw_settings as $single_setting ) {
if ( count( $single_setting['values'] ) > 1 ) {
$settings_array[ $single_setting['key'] ] = $single_setting['values'];
} else {
$settings_array[ $single_setting['key'] ] = isset( $single_setting['values'][0] ) ? $single_setting['values'][0] : '';
}
}
return $settings_array;
}
/**
* Gets the Preview Settings
* for the Feed Fly Preview
*
* @return bool
*
* @since 2.0
*/
public function get_feed_preview_settings( $preview_settings ) {
return false;
}
/**
* Retrieves and organizes feed setting data for easy use in
* the builder
*
* @return array|bool
*
* @since 2.0
*/
public function get_feed_settings() {
if ( $this->is_legacy ) {
$feed_settings = $this->proxy_provider->get_settings_class();
$feed_settings->set_feed_type_and_terms();
$feed_settings->set_transient_name();
$return = $feed_settings->get_settings();
$this->feed_db_data = array(
'id' => 'legacy',
'feed_name' => __( 'Legacy Feeds', 'feeds-for-youtube' ),
'feed_title' => __( 'Legacy Feeds', 'feeds-for-youtube' ),
'status' => 'publish',
'last_modified' => date( 'Y-m-d H:i:s' ),
);
} elseif ( empty( $this->insert_id ) ) {
return false;
} else {
$args = array(
'id' => $this->insert_id,
);
$settings_db_data = SBY_Db::feeds_query( $args );
if ( false === $settings_db_data || sizeof( $settings_db_data ) === 0 ) {
return false;
}
$this->feed_db_data = array(
'id' => $settings_db_data[0]['id'],
'feed_name' => $settings_db_data[0]['feed_name'],
'feed_title' => $settings_db_data[0]['feed_title'],
'status' => $settings_db_data[0]['status'],
'last_modified' => $settings_db_data[0]['last_modified'],
);
$return = json_decode( $settings_db_data[0]['settings'], true );
$return['feed_name'] = $settings_db_data[0]['feed_name'];
}
$return = wp_parse_args( $return, self::settings_defaults() );
if ( empty( $return['id'] ) ) {
return $return;
}
if ( ! is_array( $return['id'] ) ) {
$return['id'] = explode( ',', str_replace( ' ', '', $return['id'] ) );
}
if ( ! is_array( $return['tagged'] ) ) {
$return['tagged'] = explode( ',', str_replace( ' ', '', $return['tagged'] ) );
}
if ( ! is_array( $return['hashtag'] ) ) {
$return['hashtag'] = explode( ',', str_replace( ' ', '', $return['hashtag'] ) );
}
$args = array( 'id' => $return['id'] );
$source_query = SBY_Db::source_query( $args );
$return['sources'] = array();
if ( ! empty( $source_query ) ) {
foreach ( $source_query as $source ) {
$user_id = $source['account_id'];
$return['sources'][ $user_id ] = self::get_processed_source_data( $source );
}
} else {
$found_sources = array();
foreach ( $return['id'] as $id_or_slug ) {
$maybe_source_from_connected = SBY_Source::maybe_one_off_connected_account_update( $id_or_slug );
if ( $maybe_source_from_connected ) {
$found_sources[] = $maybe_source_from_connected;
}
}
if ( ! empty( $found_sources ) ) {
foreach ( $found_sources as $source ) {
$user_id = $source['account_id'];
$return['sources'][ $user_id ] = self::get_processed_source_data( $source );
}
} else {
$source_query = SBY_Db::source_query( $args );
if ( isset( $source_query[0] ) ) {
$source = $source_query[0];
$user_id = $source['account_id'];
$return['sources'][ $user_id ] = self::get_processed_source_data( $source );
}
}
}
return $return;
}
public static function get_processed_source_data( $source ) {
$encryption = new \SB_Instagram_Data_Encryption();
$user_id = $source['account_id'];
$info = ! empty( $source['info'] ) ? json_decode( $encryption->decrypt( $source['info'] ), true ) : array();
$cdn_avatar_url = \SB_Instagram_Parse_Pro::get_avatar_url( $info );
$processed = array(
'record_id' => stripslashes( $source['id'] ),
'user_id' => $user_id,
'type' => stripslashes( $source['account_type'] ),
'privilege' => stripslashes( $source['privilege'] ),
'access_token' => stripslashes( $encryption->decrypt( $source['access_token'] ) ),
'username' => stripslashes( $source['username'] ),
'name' => stripslashes( $source['username'] ),
'info' => stripslashes( $encryption->decrypt( $source['info'] ) ),
'error' => stripslashes( $source['error'] ),
'expires' => stripslashes( $source['expires'] ),
'profile_picture' => $cdn_avatar_url,
'local_avatar_url' => \SB_Instagram_Connected_Account::maybe_local_avatar( $source['username'], $cdn_avatar_url ),
);
return $processed;
}
/**
* Retrieves and organizes feed setting data for easy use in
* the builder
* It will NOT get the settings from the DB, but from the Customizer builder
* To be used for updating feed preview on the fly
*
* @return array|bool
*
* @since 2.0
*/
public function get_feed_settings_preview( $settings_db_data ) {
if ( false === $settings_db_data || sizeof( $settings_db_data ) === 0 ) {
return false;
}
$return = $settings_db_data;
$return = wp_parse_args( $return, self::settings_defaults() );
if ( empty( $return['sources'] ) ) {
return $return;
}
$sources = array();
foreach ( $return['sources'] as $single_source ) {
array_push( $sources, $single_source['account_id'] );
}
$args = array( 'id' => $sources );
$source_query = SBY_Db::source_query( $args );
$return['sources'] = array();
if ( ! empty( $source_query ) ) {
foreach ( $source_query as $source ) {
$user_id = $source['account_id'];
$return['sources'][ $user_id ] = self::get_processed_source_data( $source );
}
}
return $return;
}
/**
* Default settings, $return_array equalling false will return
* the settings in the general way that the "SBI_Shortcode" class,
* "sbi_get_processed_options" method does
*
* @param bool $return_array
*
* @return array
*
* @since 2.0
*/
public static function settings_defaults( $return_array = true ) {
{
$defaults = array(
'connected_accounts' => array(),
'type' => 'channel',
'channel' => '',
'num' => 9,
'nummobile' => 9,
'widthresp' => true,
'class' => '',
'height' => '',
'heightunit' => '%',
'disablemobile' => false,
'itemspacing' => 5,
'itemspacingunit' => 'px',
'background' => '',
'headercolor' => '',
'subscribecolor' => '',
'subscribetextcolor' => '',
'buttoncolor' => '',
'buttontextcolor' => '',
'layout' => 'grid',
'playvideo' => 'automatically',
'sortby' => 'none',
'imageres' => 'auto',
'showheader' => true,
'showdescription' => true,
'showbutton' => true,
'headersize' => 'small',
'headeroutside' => false,
'showsubscribe' => true,
'buttontext' => __( 'Load More...', 'feeds-for-youtube' ),
'subscribetext' => __( 'Subscribe', 'feeds-for-youtube' ),
'caching_type' => 'page',
'cache_time' => 1,
'cache_time_unit' => 'hours',
'backup_cache_enabled' => true,
'resizeprocess' => 'background',
'disable_resize' => true,
'storage_process' => 'background',
'favor_local' => false,
'disable_js_image_loading' => false,
'ajax_post_load' => false,
'ajaxtheme' => false,
'enqueue_css_in_shortcode' => false,
'font_method' => 'svg',
'customtemplates' => false,
'gallerycols' => 3,
'gallerycolsmobile' => 2,
'gridcols' => 3,
'gridcolsmobile' => 2,
'playerratio' => '9:16',
'eagerload' => false,
'custom_css' => '',
'custom_js' => '',
'gdpr' => 'auto',
'disablecdn' => false,
'allowcookies' => false,
// pro only
'usecustomsearch' => false,
'headerchannel' => '',
'customsearch' => '',
'showpast' => true,
'showlikes' => true,
'carouselcols' => 3,
'carouselcolsmobile' => 2,
'carouselarrows' => true,
'carouselpag' => true,
'carouselautoplay' => false,
'infoposition' => 'below',
'include' => array( 'title', 'icon', 'user', 'date', 'countdown' ),
'hoverinclude' => array( 'description', 'stats' ),
'descriptionlength' => 150,
'userelative' => true,
'dateformat' => '0',
'customdate' => '',
'showsubscribers' => true,
'descriptiontextsize' => '13px',
'subscriberstext' => __( 'subscribers', 'feeds-for-youtube' ),
'viewstext' => __( 'views', 'feeds-for-youtube' ),
'agotext' => __( 'ago', 'feeds-for-youtube' ),
'beforedatetext' => __( 'Streaming live', 'feeds-for-youtube' ),
'beforestreamtimetext' => __( 'Streaming live in', 'feeds-for-youtube' ),
'minutetext' => __( 'minute', 'feeds-for-youtube' ),
'minutestext' => __( 'minutes', 'feeds-for-youtube' ),
'hourstext' => __( 'hours', 'feeds-for-youtube' ),
'thousandstext' => __( 'K', 'feeds-for-youtube' ),
'millionstext' => __( 'M', 'feeds-for-youtube' ),
'watchnowtext' => __( 'Watch Now', 'feeds-for-youtube' ),
'cta' => 'related',
// pro comments
'numcomments' => 20,
'enablecomments' => false,
'linktext' => __( 'Learn More', 'feeds-for-youtube' ),
'linkurl' => '',
'linkopentype' => 'same',
'linkcolor' => '',
'linktextcolor' => '',
);
$defaults = self::filter_defaults( $defaults );
// some settings are comma separated and not arrays when the feed is created
if ( $return_array ) {
$settings_with_multiples = array(
'sources',
);
foreach ( $settings_with_multiples as $multiple_key ) {
if ( isset( $defaults[ $multiple_key ] ) ) {
$defaults[ $multiple_key ] = explode( ',', $defaults[ $multiple_key ] );
}
}
}
return $defaults;
}
}
/**
* Provides backwards compatibility for extensions
*
* @param array $defaults
*
* @return array
*
* @since 2.0
*/
public static function filter_defaults( $defaults ) {
return $defaults;
}
/**
* Saves settings for legacy feeds. Runs on first update automatically.
*
* @since 2.0
*/
public static function set_legacy_feed_settings() {
$to_save = SBI_Post_Set::legacy_to_builder_convert();
$to_save_json = json_encode( $to_save );
update_option( 'sbi_legacy_feed_settings', $to_save_json, false );
}
/**
* Used for taking raw post data related to settings
* an sanitizing it and sorting it to easily use in
* the database tables
*
* @since 2.0
*/
private function sanitize_and_sort_data() {
$data = $this->data;
$sanitized_and_sorted = array(
'feeds' => array(),
'feed_settings' => array(),
);
foreach ( $data as $key => $value ) {
$data_type = SBY_Feed_Saver_Manager::get_data_type( $key );
$sanitized_values = array();
if ( is_array( $value ) ) {
foreach ( $value as $item ) {
$type = SBY_Feed_Saver_Manager::is_boolean( $item ) ? 'boolean' : $data_type['sanitization'];
$sanitized_values[] = SBY_Feed_Saver_Manager::sanitize( $type, $item );
}
} else {
$type = SBY_Feed_Saver_Manager::is_boolean( $value ) ? 'boolean' : $data_type['sanitization'];
$sanitized_values[] = SBY_Feed_Saver_Manager::sanitize( $type, $value );
}
$single_sanitized = array(
'key' => $key,
'values' => $sanitized_values,
);
$sanitized_and_sorted[ $data_type['table'] ][] = $single_sanitized;
}
$this->sanitized_and_sorted_data = $sanitized_and_sorted;
}
}

View File

@@ -0,0 +1,707 @@
<?php
/**
* YouTube Feed Saver Manager
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder;
use SmashBalloon\YouTubeFeed\SBY_Cache;
use SmashBalloon\YouTubeFeed\Services\ShortcodeService;
use SmashBalloon\YouTubeFeed\Customizer\DB;
use Smashballoon\Customizer\Feed_Builder;
use SmashBalloon\YouTubeFeed\SBY_Parse;
use SmashBalloon\YouTubeFeed\Helpers\Util;
class SBY_Feed_Saver_Manager
{
/**
* AJAX hooks for various feed data related functionality
*
* @since 2.0
*/
public static function register()
{
add_action('wp_ajax_sby_feed_saver_manager_builder_update', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'builder_update' ));
add_action('wp_ajax_sby_feed_saver_manager_get_feed_list_page', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'get_feed_list_page' ));
add_action('wp_ajax_sby_feed_saver_manager_fly_preview', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'feed_customizer_fly_preview' ));
add_action('wp_ajax_sby_feed_handle_saver_manager_fly_preview', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'feed_customizer_feed_handle_fly_preview' ));
add_action('wp_ajax_sby_feed_saver_manager_clear_single_feed_cache', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'clear_single_feed_cache' ));
add_action('wp_ajax_sby_feed_saver_manager_duplicate_feed', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'duplicate_feed' ));
add_action('wp_ajax_sby_feed_saver_manager_delete_feeds', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'delete_feed' ));
add_action('wp_ajax_sby_dismiss_onboarding', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'after_dismiss_onboarding' ));
add_action('wp_ajax_sby_feed_refresh', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'feed_refresh' ));
add_action('wp_ajax_sby_feed_saver_clear_comments_cache', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Saver_Manager', 'clear_comments_cache' ));
}
/**
* Used in an AJAX call to update settings for a particular feed.
* Can also be used to create a new feed if no feed_id sent in
* $_POST data.
*
* @since 2.0
*/
public static function builder_update()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
$settings_data = $_POST;
$feed_id = false;
$is_new_feed = isset($settings_data['new_insert']) ? true : false;
if (! empty($settings_data['feed_id'])) {
$feed_id = sanitize_text_field($settings_data['feed_id']);
unset($settings_data['feed_id']);
} elseif (isset($settings_data['feed_id'])) {
unset($settings_data['feed_id']);
}
unset($settings_data['action']);
unset($settings_data['nonce']);
if (! isset($settings_data['feed_name'])) {
$settings_data['feed_name'] = '';
}
// If all video elements are disabled then store it as an empty array
if (empty($settings_data['settings']['include'])) {
$settings_data['settings']['include'] = array();
}
if (empty($settings_data['settings']['hoverinclude'])) {
$settings_data['settings']['hoverinclude'] = array();
}
$update_feed = isset($settings_data['update_feed']) ? true : false;
unset($settings_data['update_feed']);
if ($is_new_feed) {
$settings_data = SBY_Feed_Templates_Settings::get_feed_settings_by_feed_templates($settings_data);
}
$selected_feed_model = isset($settings_data['selectedFeedModel']) ? self::filter_feed_model_data($settings_data['selectedFeedModel'], $settings_data['feedtype']) : '';
// Check if New
if (isset($settings_data['new_insert']) && $settings_data['new_insert'] === 'true' && isset($settings_data['feedtype'])) {
$feedtype = sanitize_text_field($settings_data['feedtype']);
$feed_type_data = self::create_single_feed_type_data($feedtype, $selected_feed_model);
$settings_data = array_merge($feed_type_data, $settings_data);
$settings_data['feed_name'] = self::create_feed_name($settings_data['feedtype'], $selected_feed_model);
}
unset($settings_data['feedtype']);
unset($settings_data['selectedFeedModel']);
unset($settings_data['new_insert']);
unset($settings_data['sourcename']);
$feed_name = '';
if ($update_feed) {
$feed_name = $settings_data['feed_name'];
$settings_data = $settings_data['settings'];
}
unset($settings_data['sources']);
$feed_saver = new SBY_Feed_Saver($feed_id);
$feed_saver->set_feed_name($feed_name);
$feed_saver->set_data($settings_data);
$return = array(
'success' => false,
'feed_id' => false,
);
if ($feed_saver->update_or_insert()) {
$return = array(
'success' => true,
'feed_id' => $feed_saver->get_feed_id(),
);
if ($is_new_feed) {
echo wp_json_encode($return);
wp_die();
} else {
$feed_cache = new SBY_Cache($feed_id);
$feed_cache->clear('all');
$feed_cache->clear('posts');
echo wp_json_encode($return);
wp_die();
}
}
echo wp_json_encode($return);
wp_die();
}
/**
* Get a list of feeds with a limit and offset like a page
*
* @since 2.0
*/
public static function get_feed_list_page()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
$args = array( 'page' => (int)$_POST['page'] );
$feeds_data = sby_builder_pro()->get_feed_list($args);
echo wp_json_encode($feeds_data);
wp_die();
}
/**
* Used in an AJAX call to delete a feed cache from the Database
* $_POST data.
*
* @since 2.0
*/
public static function clear_single_feed_cache()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
$feed_id = sanitize_key($_POST['feedID']);
// clear object cache
sby_clear_object_cache();
// clear transients
sby_clear_cache();
self::feed_customizer_fly_preview();
wp_die();
}
/**
* Used To check if it's customizer Screens
* Returns Feed info or false!
*
* @param bool $include_comments
*
* @return array|bool
*
* @since 2.0
*/
public static function maybe_feed_customizer_data($include_comments = false)
{
if (isset($_GET['feed_id'])) {
$feed_id = sanitize_key($_GET['feed_id']);
$feed_saver = new SBY_Feed_Saver($feed_id);
$settings = $feed_saver->get_feed_settings();
$feed_db_data = $feed_saver->get_feed_db_data();
if ($settings !== false) {
$return = array(
'feed_info' => $feed_db_data,
'headerData' => $feed_db_data,
'settings' => $settings,
'posts' => array(),
);
if (intval($feed_id) > 0) {
$instagram_feed_settings = new \SB_Instagram_Settings_Pro(
array(
'feed' => $feed_id,
'customizer' => true,
),
sbi_defaults()
);
} else {
$instagram_feed_settings = new \SB_Instagram_Settings_Pro($settings, sbi_defaults());
}
$instagram_feed_settings->set_feed_type_and_terms();
$instagram_feed_settings->set_transient_name();
$transient_name = $instagram_feed_settings->get_transient_name();
$settings = $instagram_feed_settings->get_settings();
$feed_type_and_terms = $instagram_feed_settings->get_feed_type_and_terms();
if ($feed_id === 'legacy' && $transient_name === 'sbi_false') {
$transient_name = 'sbi_legacy';
}
$instagram_feed = new \SB_Instagram_Feed_Pro($transient_name);
$instagram_feed->set_cache($instagram_feed_settings->get_cache_time_in_seconds(), $settings);
if ($instagram_feed->regular_cache_exists()) {
$instagram_feed->set_post_data_from_cache();
if ($instagram_feed->need_posts($settings['num']) && $instagram_feed->can_get_more_posts()) {
while ($instagram_feed->need_posts($settings['num']) && $instagram_feed->can_get_more_posts()) {
$instagram_feed->add_remote_posts($settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed());
}
$instagram_feed->cache_feed_data($instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled']);
}
} else {
while ($instagram_feed->need_posts($settings['num']) && $instagram_feed->can_get_more_posts()) {
$instagram_feed->add_remote_posts($settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed());
}
if ($instagram_feed->out_of_next_pages() || $instagram_feed->should_look_for_db_only_posts($settings, $feed_type_and_terms)) {
$instagram_feed->add_db_only_posts($transient_name, $settings, $feed_type_and_terms);
}
if (! $instagram_feed->should_use_backup()) {
$instagram_feed->cache_feed_data($instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled']);
} elseif ($instagram_feed->should_cache_error()) {
$cache_time = min($instagram_feed_settings->get_cache_time_in_seconds(), 15 * 60);
$instagram_feed->cache_feed_data($cache_time, false);
}
}
$return['posts'] = $instagram_feed->get_post_data();
$header_data = array();
$instagram_feed->set_remote_header_data($settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed());
$header_data = $instagram_feed->get_header_data();
if ($settings['stories'] && ! empty($header_data)) {
$instagram_feed->set_remote_stories_data($settings, $feed_type_and_terms, $instagram_feed_settings->get_connected_accounts_in_feed());
}
$instagram_feed->cache_header_data($instagram_feed_settings->get_cache_time_in_seconds(), $settings['backup_cache_enabled']);
if (! empty($header_data) && \SB_Instagram_Connected_Account::local_avatar_exists($header_data['username'])) {
$header_data['local_avatar_url'] = \SB_Instagram_Connected_Account::get_local_avatar_url($header_data['username']);
$header_data['local_avatar'] = \SB_Instagram_Connected_Account::get_local_avatar_url($header_data['username']);
} else {
$header_data['local_avatar'] = false;
}
$header_data['local_avatar'] = false;
$return['header'] = $header_data;
$return['headerData'] = $header_data;
return $return;
}
}
return false;
}
/**
* Get single feed type create data
*
* @since 2.0
*/
public static function create_single_feed_type_data($feedtype, $model)
{
$feed_data = array();
$feed_data['usecustomsearch'] = '';
$feed_data['showpast'] = '';
$feed_data['customsearch'] = '';
$feed_data['api_key'] = '';
$feed_data['type'] = $feedtype;
$feed_data['channel'] = $model['channel'];
$feed_data['playlist'] = $model['playlist'];
$feed_data['favorites'] = $model['favorites'];
$feed_data['search'] = $model['search'];
$feed_data['live'] = $model['live'];
$feed_data['single'] = $model['single'];
$feed_data['caching_type'] = 'page';
$feed_data['caching_time'] = 1;
$feed_data['caching_time_unit'] = 'hours';
$feed_data['cache_cron_interval'] = '30mins';
$feed_data['cache_cron_time'] = 0;
$feed_data['cache_cron_am_pm'] = 'am';
return $feed_data;
}
/**
* Used to retrieve Feed Posts for preview screen
* Returns Feed info or false!
*
* @since 2.0
*/
public static function feed_customizer_fly_preview()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
if (isset($_POST['feedID']) && isset($_POST['previewSettings'])) {
$feed_id = $_POST['feedID'];
$preview_settings = SBY_Parse::parse_quoted_string_as_boolean($_POST['previewSettings']);
$feed_name = $_POST['feedName'];
$preview_settings = isset($_POST['isFeedTemplatesPopup']) ? SBY_Feed_Templates_Settings::get_feed_settings_by_feed_templates($preview_settings) + $preview_settings : $preview_settings;
$feed_saver = new SBY_Feed_Saver($feed_id);
$feed_saver->set_feed_name($feed_name);
$feed_saver->set_data($preview_settings);
if (isset($_POST['clearCache']) && $_POST['clearCache'] == true) {
sby_clear_cache();
}
$atts = Feed_Builder::add_customizer_att(
array(
'feed' => $feed_id,
'customizer' => true,
)
);
//Fixes Carousel preview issue.
$only_preview = self::carousel_column_preview($_POST['previewScreen'],$preview_settings);
$shortcode = new ShortcodeService();
$feed_output = $shortcode->sby_youtube_feed($atts, $only_preview);
$return['feed_html'] = $feed_output['feedInitOutput'];
;
$return['customizerDataSettings'] = $preview_settings;
echo json_encode($return);
}
wp_die();
}
/**
* Used to feed handle for preview screen
* Returns Feed info or false!
*
* @since 2.0
*/
public static function feed_customizer_feed_handle_fly_preview()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
if (isset($_POST['feedID']) && isset($_POST['previewSettings'])) {
$feed_id = $_POST['feedID'];
$preview_settings = SBY_Parse::parse_quoted_string_as_boolean($_POST['previewSettings']);
$feed_name = $_POST['feedName'];
$feed_type = $_POST['feedType'];
$preview_settings = isset($_POST['isFeedTemplatesPopup']) ? SBY_Feed_Templates_Settings::get_feed_settings_by_feed_templates($preview_settings) + $preview_settings : $preview_settings;
$preview_settings = self::filter_feed_model_data($preview_settings, $feed_type);
$feed_saver = new SBY_Feed_Saver($feed_id);
$feed_saver->set_feed_name($feed_name);
$feed_saver->set_data($preview_settings);
if (isset($_POST['clearCache']) && $_POST['clearCache'] == true) {
sby_clear_cache();
}
$atts = Feed_Builder::add_customizer_att(
array(
'feed' => $feed_id,
'customizer' => true,
)
);
$shortcode = new ShortcodeService();
$feed_output = $shortcode->sby_youtube_feed($atts, $preview_settings);
$return['feed_html'] = $feed_output['feedInitOutput'];
;
$return['customizerDataSettings'] = $preview_settings;
echo json_encode($return);
}
wp_die();
}
/**
* Used in an AJAX call to duplicate a Feed
* $_POST data.
*
* @since 2.0
*/
public static function duplicate_feed()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
if (! empty($_POST['feed_id'])) {
DB::duplicate_feed_query($_POST['feed_id']);
}
}
/**
* Used in an AJAX call to delete feeds from the Database
* $_POST data.
*
* @since 2.0
*/
public static function delete_feed()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
if (! empty($_POST['feeds_ids']) && is_array($_POST['feeds_ids'])) {
DB::delete_feeds_query($_POST['feeds_ids']);
}
}
/**
* Create Feed Name
* This will create the feed name when creating new Feeds
*
* @since 2.0
*/
public static function create_feed_name($selected_feed, $selected_feed_models)
{
$feed_name = 'YouTube Feed';
if ($selected_feed) {
$feed_name .= ' - ' . ucfirst($selected_feed);
}
return DB::feeds_query_name($feed_name);
}
/**
* Used to dismiss onboarding using AJAX
*
* @since 2.0
*/
public static function after_dismiss_onboarding()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
$type = 'newuser';
if (isset($_POST['was_active'])) {
$type = sanitize_text_field($_POST['was_active']);
}
Feed_Builder::update_onboarding_meta('dismissed', $type);
wp_die();
}
/**
* Used in an AJAX call to delete a feed cache from the Database
* $_POST data.
*
* @since 2.0
*/
public static function feed_refresh()
{
check_ajax_referer('sby-admin', 'nonce');
if (! sby_current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
$feed_id = sanitize_key($_POST['feedID']);
sby_clear_cache();
self::feed_customizer_fly_preview();
wp_die();
}
/**
* Filter feed model data
*
* @since 2.2
*/
public static function filter_feed_model_data($feed_data, $feedtype)
{
if ($feedtype == 'channel') {
$channel = $feed_data['channel'];
} elseif ($feedtype == 'favorites') {
$channel = $feed_data['favorites'];
} elseif ($feedtype == 'live') {
$channel = $feed_data['live'];
}
$channel_id = '';
$channel_url = '';
if (strpos($channel, '@') !== false && ( strpos($channel, 'https://') !== false || strpos($channel, 'http://') !== false )) {
$channel_url = $channel;
} elseif (strpos($channel, '@') !== false) {
$channel_url = 'https://www.youtube.com/' . $channel;
}
if ($channel_url) {
$saved_channel_id = Util::get_saved_channel_id($channel);
if (! $saved_channel_id) {
$channel_id = Util::get_channel_id_by_api_request($channel_url);
} else {
$channel_id = $saved_channel_id;
}
} else {
$channel_id = $channel;
}
if ($feedtype == 'channel') {
$feed_data['channel'] = $channel_id;
} elseif ($feedtype == 'favorites') {
$feed_data['favorites'] = $channel_id;
} elseif ($feedtype == 'live') {
$feed_data['live'] = $channel_id;
}
return $feed_data;
}
/**
* Determines what table and sanitization should be used
* when handling feed setting data.
*
* TODO: Add settings that need something other than sanitize_text_field
*
* @param string $key
*
* @return array
*
* @since 2.0
*/
public static function get_data_type($key)
{
switch ($key) {
case 'sources':
$return = array(
'table' => 'feed_settings',
'sanitization' => 'sanitize_text_field',
);
break;
case 'feed_title':
$return = array(
'table' => 'feeds',
'sanitization' => 'sanitize_text_field',
);
break;
case 'feed_name':
$return = array(
'table' => 'feeds',
'sanitization' => 'sanitize_text_field',
);
break;
case 'status':
$return = array(
'table' => 'feeds',
'sanitization' => 'sanitize_text_field',
);
break;
case 'author':
$return = array(
'table' => 'feeds',
'sanitization' => 'int',
);
break;
default:
$return = array(
'table' => 'feed_settings',
'sanitization' => 'sanitize_text_field',
);
break;
}
return $return;
}
/**
* Check if boolean
* for a value
*
* @param string $type
* @param int|string $value
*
* @return int|string
*
* @since 2.0
*/
public static function is_boolean($value)
{
return ( $value === 'true' || $value === 'false' || is_bool($value) ) ? true : false;
}
public static function cast_boolean($value)
{
if ($value === 'true' || $value === true || $value === 'on') {
return true;
}
return false;
}
/**
* Uses the appropriate sanitization function and returns the result
* for a value
*
* @param string $type
* @param int|string $value
*
* @return int|string
*
* @since 2.0
*/
public static function sanitize($type, $value)
{
switch ($type) {
case 'int':
$return = intval($value);
break;
case 'boolean':
$return = self::cast_boolean($value);
break;
default:
$return = sanitize_text_field(wp_unslash($value));
break;
}
return $return;
}
/**
* Clear comments cache AJAX call
*
* @return void
*
* @since 2.3.3
*/
public static function clear_comments_cache()
{
check_ajax_referer('sby-admin', 'nonce');
if (! current_user_can('manage_youtube_feed_options')) {
wp_send_json_error();
}
delete_transient('sby_comment_cache');
echo 'success';
wp_die();
}
/**
* Carousel Column Preview.
*
* @param string $preview_screen
* @param array $preview_settings
* @return array
*
* @since 2.3.4
*/
public static function carousel_column_preview($preview_screen, $preview_settings) {
// Return if preview_settings does not exist.
if(empty($preview_settings)) {
return $preview_settings;
}
$layout = !empty($preview_settings['layout']) ? $preview_settings['layout'] : '';
// As we do not use iframe owl slider still thinks that it's in desktop mode ( on mobile view inside preview ). So we just intercepted the desktop value with the mobile one to simulate the desired behavior.
if( !empty( $preview_screen ) && 'mobile' === $preview_screen && 'carousel' === $layout ) {
$preview_settings['cols'] = $preview_settings['colsmobile'];
}
return $preview_settings;
}
}

View File

@@ -0,0 +1,359 @@
<?php
/**
* The Feed Templates Settings Class
*
* It has the default settings for the feed templates for various feed types
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder;
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class SBY_Feed_Templates_Settings {
/**
* Add feed settings depending on feed templates
*
* @since 4.2.0
*/
public static function get_feed_settings_by_feed_templates( $settings ) {
// Check if the feedtype is timelime/posts
if ( $settings['feedtemplate'] == 'default' ) {
$settings = self::get_default_feedtemplate_settings( $settings );
}
if ( $settings['feedtemplate'] == 'carousel' ) {
$settings = self::get_carousel_feedtemplate_settings( $settings );
}
if ( $settings['feedtemplate'] == 'cards' ) {
$settings = self::get_cards_feedtemplate_settings( $settings );
}
if ( $settings['feedtemplate'] == 'list' ) {
$settings = self::get_list_feedtemplate_settings( $settings );
}
if ( $settings['feedtemplate'] == 'gallery' ) {
$settings = self::get_gallery_feedtemplate_settings( $settings );
}
if ( $settings['feedtemplate'] == 'latest_video' ) {
$settings = self::get_latest_video_feedtemplate_settings( $settings );
}
if ( $settings['feedtemplate'] == 'showcase_carousel' ) {
$settings = self::get_showcase_carousel_feedtemplate_settings( $settings );
}
if ( $settings['feedtemplate'] == 'widget' ) {
$settings = self::get_widget_feedtemplate_settings( $settings );
}
return $settings;
}
/**
* Feed settings for default template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_default_feedtemplate_settings( $settings ) {
$settings['layout'] = 'grid';
$settings['cols'] = '3';
$settings['colsmobile'] = '1';
$settings['num'] = '9';
$settings['itemspacing'] = '5';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = false;
$settings['videocardstyle'] = 'regular';
$settings = self::enable_comments_for_template( $settings, true );
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
return $settings;
}
/**
* Feed settings for carousel template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_carousel_feedtemplate_settings( $settings ) {
$settings = self::get_default_carousel_settings( $settings );
$settings['cols'] = '3';
$settings['colsmobile'] = '1';
$settings['num'] = '9';
$settings['itemspacing'] = '5';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = true;
$settings['headerstyle'] = 'text';
$settings['customheadertext'] = 'We are on YouTube';
$settings['customheadersize'] = 'medium';
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
$settings['videocardstyle'] = 'regular';
return $settings;
}
/**
* Feed settings for cards template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_cards_feedtemplate_settings( $settings ) {
$settings['layout'] = 'grid';
$settings['cols'] = '3';
$settings['colsmobile'] = '1';
$settings['num'] = '9';
$settings['itemspacing'] = '8';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = true;
$settings['headerstyle'] = 'text';
$settings['customheadertext'] = 'We are on YouTube';
$settings['customheadersize'] = 'medium';
$settings['videocardstyle'] = 'boxed';
$settings['boxedbgcolor'] = '#ffffff';
$settings['boxborderradius'] = '4';
$settings['enableboxshadow'] = true;
$settings = self::enable_comments_for_template( $settings, true );
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
return $settings;
}
/**
* Feed settings for lists template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_list_feedtemplate_settings( $settings ) {
$settings['layout'] = 'list';
$settings['num'] = '2';
$settings['itemspacing'] = '5';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = true;
$settings['headerstyle'] = 'standard';
$settings['videocardstyle'] = 'regular';
$settings = self::enable_comments_for_template( $settings, false );
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
return $settings;
}
/**
* Feed settings for gallery template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_gallery_feedtemplate_settings( $settings ) {
$settings['layout'] = 'gallery';
$settings['cols'] = '3';
$settings['colsmobile'] = '1';
$settings['num'] = '6';
$settings['itemspacing'] = '5';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = false;
$settings['videocardstyle'] = 'regular';
$settings = self::enable_comments_for_template( $settings, false );
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
return $settings;
}
/**
* Feed settings for latest_video template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_latest_video_feedtemplate_settings( $settings ) {
$settings['layout'] = 'list';
$settings['num'] = '1';
$settings['itemspacing'] = '5';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = true;
$settings['videocardstyle'] = 'regular';
$settings = self::enable_comments_for_template( $settings, true );
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
return $settings;
}
/**
* Feed settings for showcase carousel template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_showcase_carousel_feedtemplate_settings( $settings ) {
$settings = self::get_default_carousel_settings( $settings );
$settings['cols'] = '1';
$settings['colsmobile'] = '1';
$settings['num'] = '3';
$settings['itemspacing'] = '5';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = true;
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
$settings['videocardstyle'] = 'regular';
return $settings;
}
/**
* Feed settings for widget template type
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_widget_feedtemplate_settings( $settings ) {
$settings['layout'] = 'list';
$settings['num'] = '2';
$settings['itemspacing'] = '5';
$settings['colorpalette'] = 'inherit';
$settings['showheader'] = false;
$settings['videocardstyle'] = 'regular';
$settings = self::get_default_loadmore_button_settings( $settings );
$settings = self::get_default_subscribe_button_settings( $settings );
$settings = self::enable_comments_for_template( $settings, false );
return $settings;
}
/**
* Default settings for carousel settings
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_default_carousel_settings( $settings ) {
$settings['layout'] = 'carousel';
$settings['carouselrows'] = 1;
$settings['carouselloop'] = 'rewind';
$settings['carouseltime'] = '3000';
$settings['carouselarrows'] = true;
$settings['carouselpag'] = true;
$settings['carouselautoplay'] = true;
$settings = self::enable_comments_for_template( $settings, true );
return $settings;
}
/**
* Default settings for load more button
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_default_loadmore_button_settings( $settings ) {
$settings['showbutton'] = true;
$settings['buttoncolor'] = '';
$settings['buttonhovercolor'] = '';
$settings['buttontextcolor'] = '';
return $settings;
}
/**
* Default settings for subscribe button
*
* @since 2.0
*
* @param array $settings
* @return array $settings
*/
public static function get_default_subscribe_button_settings( $settings ) {
$settings['showsubscribe'] = true;
$settings['subscribecolor'] = '';
$settings['subscribehovercolor'] = 'rgb(255, 255, 255, .25)';
$settings['subscribetextcolor'] = '';
return $settings;
}
/**
* Enables comments for the template settings if the conditions are met.
*
* @since 2.3.3
*
* @param array $settings
* @param bool $flag
* @return array $settings
*/
private static function enable_comments_for_template($settings, $flag) {
if( sby_is_pro() && !sby_license_notices_active()) {
$settings['enablecomments'] = $flag;
}
return $settings;
}
}

View File

@@ -0,0 +1,846 @@
<?php
/**
* YouTube Feed Source
*
* @since 2.0
*
* Current Connected Account Data Example
*
*/
namespace SmashBalloon\YouTubeFeed\Builder;
use function DI\value;
class SBY_Source {
const BATCH_SIZE = 10;
/**
* AJAX hooks for various feed data related functionality
*
* @since 2.0
*/
public static function hooks() {
add_action( 'wp_ajax_sbi_source_builder_update', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Source', 'builder_update' ) );
add_action( 'wp_ajax_sbi_source_builder_update_multiple', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Source', 'builder_update_multiple' ) );
add_action( 'wp_ajax_sbi_source_get_page', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Source', 'get_page' ) );
add_action( 'wp_ajax_sbi_source_get_featured_post_preview', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Source', 'get_featured_post_preview' ) );
add_action( 'wp_ajax_sbi_source_get_playlist_post_preview', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Source', 'get_playlist_post_preview' ) );
add_action( 'admin_init', array( 'SmashBalloon\YouTubeFeed\Builder\SBY_Source', 'batch_process_legacy_source_queue' ) );
}
/**
* Used in an AJAX call to update sources based on selections or
* input from a user. Makes an API request to add additiona info
* about the connected source.
*
* @since 2.0
*/
public static function builder_update() {
if ( ! check_ajax_referer( 'sbi_admin_nonce' , 'nonce', false ) && ! check_ajax_referer( 'sby-admin' , 'nonce', false ) ) {
wp_send_json_error();
}
if ( ! sby_current_user_can( 'manage_instagram_feed_options' ) ) {
wp_send_json_error();
}
$source_data = array(
'access_token' => sanitize_text_field( $_POST['access_token'] ),
'id' => sanitize_text_field( $_POST['id'] ),
'type' => sanitize_text_field( $_POST['type'] ),
'username' => isset( $_POST['username'] ) ? sanitize_text_field( $_POST['username'] ) : '',
);
$return = sbi_connect_new_account( $source_data['access_token'], $source_data['id'] );
if ( empty( $return['error'] ) ) {
wp_send_json_success( SBI_Feed_Builder::get_source_list() );
}
wp_send_json_error( array( 'message' => $return['error'] ) );
}
/**
* Add our update a source from raw API data.
*
* @param $source_data
*
* @return string
*/
public static function process_connecting_source_data( $source_data ) {
$connected_account = array(
'id' => $source_data['id'],
'user_id' => $source_data['id'],
'type' => $source_data['type'],
'account_type' => $source_data['type'],
'username' => $source_data['username'],
'access_token' => $source_data['access_token'],
'privilege' => $source_data['privilege'],
);
$single_source = self::update_single_source( $connected_account, false );
if ( ! empty( $single_source['error'] ) ) {
$message = ! empty( $single_source['error']['error']['message'] ) ? esc_html( $single_source['error']['error']['message'] ) : '';
$code = ! empty( $single_source['error']['error']['code'] ) ? esc_html( $single_source['error']['error']['code'] ) : '';
if ( isset( $single_source['error']['response'] ) && is_wp_error( $single_source['error']['response'] ) ) {
$response = $single_source['error']['response'];
$message = sprintf( __( 'Error connecting to %s.', 'feeds-for-youtube' ), $single_source['error']['url'] );
if ( isset( $response ) && isset( $response->errors ) ) {
foreach ( $response->errors as $key => $item ) {
$code = $key;
$message .= $item[0];
}
}
}
$message .= ' <a href="https://smashballoon.com/instagram-feed/docs/errors/" target="_blank" rel="noopener">' . __( 'Directions on how to resolve this issue', 'feeds-for-youtube' ) . '</a>';
$return_html = '<div class="sb-alerts-wrap"><div class="sb-alert">';
$return_html .= '<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">';
$return_html .= '<path d="M8.99935 0.666504C4.39935 0.666504 0.666016 4.39984 0.666016 8.99984C0.666016 13.5998 4.39935 17.3332 8.99935 17.3332C13.5993 17.3332 17.3327 13.5998 17.3327 8.99984C17.3327 4.39984 13.5993 0.666504 8.99935 0.666504ZM9.83268 13.1665H8.16602V11.4998H9.83268V13.1665ZM9.83268 9.83317H8.16602V4.83317H9.83268V9.83317Z" fill="#995C00"/>';
$return_html .= '</svg>';
$return_html .= '<span><strong>' . sprintf( __( 'Connection Error: %s ', 'feeds-for-youtube' ), $code ) . '</strong></span><br>' . $message . '</div></div>';
$return = array(
'success' => false,
'message' => $return_html,
);
return json_encode( $return );
} else {
global $sb_instagram_posts_manager;
$sb_instagram_posts_manager->remove_error( 'connection' );
}
$manager = new \SB_Instagram_Data_Manager();
$manager->update_last_used();
return json_encode( SBI_Feed_Builder::get_source_list() );
}
/**
* Used in an AJAX call to update Multiple sources based on selections or
* input from a user. Makes an API request to add additiona info
* about the connected source.
*
* @since 2.0
*/
public static function builder_update_multiple() {
if ( ! check_ajax_referer( 'sbi_admin_nonce' , 'nonce', false ) && ! check_ajax_referer( 'sby-admin' , 'nonce', false ) ) {
wp_send_json_error();
}
if ( ! sby_current_user_can( 'manage_instagram_feed_options' ) ) {
wp_send_json_error();
}
if ( isset( $_POST['sourcesList'] ) && ! empty( $_POST['sourcesList'] ) && is_array( $_POST['sourcesList'] ) ) {
foreach ( $_POST['sourcesList'] as $single_source ) :
$source_data = array(
'access_token' => sanitize_text_field( $single_source['access_token'] ),
'id' => sanitize_text_field( $single_source['id'] ),
'type' => sanitize_text_field( $single_source['type'] ),
'username' => isset( $single_source['username'] ) ? sanitize_text_field( $single_source['username'] ) : '',
);
if ( $single_source['type'] === 'business' ) {
$source_data['privilege'] = 'tagged';
}
if ( ! empty( $single_source['name'] ) ) {
$source_data['name'] = sanitize_text_field( $single_source['name'] );
}
self::process_connecting_source_data( $source_data );
endforeach;
}
echo json_encode( SBI_Feed_Builder::get_source_list() );
wp_die();
}
/**
* Get a list of sources with a limit and offset like a page
*
* @since 2.0
*/
public static function get_page() {
if ( ! check_ajax_referer( 'sbi_admin_nonce' , 'nonce', false ) && ! check_ajax_referer( 'sby-admin' , 'nonce', false ) ) {
wp_send_json_error();
}
if ( ! sby_current_user_can( 'manage_instagram_feed_options' ) ) {
wp_send_json_error();
}
$args = array( 'page' => $_POST['page'] );
$source_data = SBI_Db::source_query( $args );
echo json_encode( $source_data );
wp_die();
}
/**
* Connection URLs are based on the website connecting accounts so that is
* configured here and returned
*
* @param bool $is_settings
*
* @return array
*
* @since 2.0
*/
public static function get_connection_urls( $is_settings = false ) {
$urls = array();
$admin_url_state = $is_settings ? admin_url( 'admin.php?page=sby-feed-builder-settings' ) : admin_url( 'admin.php?page=sbi-feed-builder' );
//If the admin_url isn't returned correctly then use a fallback
if ( $admin_url_state === '/wp-admin/admin.php?page=sbi-feed-builder'
|| $admin_url_state === '/wp-admin/admin.php?page=sbi-feed-builder&tab=configuration' ) {
$admin_url_state = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
}
#$urls['personal'] ='https://connect.smashballoon.com/auth/ig/?wordpress_user=&v=pro&vn=' . SBYVER . '&state=';
#$urls['business'] = 'https://connect.smashballoon.com/auth/ig/?wordpress_user=&v=pro&vn=' . SBYVER . '&state=';
$urls['personal'] ='https://connect.smashballoon.com/auth/ig/?wordpress_user=&v=pro&vn=' . SBYVER;
$urls['business'] = 'https://connect.smashballoon.com/auth/ig/?wordpress_user=&v=pro&vn=' . SBYVER;
$urls['stateURL'] = $admin_url_state;
return $urls;
}
/**
* Used as a listener for the account connection process. If
* data is returned from the account connection processed it's used
* to generate the list of possible sources to chose from.
*
* @return array|bool
*
* @since 2.0
*/
public static function maybe_source_connection_data() {
if ( isset( $_GET['sbi_access_token'] ) && isset( $_GET['sbi_graph_api'] ) ) {
$return = self::retrieve_available_business_accounts();
return $return;
} elseif ( isset( $_GET['sbi_access_token'] ) && isset( $_GET['sbi_account_type'] ) ) {
$return = self::retrieve_available_personal_accounts();
return $return;
}
return false;
}
/**
* Uses the Instagram Basic Display API to get available personal
* accounts
*
* @return array|bool
*
* @since 2.0
*/
public static function retrieve_available_personal_accounts() {
$encryption = new \SB_Instagram_Data_Encryption();
$return = array(
'type' => 'personal',
'unconnectedAccounts' => array(),
'matchingExistingAccounts' => array(),
'didQuickUpdate' => false,
);
$access_token = sanitize_text_field( $_GET['sbi_access_token'] );
if ( empty( $access_token ) ) {
return array();
}
$user_id = sanitize_text_field( $_GET['sbi_id'] );
$user_name = sanitize_text_field( $_GET['sbi_username'] );
$expires_in = (int) $_GET['sbi_expires_in'];
$expires_timestamp = time() + $expires_in;
$source_data = array(
'access_token' => $access_token,
'id' => $user_id,
'user_id' => $user_id,
'type' => 'basic',
'username' => $user_name,
'privilege' => '',
'expires' => date( 'Y-m-d H:i:s', $expires_timestamp ),
);
$connection = new \SB_Instagram_API_Connect( $source_data, 'header', array() );
$connection->connect();
$header_details = '{}';
$source_data['error'] = '';
if ( ! $connection->is_wp_error() && ! $connection->is_instagram_error() ) {
$header_details_array = $connection->get_data();
$header_details_array = self::merge_account_details( $header_details_array, $source_data );
$source_data['username'] = $header_details_array['username'];
$header_details = json_encode( $header_details_array );
} else {
$source_data['error'] = $connection;
if ( $connection->is_wp_error() ) {
$page_error = $connection->get_wp_error();
if ( ! empty( $page_error ) && isset( $page_error['response']->errors ) ) {
$error_message = '';
foreach ( $page_error['response']->errors as $key => $item ) {
$error_message .= $key . ': ' . $item[0] . ' ';
}
return array(
'error' => array(
'code' => 'HTTP Request',
'message' => $error_message,
'details' => $error_message,
),
);
}
} else {
$error = $connection->get_data();
return array(
'error' => array(
'code' => $error['error']['code'],
'message' => $error['error']['message'],
'details' => $error['error']['message'],
),
);
}
}
$source_data['info'] = $header_details;
$return['unconnectedAccounts'][] = $source_data;
$args = array(
'id' => $user_id,
);
$results = SBI_Db::source_query( $args );
$already_connected_as_business_account = ( isset( $results[0] ) && $results[0]['account_type'] === 'business' );
$matches_existing_personal = ( isset( $results[0] ) && $results[0]['account_type'] === 'personal' );
if ( $already_connected_as_business_account ) {
$return['matchingExistingAccounts'] = $results[0];
$instagram_account_data = json_decode( $encryption->decrypt( $results[0]['info'] ), true );
$return['matchingExistingAccounts']['avatar'] = isset( $instagram_account_data['profile_picture_url'] ) ? $instagram_account_data['profile_picture_url'] : false;
$return['notice'] = __( 'The Instagram account you are logged into is already connected as a "business" account. Remove the business account if you\'d like to connect as a basic account instead (not recommended).', 'feeds-for-youtube' );
} elseif ( $matches_existing_personal ) {
$return['matchingExistingAccounts'] = $results[0];
self::update_or_insert( $source_data );
$return['notice'] = '';
$return['didQuickUpdate'] = true;
} else {
self::update_or_insert( $source_data );
$return['didQuickUpdate'] = true;
}
return $return;
}
/**
* Uses the Facebook API to retrieve a list of business accounts
*
* @return array|bool
*
* @since 2.0
*/
public static function retrieve_available_business_accounts() {
$return = array(
'type' => 'business',
'unconnectedAccounts' => array(),
'matchingExistingAccounts' => array(),
'didQuickUpdate' => false,
);
$access_token = sbi_maybe_clean( urldecode( $_GET['sbi_access_token'] ) );
if ( empty( $access_token ) ) {
return array();
}
$url = 'https://graph.facebook.com/me/accounts?fields=instagram_business_account,access_token&limit=500&access_token=' . $access_token;
$args = array(
'timeout' => 60,
);
$result = wp_remote_get( $url, $args );
$pages_data = '{}';
if ( ! is_wp_error( $result ) ) {
$pages_data = $result['body'];
} else {
$page_error = $result;
}
if ( isset( $page_error ) && isset( $page_error->errors ) ) {
$error_message = '';
foreach ( $page_error->errors as $key => $item ) {
$error_message .= $key . ': ' . $item[0] . ' ';
}
return array(
'error' => array(
'code' => 'HTTP Request',
'message' => __( 'Your server could not complete a remote request to Facebook\'s API. Your host may be blocking access or there may be a problem with your server.', 'feeds-for-youtube' ),
'details' => $error_message,
),
);
}
$pages_data_arr = json_decode( $pages_data, true );
if ( empty( $pages_data_arr['data'] ) ) {
return array(
'error' => array(
'code' => 'No Accounts Found',
'message' => __( 'Couldn\'t find Business Profile', 'feeds-for-youtube' ),
'details' => sprintf( __( 'Uh oh. It looks like this Facebook account is not currently connected to an Instagram Business profile. Please check that you are logged into the %1$sFacebook account%2$s in this browser which is associated with your Instagram Business Profile.', 'feeds-for-youtube' ), '<a href="https://www.facebook.com/" target="_blank" rel="noopener noreferrer">', '</a>' ),
),
);
}
$user_url = 'https://graph.facebook.com/me?fields=name,id,picture&access_token=' . $access_token;
$args = array(
'timeout' => 60,
);
$result = wp_remote_get( $user_url, $args );
if ( ! is_wp_error( $result ) ) {
$user_data = $result['body'];
$user_data_arr = json_decode( $user_data, true );
$return['user'] = $user_data_arr;
}
$return['numFound'] = count( $pages_data_arr['data'] );
foreach ( $pages_data_arr['data'] as $page_data ) {
if ( isset( $page_data['instagram_business_account'] ) ) {
$instagram_business_id = $page_data['instagram_business_account']['id'];
$page_access_token = isset( $page_data['access_token'] ) ? $page_data['access_token'] : '';
$instagram_account_url = 'https://graph.facebook.com/' . $instagram_business_id . '?fields=name,username,profile_picture_url&access_token=' . $access_token;
$args = array(
'timeout' => 60,
);
$result = wp_remote_get( $instagram_account_url, $args );
if ( ! is_wp_error( $result ) ) {
$instagram_account_info = $result['body'];
$instagram_account_data = json_decode( $instagram_account_info, true );
$instagram_biz_img = isset( $instagram_account_data['profile_picture_url'] ) ? $instagram_account_data['profile_picture_url'] : false;
$source_data = array(
'access_token' => $access_token,
'id' => $instagram_business_id,
'user_id' => $instagram_business_id,
'type' => 'business',
'username' => $instagram_account_data['username'],
'avatar' => $instagram_biz_img,
'privilege' => 'tagged',
);
$source_data['info'] = json_encode( $instagram_account_data );
$return['unconnectedAccounts'][] = $source_data;
$args = array(
'id' => $instagram_business_id,
);
$results = SBI_Db::source_query( $args );
$already_connected_as_business_account = ( isset( $results[0] ) && $results[0]['account_type'] === 'business' );
$matches_existing_personal = ( isset( $results[0] ) && $results[0]['account_type'] === 'personal' );
if ( $already_connected_as_business_account ) {
self::update_or_insert( $source_data );
} elseif ( $matches_existing_personal && $return['numFound'] === 1 ) {
$return['didQuickUpdate'] = true;
self::update_or_insert( $source_data );
}
} else {
$page_error = $result;
}
}
}
if ( empty( $return['unconnectedAccounts'] ) ) {
return array(
'error' => array(
'code' => 'No Accounts Found',
'message' => __( 'Couldn\'t find Business Profile', 'feeds-for-youtube' ),
'details' => sprintf( __( 'Uh oh. It looks like this Facebook account is not currently connected to an Instagram Business profile. Please check that you are logged into the %1$sFacebook account%2$s in this browser which is associated with your Instagram Business Profile. If you are, in fact, logged-in to the correct account please make sure you have Instagram accounts connected with your Facebook account by following %3$sthis FAQ%4$s', 'feeds-for-youtube' ), '<a href="https://www.facebook.com/" target="_blank" rel="noopener noreferrer">', '</a>', '<a href="https://smashballoon.com/reconnecting-an-instagram-business-profile/" target="_blank" rel="noopener noreferrer">', '</a>' ),
),
);
}
return $return;
}
/**
* Used to update or insert connected accounts (sources)
*
* @param array $source_data
*
* @return bool
*
* @since 2.0
*/
public static function update_or_insert( $source_data ) {
if ( ! isset( $source_data['id'] ) ) {
return false;
}
if ( isset( $source_data['info'] ) ) {
// data from an API request related to the source is saved as a JSON string
if ( is_object( $source_data['info'] ) || is_array( $source_data['info'] ) ) {
$source_data['info'] = json_encode( $source_data['info'] );
}
}
if ( self::exists_in_database( $source_data ) ) {
$source_data['last_updated'] = date( 'Y-m-d H:i:s' );
self::update( $source_data, false );
} else {
if ( ! isset( $source_data['access_token'] ) ) {
return false;
}
self::insert( $source_data );
}
return true;
}
/**
* Whether or not the source exists in the database
*
* @param array $args
*
* @return bool
*
* @since 2.0
*/
public static function exists_in_database( $args ) {
$results = SBI_Db::source_query( $args );
return isset( $results[0] );
}
/**
* Add a new source as a row in the sbi_sources table
*
* @param array $source_data
*
* @return false|int
*
* @since 2.0
*/
public static function insert( $source_data ) {
if ( isset( $source_data['name'] ) ) {
$source_data['username'] = $source_data['name'];
}
$data = $source_data;
return SBI_Db::source_insert( $data );
}
/**
* Update info in rows that match the source data
*
* @param array $source_data
*
* @return false|int
*
* @since 2.0
*/
public static function update( $source_data, $where_privilige = true ) {
$where = array( 'id' => $source_data['id'] );
unset( $source_data['id'] );
if ( $where_privilige && isset( $source_data['privilege'] ) ) {
$where['privilege'] = $source_data['privilege'];
}
// usernames are more common in the other plugins so
// that is the name of the column that is used as the
// page or group "name" data
if ( isset( $source_data['name'] ) ) {
$source_data['username'] = $source_data['name'];
}
$data = $source_data;
return SBI_Db::source_update( $data, $where );
}
/**
* Creates a queue of connected accounts that need to be added to
* the sources table
*
* @since 2.0
*/
public static function set_legacy_source_queue() {
$sbi_statuses_option = get_option( 'sbi_statuses', array() );
$options = get_option( 'sb_instagram_settings', array() );
$connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
$sbi_statuses_option['legacy_source_queue'] = array_chunk( array_keys( $connected_accounts ), self::BATCH_SIZE );
update_option( 'sbi_statuses', $sbi_statuses_option );
return $sbi_statuses_option['legacy_source_queue'];
}
/**
* Whether or not there are still sources in the queue and
* this isn't disabled
*
* @return bool
*
* @since 2.0
*/
public static function should_do_source_updates() {
$sbi_statuses_option = get_option( 'sbi_statuses', array() );
$should_do_source_updates = isset( $sbi_statuses_option['legacy_source_queue'] ) ? ! empty( $sbi_statuses_option['legacy_source_queue'] ) : false;
return apply_filters( 'should_do_source_updates', $should_do_source_updates );
}
/**
* Processes one set of connected accounts
*
* @since 2.0
*/
public static function batch_process_legacy_source_queue() {
if ( ! self::should_do_source_updates() ) {
return;
}
$sbi_statuses_option = get_option( 'sbi_statuses', array() );
$batch = array_shift( $sbi_statuses_option['legacy_source_queue'] );
update_option( 'sbi_statuses', $sbi_statuses_option ); // updated early just in case there is a fatal error
if ( empty( $batch ) ) {
return;
}
$options = get_option( 'sb_instagram_settings', array() );
$connected_accounts = isset( $options['connected_accounts'] ) ? $options['connected_accounts'] : array();
foreach ( $batch as $account_key ) {
$connected_account = isset( $connected_accounts[ $account_key ] ) ? $connected_accounts[ $account_key ] : false;
if ( $connected_account ) {
self::update_single_source( $connected_account );
}
}
return $sbi_statuses_option['legacy_source_queue'];
}
/**
* Transfer data from a connected account to the sources table
* after it's been validated with an API call
*
* @param array $connected_account
* @param bool $connect_if_error
*
* @return array
*
* @since 2.0
*/
public static function update_single_source( $connected_account, $connect_if_error = true ) {
$account_type = isset( $connected_account['account_type'] ) ? $connected_account['account_type'] : 'business';
$connection = new \SB_Instagram_API_Connect( $connected_account, 'header', array() );
$connection->connect();
if ( isset( $connected_account['privilege'] ) && $connected_account['privilege'] === 'tagged' ) {
$connected_account['use_tagged'] = true;
}
$source_data = array(
'access_token' => $connected_account['access_token'],
'id' => $connected_account['user_id'],
'type' => $account_type,
'username' => $connected_account['username'],
'privilege' => ! empty( $connected_account['use_tagged'] ) ? 'tagged' : '',
);
if ( ! empty( $connected_account['expires_timestamp'] ) ) {
$source_data['expires'] = date( 'Y-m-d H:i:s', $connected_account['expires_timestamp'] );
}
if ( $connected_account['local_avatar'] ) {
\SB_Instagram_Connected_Account::update_local_avatar_status( $connected_account['username'], true );
}
$header_details = '{}';
$source_data['error'] = '';
if ( ! $connection->is_wp_error() && ! $connection->is_instagram_error() ) {
$header_details_array = $connection->get_data();
$header_details_array = self::merge_account_details( $header_details_array, $connected_account );
$cdn_avatar_url = \SB_Instagram_Parse::get_avatar( $header_details_array, array(), true );
if ( ! empty( $cdn_avatar_url ) ) {
$created = \SB_Instagram_Connected_Account::create_local_avatar( $header_details_array['username'], $cdn_avatar_url );
\SB_Instagram_Connected_Account::update_local_avatar_status( $header_details_array['username'], $created );
}
$source_data['username'] = $header_details_array['username'];
$header_details = json_encode( $header_details_array );
} else {
$source_data['error'] = $connection;
if ( $connection->is_wp_error() ) {
$source_data['error'] = $connection->get_wp_error();
} else {
$source_data['error'] = $connection->get_data();
}
}
$source_data['info'] = $header_details;
if ( ! empty( $connected_account['private'] ) ) {
$source_data['info']['private'] = $connected_account['private'];
}
if ( empty( $source_data['error'] ) || $connect_if_error ) {
self::update_or_insert( $source_data );
}
$source_data['record_id'] = 0;
$source_data['account_id'] = $connected_account['user_id'];
$source_data['account_type'] = $account_type;
return $source_data;
}
/**
* Creates a source from the access token and
* source ID saved in 3.x settings
*
* @since 2.0
*/
public static function update_source_from_legacy_settings() {
// not needed
}
public static function merge_account_details( $header_details_array, $connected_account ) {
$header_details_array['local_avatar'] = ! empty( $connected_account['local_avatar'] );
$header_details_array['name'] = ! empty( $connected_account['name'] ) ? $connected_account['name'] : '{}';
$header_details_array['page_access_token'] = ! empty( $connected_account['page_access_token'] ) ? $connected_account['page_access_token'] : '';
return $header_details_array;
}
/**
* If the plugin is still updating legacy sources this function
* can be used to udpate a single source if needed before
* the update is done.
*
* @param string $slug_or_id
*
* @return array|bool
*/
public static function maybe_one_off_connected_account_update( $slug_or_id ) {
if ( ! self::should_do_source_updates() ) {
return false;
}
$connected_accounts = (array) json_decode( stripcslashes( get_option( 'sbi_connected_accounts' ) ), true );
$connected_account = isset( $connected_accounts[ $slug_or_id ] ) ? $connected_accounts[ $slug_or_id ] : false;
if ( $connected_account ) {
return self::update_single_source( $connected_account );
}
return false;
}
/**
* Clears the "error" column in the sbi_sources table for a specific
* account
*
* @param string $account_id
*
* @return bool
*
* @since 2.0
*/
public static function clear_error( $account_id ) {
$source_data = array(
'id' => $account_id,
'error' => '',
);
return self::update_or_insert( $source_data );
}
/**
* Adds an error to the error table by account ID
*
* @param string $account_id
* @param string|object|array $error
*
* @return bool
*
* @since 2.0
*/
public static function add_error( $account_id, $error ) {
$source_data = array(
'id' => $account_id,
'error' => is_string( $error ) ? $error : json_encode( $error ),
);
return self::update_or_insert( $source_data );
}
/**
* Uses query results from the sbi_sources table to convert them
* into connected account data and return them as a connected account
* array as would be used in versions 5.x and below
*
* @param array $source_data
*
* @return array
*
* @since 2.0
*/
public static function convert_sources_to_connected_accounts( $source_data ) {
$encryption = new \SB_Instagram_Data_Encryption();
$connected_accounts = array();
foreach ( $source_data as $source_datum ) {
$info = ! empty( $source_datum['info'] ) ? json_decode( $encryption->decrypt( $source_datum['info'] ), true ) : array();
$settings = array( 'gdpr' => 'no' );
$avatar = \SB_Instagram_Parse::get_avatar( $info, $settings, true );
$connected_account = array(
'id' => $source_datum['account_id'],
'user_id' => $source_datum['account_id'],
'type' => $source_datum['account_type'],
'account_type' => $source_datum['account_type'],
'username' => $source_datum['username'],
'access_token' => sbi_maybe_clean( $source_datum['access_token'] ),
'privilege' => $source_datum['privilege'],
'expires_timestamp' => strtotime( $source_datum['expires'] ),
'is_valid' => empty( $source_datum['error'] ),
'profile_picture' => $avatar,
'last_checked' => isset( $source_datum['last_updated'] ) ? strtotime( $source_datum['last_updated'] ) : time(),
);
if ( ! empty( $info['private'] ) ) {
$connected_account['private'] = $info['private'];
}
$connected_account['local_avatar_url'] = \SB_Instagram_Connected_Account::maybe_local_avatar( $source_datum['username'], $avatar );
$connected_accounts[ $source_datum['account_id'] ] = $connected_account;
}
return $connected_accounts;
}
/**
* Returns a batch of accounts that have expiring access tokens
*
* @return array|bool
*
* @since 2.0
*/
public static function get_expiring() {
$args = array( 'expiring' => true );
$results = SBI_Db::source_query( $args );
return $results;
}
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Customizer Builder
*
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SB_Builder_Customizer {
/**
* Controls Classes Array
*
*
* @since 2.0
* @access private
*
* @var array
*/
public static $controls_classes = array();
/**
* Get controls list.
*
* Getting controls list
*
* @since 2.0
* @access public
*
* @return array
*/
public static function get_controls_list() {
return array(
'actionbutton',
'checkbox',
'checkboxsection',
'datepicker',
'colorpicker',
'number',
'select',
'switcher',
'text',
'textarea',
'toggle',
'toggleset',
'heading',
'separator',
'customview',
'coloroverride',
'togglebutton',
'hidden',
'imagechooser',
'checkboxlist',
);
}
/**
* Register Controls
*
* Including Control
*
* @since 2.0
* @access public
*
*/
public static function register_controls() {
$controls_list = self::get_controls_list();
foreach ( $controls_list as $control ) {
$controlClassName = 'SB_' . ucfirst( $control ) . '_Control';
$cls_name = __NAMESPACE__ . '\Controls\\' . $controlClassName;
$control_class = new $cls_name();
self::$controls_classes[ $control ] = $control_class;
}
}
/**
* Print Controls Vue JS Tempalte
*
* Including Control
*
* @since 2.0
* @access public
*
*/
public static function get_controls_templates( $editingType ) {
$controls_list = self::get_controls_list();
foreach ( $controls_list as $control ) {
self::$controls_classes[ $control ]->print_control_wrapper( $editingType );
}
}
}

View File

@@ -0,0 +1,143 @@
<?php
/**
* Builder Customizer Tab
*
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Tabs;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SBY_Builder_Customizer_Tab {
/**
* Get Tabs Data
*
*
* @since 2.0
* @access public
*
* @return array
*/
public static function get_customizer_tabs() {
return array(
'customize' => array(
'id' => 'customize',
'heading' => __( 'Customize', 'feeds-for-youtube' ),
'sections' => SBY_Customize_Tab::get_sections(),
),
'settings' => array(
'id' => 'settings',
'heading' => __( 'Settings', 'feeds-for-youtube' ),
'sections' => SBY_Settings_Tab::get_sections(),
),
);
}
/**
* Text Size Options
*
*
* @since 2.0
* @access public
*
* @return array
*/
public static function get_text_size_options() {
return array(
'inherit' => __( 'Inherit', 'feeds-for-youtube' ),
'10' => '10px',
'11' => '11px',
'12' => '12px',
'13' => '13px',
'14' => '14px',
'15' => '15px',
'16' => '16px',
'18' => '18px',
'20' => '20px',
'24' => '24px',
'28' => '28px',
'32' => '32px',
'36' => '36px',
'42' => '42px',
'48' => '48px',
'54' => '54px',
'60' => '60px',
);
}
/**
* header Icons Options
*
*
* @since 2.0
* @access public
*
* @return array
*/
public static function get_header_icons_options() {
return array(
'facebook-square' => 'Facebook 1',
'facebook' => 'Facebook 2',
'calendar' => 'Events 1',
'calendar-o' => 'Events 2',
'picture-o' => 'Photos',
'users' => 'People',
'thumbs-o-up' => 'Thumbs Up 1',
'thumbs-up' => 'Thumbs Up 2',
'comment-o' => 'Speech Bubble 1',
'comment' => 'Speech Bubble 2',
'ticket' => 'Ticket',
'list-alt' => 'News List',
'file' => 'File 1',
'file-o' => 'File 2',
'file-text' => 'File 3',
'file-text-o' => 'File 4',
'youtube-play ' => 'Video',
'youtube-play' => 'YouTube',
'vimeo-square' => 'Vimeo',
);
}
/**
* Date Format Options
*
*
* @since 2.0
* @access public
*
* @return array
*/
public static function get_date_format_options() {
$original = strtotime( '2016-07-25T17:30:00+0000' );
return array(
'1' => __( '2 days ago', 'feeds-for-youtube' ),
'2' => gmdate( 'F jS, g:i a', $original ),
'3' => gmdate( 'F jS', $original ),
'4' => gmdate( 'D F jS', $original ),
'5' => gmdate( 'l F jS', $original ),
'6' => gmdate( 'D M jS, Y', $original ),
'7' => gmdate( 'l F jS, Y', $original ),
'8' => gmdate( 'l F jS, Y - g:i a', $original ),
'9' => gmdate( "l M jS, 'y", $original ),
'10' => gmdate( 'm.d.y', $original ),
'18' => gmdate( 'm.d.y - G:i', $original ),
'11' => gmdate( 'm/d/y', $original ),
'12' => gmdate( 'd.m.y', $original ),
'19' => gmdate( 'd.m.y - G:i', $original ),
'13' => gmdate( 'd/m/y', $original ),
'14' => gmdate( 'd-m-Y, G:i', $original ),
'15' => gmdate( 'jS F Y, G:i', $original ),
'16' => gmdate( 'd M Y, G:i', $original ),
'17' => gmdate( 'l jS F Y, G:i', $original ),
'18' => gmdate( 'Y-m-d', $original ),
'custom' => __( 'Custom', 'feeds-for-youtube' ),
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,318 @@
<?php
/**
* Customizer Tab
*
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder\Tabs;
use SmashBalloon\YouTubeFeed\Builder\SBY_Feed_Builder;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class SBY_Settings_Tab {
/**
* Get Customize Tab Sections
*
*
* @since 2.0
* @access public
*
* @return array
*/
public static function get_sections() {
return array(
'settings_feedtype' => array(
'heading' => __( 'Sources', 'feeds-for-youtube' ),
'icon' => 'source',
'controls' => self::get_settings_sources_controls(),
),
'settings_filters_moderation' => array(
'heading' => __( 'Filters and Moderation', 'feeds-for-youtube' ),
'icon' => 'filter',
'separator' => 'none',
'controls' => self::get_settings_filters_moderation_controls(),
),
'settings_sort' => array(
'heading' => __( 'Sort', 'feeds-for-youtube' ),
'icon' => 'sort',
'controls' => self::get_settings_sort_controls(),
),
'settings_shoppable_feed' => array(
'heading' => __( 'Shoppable Feed', 'feeds-for-youtube' ),
'icon' => 'shop',
'separator' => 'none',
'controls' => self::get_settings_shoppable_feed_controls(),
),
'empty_sections' => array(
'heading' => '',
'isHeader' => true,
),
'settings_advanced' => array(
'heading' => __( 'Advanced', 'feeds-for-youtube' ),
'icon' => 'cog',
'controls' => self::get_settings_advanced_controls(),
),
);
}
/**
* Get Settings Tab Filters & Moderation Section
* @since 4.0
* @return array
*/
public static function get_settings_filters_moderation_controls() {
return array(
array(
'type' => 'customview',
'viewId' => 'moderationmode',
'switcher' => array(
'id' => 'enablemoderationmode',
'label' => __( 'Enable', 'feeds-for-youtube' ),
'reverse' => 'true',
'stacked' => 'true',
'labelStrong' => true,
'options' => array(
'enabled' => true,
'disabled' => false,
),
),
'moderationTypes' => array(
'allow' => array(
'label' => __( 'Allow List', 'feeds-for-youtube' ),
'description' => __( 'Hides post by default so you can select the ones you want to show', 'feeds-for-youtube' ),
),
'block' => array(
'label' => __( 'Block List', 'feeds-for-youtube' ),
'description' => __( 'Show all posts by default so you can select the ones you want to hide', 'feeds-for-youtube' ),
),
),
),
array(
'type' => 'separator',
'top' => 10,
'bottom' => 10,
'checkViewDisabled' => 'moderationMode',
),
array(
'type' => 'heading',
'strongHeading' => 'true',
'heading' => __( 'Filters', 'feeds-for-youtube' ),
'checkViewDisabled' => 'moderationMode',
),
array(
'type' => 'textarea',
'id' => 'includewords',
'heading' => __( 'Only show posts containing', 'feeds-for-youtube' ),
'tooltip' => __( 'Only show posts which contain certain words or hashtags in the caption. For example, adding "sheep, cow, dog" will show any photos which contain either the word sheep, cow, or dog. You can separate multiple words or hashtags using commas.', 'feeds-for-youtube' ),
'placeholder' => __( 'Add words here to only show posts containing these words', 'feeds-for-youtube' ),
'checkViewDisabled' => 'moderationMode',
),
array(
'type' => 'textarea',
'id' => 'excludewords',
'disabledInput' => true,
'heading' => __( 'Do not show posts containing', 'feeds-for-youtube' ),
'tooltip' => __( 'Remove any posts containing these text strings, separating multiple strings using commas.', 'feeds-for-youtube' ),
'placeholder' => __( 'Add words here to hide any posts containing these words', 'feeds-for-youtube' ),
'checkViewDisabled' => 'moderationMode',
),
array(
'type' => 'heading',
'strongHeading' => 'true',
'stacked' => 'true',
'heading' => __( 'Show specific types of posts', 'feeds-for-youtube' ),
'checkViewDisabled' => 'moderationMode',
),
array(
'type' => 'checkbox',
'id' => 'photosposts',
'label' => __( 'Photos', 'feeds-for-youtube' ),
'reverse' => 'true',
'stacked' => 'true',
'checkViewDisabled' => 'moderationMode',
'ajaxAction' => 'feedFlyPreview',
'options' => array(
'enabled' => true,
'disabled' => false,
),
),
array(
'type' => 'checkbox',
'id' => 'videosposts',
'label' => __( 'Feed Videos', 'feeds-for-youtube' ),
'reverse' => 'true',
'stacked' => 'true',
'checkViewDisabled' => 'moderationMode',
'ajaxAction' => 'feedFlyPreview',
'options' => array(
'enabled' => true,
'disabled' => false,
),
),
array(
'type' => 'checkbox',
'id' => 'igtvposts',
'label' => __( 'IGTV Videos', 'feeds-for-youtube' ),
'reverse' => 'true',
'stacked' => 'true',
'checkViewDisabled' => 'moderationMode',
'ajaxAction' => 'feedFlyPreview',
'options' => array(
'enabled' => true,
'disabled' => false,
),
),
array(
'type' => 'separator',
'top' => 26,
'bottom' => 15,
'checkViewDisabled' => 'moderationMode',
),
array(
'type' => 'number',
'id' => 'offset',
'strongHeading' => 'true',
'stacked' => 'true',
'placeholder' => '0',
'fieldSuffix' => 'posts',
'heading' => __( 'Post Offset', 'feeds-for-youtube' ),
'description' => __( 'This will skip the specified number of posts from displaying in the feed', 'feeds-for-youtube' ),
'checkViewDisabled' => 'moderationMode',
),
);
}
/**
* Get Settings Tab Sort Section
* @since 4.0
* @return array
*/
public static function get_settings_sort_controls() {
return array(
array(
'type' => 'toggleset',
'id' => 'sortby',
'heading' => __( 'Sort Posts by', 'feeds-for-youtube' ),
'strongHeading' => 'true',
'ajaxAction' => 'feedFlyPreview',
'options' => array(
array(
'value' => 'none',
'label' => __( 'Newest', 'feeds-for-youtube' ),
),
array(
'value' => 'likes',
'label' => __( 'Likes', 'feeds-for-youtube' ),
),
array(
'value' => 'random',
'label' => __( 'Random', 'feeds-for-youtube' ),
),
),
),
);
}
/**
* Get Settings Tab Shoppable Feed Section
* @since 4.0
* @return array
*/
public static function get_settings_shoppable_feed_controls() {
return array(
array(
'type' => 'switcher',
'id' => 'shoppablefeed',
'label' => __( 'Enable', 'feeds-for-youtube' ),
'reverse' => 'true',
'stacked' => 'true',
'options' => array(
'enabled' => true,
'disabled' => false,
),
),
array(
'type' => 'customview',
'condition' => array( 'shoppablefeed' => array( false ) ),
'conditionHide' => true,
'viewId' => 'shoppabledisabled',
),
array(
'type' => 'customview',
'condition' => array( 'shoppablefeed' => array( true ) ),
'conditionHide' => true,
'viewId' => 'shoppableenabled',
),
array(
'type' => 'customview',
'condition' => array( 'shoppablefeed' => array( true ) ),
'conditionHide' => true,
'viewId' => 'shoppableselectedpost',
),
);
}
/**
* Get Settings Tab Advanced Section
* @since 4.0
* @return array
*/
public static function get_settings_advanced_controls() {
return array(
array(
'type' => 'number',
'id' => 'maxrequests',
'strongHeading' => 'true',
'heading' => __( 'Max Concurrent API Requests', 'feeds-for-youtube' ),
'description' => __( 'Change the number of maximum concurrent API requests. Not recommended unless directed by the support team.', 'feeds-for-youtube' ),
),
array(
'type' => 'switcher',
'id' => 'customtemplates',
'label' => __( 'Custom Templates', 'feeds-for-youtube' ),
'description' => sprintf( __( 'The default HTML for the feed can be replaced with custom templates added to your theme\'s folder. Enable this setting to use these templates. Custom templates are not used in the feed editor. %1$sLearn More%2$s', 'feeds-for-youtube' ), '<a href="https://smashballoon.com/guide-to-creating-custom-templates/?utm_source=plugin-pro&utm_campaign=sbi&utm_medium=customizer" target="_blank">', '</a>' ),
'descriptionPosition' => 'bottom',
'reverse' => 'true',
'strongHeading' => 'true',
'labelStrong' => 'true',
'options' => array(
'enabled' => true,
'disabled' => false,
),
),
);
}
/**
* Get Settings TabSources Section
* @since 2.0
* @return array
*/
public static function get_settings_sources_controls() {
return array(
array(
'type' => 'customview',
'viewId' => 'sources',
),
);
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* SBY Tooltip Wizard
*
*
* @since 2.0
*/
namespace SmashBalloon\YouTubeFeed\Builder;
class Tooltip_Wizard {
/**
* Register component
*
* @since 2.0
*/
public function register() {
$this->hooks();
}
/**
* Register hooks.
*
* @since 2.0
*/
public function hooks() {
add_action( 'admin_enqueue_scripts', [ $this, 'enqueues' ] );
add_action( 'admin_footer', [ $this, 'output' ] );
}
/**
* Enqueue assets.
*
* @since 2.0
*/
public function enqueues() {
wp_enqueue_style(
'sby_tooltipster',
SBY_PLUGIN_URL . 'css/tooltipster.css',
null,
SBYVER
);
wp_enqueue_script(
'tooltipster',
SBY_PLUGIN_URL . 'js/jquery.tooltipster.min.js',
[ 'jquery' ],
SBYVER,
true
);
wp_enqueue_script(
'sby-admin-tooltip-wizard',
SBY_PLUGIN_URL . 'js/tooltip-wizard.js',
[ 'jquery' ],
SBYVER
);
$wp_localize_data = [];
if( $this->check_gutenberg_wizard() ){
$wp_localize_data['sby_wizard_gutenberg'] = true;
}
wp_localize_script(
'sby-admin-tooltip-wizard',
'sby_admin_tooltip_wizard',
$wp_localize_data
);
}
/**
* Output HTML.
*
* @since 2.0
*/
public function output() {
if( $this->check_gutenberg_wizard() ){
$this->gutenberg_tooltip_output();
}
}
/**
* Gutenberg Tooltip Output HTML.
*
* @since 2.0
*/
public function check_gutenberg_wizard() {
global $pagenow;
return ( ( $pagenow == 'post.php' ) || (get_post_type() == 'page') )
&& ! empty( $_GET['sby_wizard'] );
}
/**
* Gutenberg Tooltip Output HTML.
*
* @since 2.0
*/
public function gutenberg_tooltip_output() {
?>
<div id="sby-gutenberg-tooltip-content">
<div class="sby-tlp-wizard-cls sby-tlp-wizard-close"></div>
<div class="sby-tlp-wizard-content">
<strong class="sby-tooltip-wizard-head"><?php echo __('Add a Block','feeds-for-youtube') ?></strong>
<p class="sby-tooltip-wizard-txt"><?php echo __('Click the plus button, search for Feeds for YouTube','feeds-for-youtube'); ?>
<br/><?php echo __('Feed, and click the block to embed it.','feeds-for-youtube') ?> <a href="https://smashballoon.com/doc/wordpress-5-block-page-editor-gutenberg/?youtube" rel="noopener" target="_blank" rel="nofollow noopener"><?php echo __('Learn More','feeds-for-youtube') ?></a></p>
<div class="sby-tooltip-wizard-actions">
<button class="sby-tlp-wizard-close"><?php echo __('Done','feeds-for-youtube') ?></button>
</div>
</div>
</div>
<?php
}
}