How to auto check Downloadable and Virtual checkbox on Dokan frontend upload form? - dokan

I want to auto check on Downloadable and Virtual checkbox on Dokan plugin, this my code:
add_action( 'woocommerce_product_options_general_product_data', 'hiding_and_set_product_settings' );
function hiding_and_set_product_settings(){
## ==> Set HERE your targeted user role:
$targeted_user_roles = array( 'administrator', 'shop_manager', 'vendor', 'vendors' );
// Getting the current user object
$user = wp_get_current_user();
// getting the roles of current user
$user_roles = $user->roles;
if ( array_intersect( $targeted_user_roles, $user_roles ) ){
## CSS RULES ## (change the opacity to 0 after testing)
// HERE Goes OUR CSS To hide 'virtual' and 'downloadable' checkboxes
?>
<style>
label[for="_virtual"], label[for="_downloadable"]{ opacity: 0.2 !important; /* opacity: 0; */ }
</style>
<?php
## JQUERY SCRIPT ##
// Here we set as selected the 'virtual' and 'downloadable' checkboxes
?>
<script>
(function($){
$('input[name=_virtual]').prop('checked', true);
$('input[name=_downloadable]').prop('checked', true);
})(jQuery);
</script>
<?php
}
}
This in my function, child theme. I found this code from: https://stackoverflow.com/a/42177288/6574214. But this code only work for backend only, i want on dokan frontend upload form. Anyone know the code? I want comment on https://stackoverflow.com/a/42177288/6574214 but i not have reputation for that... :(

I found a solution for this.
Background : We are developing a website where vendors can sell digital products only. So we got this issue as we need to hide the options and keep downloadable and virtual enabled.
Here is the code you can use :
The above code you are using will work for woocommerce backend but to make it work in the frontend you need to use this hook : dokan_product_edit_after_options.
Ref : https://wedevs.com/docs/dokan/developer-documentation/seller-dashboard-action-hooks/
Solution :
add_action( 'dokan_product_edit_after_options', 'pitby_dokan_preselect' );
function pitby_dokan_preselect(){
?>
<style>
label[for="_virtual"], label[for="_downloadable"]{ opacity: 0; }
</style>
<?php
?>
<script>
(function($){
$('input[name=_virtual]').prop('checked', true);
$('input[name=_downloadable]').prop('checked', true);
})(jQuery);
</script>
<?php
}
Thanks & Regards,
Vamsi.

Related

Angular - Dynamic header

I have a website currently under development.
Issue: When accessing a page, the front page is briefly displayed - and then the current page is shown.
Please try refreshing this link to have better understanding. Notice that while loading, the front page is displayed - and after load completes, then the correct page is displayed.
Question What shall I do to avoid the front page being shown during refresh of a page?
Background: Every page in the website have different header. My approach:
Created header helper service
Header helper service keep watching for route change
Depending on current route it sets different css class on header component template. This works perfect if user navigates through website without refreshing page
Please see html and header helper service code below
<div [ngClass]="{'no-hero': headerType === 400, 'restaurant-page': headerType === 200, 'restaurant-list': headerType === 300}"
class="top-section">
<div class="top-section-bg">
</div>
// Code removed for brevity
</div>
private setHeaderType(): void {
if (this.currentUrl.includes("search-restaurants")) {
this.headerType = HeaderType.restaurantSearch;
} else if (this.currentUrl.includes("profile") || this.currentUrl.includes('faqs') || this.currentUrl.includes('bookings')) {
this.headerType = HeaderType.noHero;
} else if (this.currentUrl === "/") {
this.headerType = HeaderType.home;
} else {
this.headerType = HeaderType.restaurantDetail;
}
this.headerTypeSource.next(this.headerType);
}
My solution here is to have some styles in the index.html as plaintext, hardcoded styles, that hide the front page on reload. Aka.
index.html
<html>
<style>
.loading-overlay {
z-index: 99;
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
color: red;
}
.loading-overlay--hide { display: none; }
</style>
<div class="loading-overlay"></div>
</html>
And when angular boots, I just do this to hide the loader
document.getElementById('full-page-loader').className += " full-page-loader--hide";

setting up rel="next" javascript ajax <a>

I have a tag (show more) that when user clicks it loads the next 10 results onto what is already there.
I looked around to make this seo friendly but all this talks about is ..
how can i make my relevant for seo next page (really showing more instead of next)
Rather than load with ajax, why not just hide everything after the first 10 and have the next tag show the next 10. See following example.
<style>
.hide{
display: none;
}
</style>
<div id='contain'>
<?php
//Not sure what you are loading but this is a dummy loop done in PHP
$i=0;
while($i<101){
//Set the class based on the result. If greater than 10 then hide this result.
$class = ($i<10 ? "result" : "result hide");
echo"<div class='$class'>
<p>MY CONTENT</p>
</div>";
$i++;
}
?>
</div>
<a href='#' id='showMore'>Show 10 More</a>
<script>
$('#showMore').click(function(e){
e.preventDefault();
var i = 0;
$('.hide').each(function(){
if(i<10){
$(this).removeClass('hide');
}
else{
return;
}
i++;
});
});
</script>
That is the only way I can think of solving the problem. I understand ajax is being used to speed up the query.

Yii 1.1 - creating a multi step form with validation

I'm basically trying to create a multi-step form using the CActiveForm class in Yii. The idea is I want to use the built-in functionality to achieve this in the simplest way possible. The requirement I have is as follows:
A multi step ONE PAGE form (using DIVs that show/hide with jQuery)
AJAX validation on EACH step (validate step-specific attributes only)
The validation MUST work using the validateOnChange() and validateOnSubmit() methods
This is a half-working solution I have developed so far:
View:
<div class="form">
<?php $form = $this->beginWidget('CActiveForm', array(
'id'=>'listing-form',
'enableClientValidation'=>false,
'enableAjaxValidation'=>true,
'clientOptions'=>array(
'validateOnChange'=>true,
'validateOnSubmit'=>true,
'afterValidate'=>'js:validateListing',
),
)); ?>
<?php echo $form->errorSummary($model); ?>
<div class="step" id="step-1">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step1')); ?>
</div>
<div class="step" id="step-2" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Next Step', array('name'=>'step2')); ?>
</div>
<div class="step" id="step-3" style="display: none;">
// model input fields
<?php echo CHtml::submitButton('Submit', array('name'=>'step3')); ?>
</div>
<?php $this->endWidget(); ?>
</div>
JavaScript:
function validateListing(form, data, hasError)
{
if(hasError)
{
// display JS flash message
}
else
{
if($('#step-1').css('display') != 'none')
{
$('#step-1').hide();
$('#step-2').show();
}
else if($('#step-2').css('display') != 'none')
{
$('#step-2').hide();
$('#step-3').show();
}
else if($('#step-3').css('display') != 'none')
{
return true; // trigger default form submit
}
}
}
Controller:
public function actionCreate()
{
$model = new Listing;
// step 1 ajax validation
if(isset($_POST['step1']))
{
$attributes = array('name', 'address1', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 2 ajax validation
if(isset($_POST['step2']))
{
$attributes = array('category', 'type', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// step 3 ajax validation
if(isset($_POST['step3']))
{
$attributes = array('details', 'source', 'etc');
$this->performAjaxValidation($model, $attributes);
}
// process regular POST
if(isset($_POST['Listing']))
{
$model->attributes = $_POST['Listing'];
if($model->validate()) // validate all attributes again to be sure
{
// perform save actions, redirect, etc
}
}
$this->render('create', array(
'model'=>$model,
));
}
protected function performAjaxValidation($model, $attributes=null)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='listing-form')
{
echo CActiveForm::validate($model, $attributes);
Yii::app()->end();
}
}
To summarise. Basically what I have is a form with 3 submit buttons (one for each step). In my controller I check which submit button was pressed and I run AJAX validation for the attributes specific to that step.
I use a custom afterValidate() function to show/hide the steps upon submit. On step 3, the default form submit is triggered, which posts all the form attributes to the controller.
This works well, except it won't work with validateOnChange() (since the submit button doesn't get posted). Also I was wondering whether this is actually the best way to do this, or if anyone knows of a better way?
Thanks.
I'd suggesting using scenarios to turn on and off the appropriate rules. Adjust the model scenario based on what is sent to your controller.
Note: this may also be a really good place to use a CFormModel instead of a CActiveRecord, depending on what is in your form.
Edit: can you add a hidden field to each div section that contains the info about what step you are on? Seems like that should work instead of your submit buttons.
OPTION 1
When you do not receive a button, why not validate the entire form, why do you need to validate only specific attributes? Yii will validate the entire model, send back all the errors but only that particular error will be shown by the active form because that is how it works already.
OPTION 2
You can have 3 forms (not 1 like you have now), 1 on each step. Also create 3 scenarios 1 for each step.
Each form has a hidden field that gets posted with the form, it can actually be the scenario name just validate it when it comes in. Validate the model using this hidden field to set the scenario you are on.
You can cache parts on the model when the form is submitted successfully and at the end you have the complete model.
you can always have custom validation and it won't break your normal form validation
in your model
private $step1 = false;
private $step2 = false;
private $all_ok = false;
protected function beforeValidate()
{
if(!empty($this->attr1) && $this->attr2) // if the fields you are looking for are filled, let it go to next
{
$this->step1 = true;
}
if($this->step1)
{
... some more validation
$this->step2 = true;
}
if($this->step2)
{
... if all your logic meets
$this->all_ok = true;
}
// if all fields that your looking for are filled, let parent validate them all
// if they don't go with their original rules, parent will notify
if($this->all_ok)
return parent::beforeValidate();
$this->addError($this->tableSchema->primaryKey, 'please fillout the form correctly');
return false;
}
I think better create specific class for each step of validation and use scenarios with rules. Below is small example.
//protected/extensions/validators
class StepOneMyModelValidator extends CValidator
{
/**
* #inheritdoc
*/
protected function validateAttribute($object, $attribute)
{
/* #var $object YourModel */
// validation step 1 here.
if (exist_problems) {
$object->addError($attribute, 'step1 is failed');
}
...
Create other classes(steps) for validation...
// in your model
public function rules()
{
return array(
array('attr', 'ext.validators.StepOneMyModelValidator', 'on' => 'step1'),
...
How to use in controller:
$model = new Listing();
$steps = array('step1', 'step2', /* etc... */);
foreach($_POST as $key => $val) {
if (in_array($key, $steps)) {
$model->setScenario($key);
break;
}
}
$model->validate();
echo '<pre>';
print_r($model->getErrors());
echo '</pre>';
die();
Or we can validate all steps in one validator.

Yii Framework + Infinite Scroll + Masonry Callback not working

I know that InfiniteScroll and Masonry work well together. But I am using the Infinite Scroll Extension of Yii (called yiinfinite-scroll) and tried to apply Masonry on it. Infinite Scroll for itself works perfectly, Masonry for itself too. But after InfiniteScroll tries to load a new set of images (I've got an image page), the callback part of InfiniteScroll doesn't seem to fire, because the newly appended elements don't have any masonry code in it and appear behind the first visible items. (I know that this bug is reported often, but the solutions I found so far didn't work for me).
My structure for showing the picture looks like this:
<div class="items">
<div class="pic">...</pic>
<div class="pic">...</pic>
...
</div>
The first page load looks like this
<div class="items masonry" style="...">
<div class="pic masonry-brick" ...></div>
<div class="pic masonry-brick" ...></div>
...
</div> // everything's fine, masonry is injected into the code
After infinite scroll dynamically loads new images these look like this:
<div class="items masonry" ...></div>
<div class="pic masonry-brick" ...></div>
...
// appended pics:
<div class="pic"></div>
<div class="pic"></div>
</div> // so no masonry functionality was applied
My Masonry Code:
$(function (){
var $container = $('.items');
$container.imagesLoaded(function(){
$container.masonry({
itemSelector: '.pic',
columnWidth: 405
});
});
});
$container.infinitescroll({
// normally, the options are found here. but as I use infinitescroll as a Yii extension, the plugin is already initiated with options
}
},
// trigger Masonry as a callback
function( newElements ) {
// hide new items while they are loading
var $newElems = $( newElements ).css({ opacity: 0 });
// ensure that images load before adding to masonry layout
$newElems.imagesLoaded(function(){
// show elems now they're ready
$newElems.animate({ opacity: 1 });
$container.masonry( 'appended', $newElems, true );
});
});
});
I also tried to copy and replace the current InfiniteScroll-min.js file in the extension folder by the newest one. Same effect...
Best regards,
Sebastian
Okay I found a solution. I post it here if somebody else has the same issue:
I just modified the YiinfiniteScroller Class from the Yiinfinite Scroll Yii Extension and added the callback part for Infinite Scroll which was missing:
private function createInfiniteScrollScript() {
Yii::app()->clientScript->registerScript(
uniqid(),
"$('{$this->contentSelector}').infinitescroll(".$this->buildInifiniteScrollOptions().", ".$this->callback.");"
);
}
At the beginning of the class I added the line
public $callback;
to use it later in the method.
Then you can call the Widget with an additional option callback, for example like this:
'callback' => 'function( newElements ) {
// hide new items while they are loading
var $newElems = $( newElements ).css({ opacity: 0 });
// ensure that images load before adding to masonry layout
$newElems.imagesLoaded(function(){
// show elems now theyre ready
$newElems.animate({ opacity: 1 });
$(".items").masonry( "appended", $newElems, true );
});
}',
Works like charm.

Disqus Plugin Explanation of Dynamic Tags

So I am using the Disqus Plugin v2.65. I am trying to edit the dsq-global-toolbar at the top of the Disqus comments.
The following tags are in disqus-comment-system/comments.php
<div id="disqus_thread">
<?php if (!get_option('disqus_disable_ssr')): ?>
<?php
// if (is_file(TEMPLATEPATH . '/comments.php')) {
// include(TEMPLATEPATH . '/comments.php');
// }
?>
<div id="dsq-content">
<ul id="dsq-comments">
however on my site there are mulitple tags (the disqus-global-toolbar div) that seem to be dynamically appended between the dsq-content div and the dsq-comments ul. Where is this coming from and where can I edit this? Any help would be greatly appreciated.
I think it is coming somewhere around line 3140 in disqus.js
You can use this code to wait for the document to finish loading completely then do your changes (client side):
$(document).ready(function() {
window.disqus_no_style = true;
$.getScript('http://sitename.disqus.com/embed.js', function() {
var loader = setInterval(function() {
if($('#disqus_thread').html().length) {
clearInterval(loader);
disqusReady();
}
}, 1000);
});
function disqusReady() {
//whatever you can imagine
}
});
window.diqus_no_style can be deleted as well as the $.getsript wrapper.
Is that what you are looking for?
Something like this (use livequery instead of live):
function disqusReady() {
$('#dsq-global-toolbar').livequery(function() {
//$(this) will refer to object
});
}
Not sure what plug-in you're talking about, but if it's WordPress, I've done the same thing. Modify wp-content/plug-ins/disqus-comment-system/comments.php by adding an event handler for 'afterRender' (fires when the content ready in the DOM, but still hidden), eg. around line 70:
config.callbacks.afterRender.push(myFunctionToModifyDisqusOutput);