I'm working in a ecommerce with wordpresss and woocommerce, im adding to the shop page and category pages buttons that display the sizes for each product. with this code inside the theme function:
function woocommerce_variable_add_to_carts() {
global $product, $post;
$variations = $product->get_available_variations();
$product_sku = $product->get_sku();
$out = '<ul class="iconic-was-swatches iconic-was-swatches--loop iconic-was-swatches--text-swatch iconic-was-swatches--square">';
foreach ($variations as $key => $value) {
if (!empty($value['attributes'])) {
foreach ($value['attributes'] as $attr_key => $attr_value) {
$out .= '<li><a id="'.esc_attr($post->ID).'" data-quantity="1" data-product_id="'.esc_attr($post->ID).'" data-product_sku="'.$product_sku.'" class="iconic-was-swatch iconic-was-swatch--follow iconic-was-swatch--text-swatch add_to_cart_button">';
$out .= $attr_value . '</a></li>';
}
}
}
$out .= '</ul>';
echo $out;
}
add_action('woocommerce_before_shop_loop_item_title', 'woocommerce_variable_add_to_carts');
The idea is that when the users click in one of those sizes buttons the product is added to the cart directly in that page (shop page, category page). I made a custom endpoint to solve that from the answer provided here. I call the ajax function in the js file that Contains this:
$('.add_to_cart_button').on('click',function(){
jQuery.ajax({
url: WC_VARIATION_ADD_TO_CART.ajax_url,
type: "POST",
data: {
action : "customAdd_to_cart",
product_id : "697",
variation_id : "707",
quantity : 1,
variation : {
size : "s",
color: "pink"
}
},
success: function(){
alert('Ajax Success ');
}
});
});
(i'm using a specific product_id and variation_id for testing) then i add the callback function in the themes function page to add the products to the cart :
function customAddToCart() {
ob_start();
try {
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $data['product_id'] ) );
$quantity = empty( $data['quantity'] ) ? 1 : wc_stock_amount( $data['quantity'] );
$variation_id = isset( $data['variation_id'] ) ? absint( $data['variation_id'] ) : '';
$variations = $variation_id ? (array) get_variation_data_from_variation_id( $variation_id ) : null;
$product_status = get_post_status( $product_id );
$passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data );
if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) && 'publish' === $product_status ) {
do_action( 'woocommerce_ajax_added_to_cart', $product_id );
$res = getCartFragments();
} else {
$res = array(
'error' => true
);
}
return $res;
} catch (Exception $e) {
return new WP_Error('add_to_cart_error', $e->getMessage(), array('status' => 500));
}
}
add_action( 'wp_ajax_nopriv_woocommerce_add_variation_to_cart', 'customAddToCart' );
all this seems to work fine because doesn't give any error in console but the problems is that the variation Size in not added with the product that is selected just add the product. I dont know why this is happening, i even add an alert in the ajax success function
alert('Ajax Success ');
and that alert is displayed but the data it seems is not been sending like it should.
i want to know what i'm missing in any of this codes or it could be the js file and his location or i need to send another value in the a> builded in the first function above. i have try a lot things but the behavior still the same.
A quick scan over your code and I've noticed that the action you are calling with ajax is not correct. It should be woocommerce_add_variation_to_cart not customAdd_to_cart. Also it is common practice to use wp_send_json (or the more specific wp_send_json_success and wp_send_json_error functions) at the end of your ajax callback function so that you get a readable and sensible response in jQuery. Check out the following link if you have not used it before:
https://codex.wordpress.org/Function_Reference/wp_send_json
Hope this helps.
Related
-- Edit 1 --
Found out some new things. I'm adding them on top since they might be more relevant than the code below.
I've rerun the scripts a few times. I now get different findings actually.
Running var_dump($wp_query->query); right after $the_query = new WP_Query($queryArgs);In the first render of the post loop gives me the query vars of the page the loop is rendered on. Calling it with ajax it reruns the same part of the code, right? So than it returns empty.
My thoughts:
Pages is called, runs funtions.php.
Runs the part of the wp_enqueue_script('rtt_scripts');
This is the moment it gets the current $wp_query values. Which are the values of the page.
Than renders the page with the post loop.
This is the moment the post loop runs $the_query = new WP_Query($queryArgs);
On press of the load more the ajax than calls it to rerun the post loop. With the query vars set with wp_enqueue_script('rtt_scripts');
This made me think. Am I running the code in a wrong order? Are the query vars for ajax set on the wrong moment? Other thought. Should I focus on how to get the query vars on the first post loop to the ajax query vars?
-- End Edit --
I’m having trouble with a load more button in Wordpress. The code below is the basic code I have right now.
As far as I can see this should be a working code :) Problem is though that this doesn’t work.
My problem is that I don’t know where to start debugging. Closest I know where the problem lies is this:
In rtt_loadmore_ajax_handler() there is the var $queryArg
When var_dumping the var $queryArg in both rtt_post_grid() and rtt_loadmore_ajax_handler()
It gives different results. Here I would expect the same results. In the Ajax call it returns the arguments
of the current rendered page and not of the post query on this page.
Would the global $wp_query; be the problem? And how do I go from here?
The basic post code:
function rtt_post_grid()
{
$queryArgs = Array(
"post_type" => Array(
'news',
'agenda'
),
'posts_per_page' => 4,
'post_status' => 'publish',
'paged' => 1
);
// post grid wrap
echo '<div id="rtt_posts_wrap" >';
rtt_post_grid_query($queryArgs);
echo '</div>';
// load more button
echo '<form>';
echo '<button id="rtt_loadmore" class=" button">Load more post</button> ';
echo '<input type="hidden" name="action" value="loadmore" />'; // this line might be obsolete
echo '</form>';
}
function rtt_post_grid_query($queryArgs)
{
// The Query
$the_query = new WP_Query($queryArgs);
// The Loop
if ($the_query->have_posts()) {
echo '<ul>';
while ($the_query->have_posts()) {
$the_query->the_post();
echo '<li>' . get_the_title() . '</li>';
}
echo '</ul>';
/* Restore original Post Data */
wp_reset_postdata();
} else {
// no posts found
echo 'no posts found';
}
}
Setting the JS:
if(!has_action('rtt_post_grid_script_and_styles')) {
add_action('wp_enqueue_scripts', 'rtt_post_grid_script_and_styles', 1);
function rtt_post_grid_script_and_styles()
{
global $wp_query;
wp_register_script('rtt_scripts', plugin_dir_url( __FILE__ ) . 'js/script.js', array('jquery'), time());
wp_enqueue_script('rtt_scripts');
wp_localize_script('rtt_scripts', 'rtt_loadmore_params', array(
'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php', // WordPress AJAX
'posts' => json_encode($wp_query->query_vars), // everything about your loop is here
'current_page' => $wp_query->query_vars['paged'] ? $wp_query->query_vars['paged'] : 1,
'max_page' => $wp_query->max_num_pages
));
wp_enqueue_script('rtt_scripts');
}
}
The JS/Ajax:
jQuery(function($){
$(window).ready(function() {
$('#rtt_loadmore').click(function () {
$.ajax({
url: rtt_loadmore_params.ajaxurl,
data: {
'action': 'loadmore', // the parameter for admin-ajax.php
'query': rtt_loadmore_params.posts, // loop parameters passed by wp_localize_script()
'page': rtt_loadmore_params.current_page, // current page
},
dataType: 'json',
type: 'POST',
beforeSend: function (xhr) {
$('#rtt_loadmore').text('Bezig met laden...'); // some type of preloader
},
success: function (data) {
if (data) {
$('#rtt_loadmore').text('More posts');
$('#rtt_posts_wrap').append(data.content); // insert new posts
rtt_loadmore_params.current_page++;
if (rtt_loadmore_params.current_page == rtt_loadmore_params.max_page){
$('#rtt_loadmore').hide(); // if last page, HIDE the button
}
} else {
$('#rtt_loadmore').hide(); // if no data, HIDE the button as well
}
}
});
return false;
});
});
});
The Ajax handler:
add_action('wp_ajax_loadmore', 'rtt_loadmore_ajax_handler'); // wp_ajax_{action}
add_action('wp_ajax_nopriv_loadmore', 'rtt_loadmore_ajax_handler'); // wp_ajax_nopriv_{action}
function rtt_loadmore_ajax_handler(){
$postData = $_POST;
// prepare our arguments for the query
$queryArgs = json_decode( stripslashes( $postData['query'] ), true );
$queryArgs['paged'] = $postData['page'] + 1; // we need next page to be loaded
$queryArgs['post_status'] = 'publish';
ob_start();
rtt_post_grid_query($queryArgs);
$output = ob_get_contents();
ob_end_clean();
global $the_query;
echo json_encode( array(
'posts' => serialize( $the_query->query_vars ),
'max_page' => $the_query->max_num_pages,
'found_posts' => $the_query->found_posts,
'content' => $output
) );
die;
}
So, I've figured it out. I'll explain for it might be useful to somebody else.
The reason it did not work is because the code above is more useful in a template. But I use it in a shortcode. The wp_localize_script() was run on rendering the page and not on running the shortcode. That's why it didn't had the right variables.
I've moved the code below inside the shortcode. Right after the new WP_query:
// The Query
$the_query = new WP_Query($queryArgs);
// The Loop
if ($the_query->have_posts()) {
wp_enqueue_script_ajax_vars($the_query);
Than passed the new query
function wp_enqueue_script_ajax_vars($the_query)
{
wp_register_script('rtt_scripts', plugin_dir_url(__FILE__) . 'js/script.js', array('jquery'), time());
wp_localize_script('rtt_scripts', 'rtt_loadmore_params', array(
'ajaxurl' => site_url() . '/wp-admin/admin-ajax.php', // WordPress AJAX
'posts' => json_encode($the_query->query_vars), // everything about your loop is here
'query_vars' => json_encode($the_query->query),
'current_page' => $the_query->query_vars['paged'] ? $the_query->query_vars['paged'] : 1,
'max_page' => $the_query->max_num_pages,
));
wp_enqueue_script('rtt_scripts', '', '', '', true); // note the last 'true' this sets it inside the footer
}
Resulting in wp_localize_script() creating the variable in the footer. It was in the header before. But by getting it within the shortcode, sending the new query arguments and putting them inside the footer (since the header is already rendered by then) I have set the JS var for Ajax.
Add the two order arguments to $queryArgs.
// prepare our arguments for the query
$queryArgs = json_decode( stripslashes( $postData['query'] ), true );
$queryArgs['paged'] = $postData['page'] + 1; // we need next page to be loaded
$queryArgs['post_status'] = 'publish';
$queryArgs['orderby'] = 'date'; // add this to order by date
$queryArgs['order'] = 'DESC'; // add this to display the most recent
I am trying to remove WordPress posts from front end using AJAX.
My code removes post, but displays blank page with "success", when i want to just fade out this post without page reloading and displaying blank page.
PHP code:
<?php if( current_user_can( 'delete_post' ) ) : ?>
<?php $nonce = wp_create_nonce('my_delete_post_nonce') ?>
delete
<?php endif ?>
Functions.php code:
function my_frontend_script() {
wp_enqueue_script( 'my_script', get_template_directory_uri() . '/js/my_script.js', array( 'jquery' ), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_frontend_script' );
wp_localize_script( 'js/my_script.js', 'MyAjax2', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'ajaxnonce' => wp_create_nonce('ajax-nonce') ) );
add_action( 'wp_ajax_my_delete_post', 'my_delete_post' );
function my_delete_post(){
$permission = check_ajax_referer( 'my_delete_post_nonce', 'nonce', false );
if( $permission == false ) {
echo 'error';
}
else {
wp_delete_post( $_REQUEST['id'] );
echo 'success';
}
die();
}
my_script.js code:
jQuery( document ).ready( function($) {
$(document).on( 'click', '.delete-post', function() {
var id = $(this).data('id');
var nonce = $(this).data('nonce');
var post = $(this).parents('.post:first');
$.ajax({
type: 'post',
url: MyAjax2.ajaxurl,
data: {
action: 'my_delete_post',
nonce: nonce,
id: id
},
success: function( result ) {
if( result == 'success7' ) {
post.fadeOut( function(){
post.remove();
});
}
}
})
return false;
})
})
The problem is page is reloading to a blank page with "success" text, when it should just fade out and remove post from current page, without reloading.
It looks like my_script.js is not even used at all :(
Any help much appreciated.
delete
it's reloading because it loads first the url in your href attribute, then executing your ajax-call. thats not what you want. you want to execute only the onclick. this should solve the problem. just put a # in your href
delete
or make buttons
<button data-id="<?php the_ID() ?>" data-nonce="<?php echo $nonce ?>" class="delete-post">delete</button>
edit: if it's still not working, it's because you got a typo here
if( result == 'success7' )
success7 instead of success
I've made a form with two select fields. The first field is populated with the parents of a custom taxonomy. The second field is populated with the children of each one. I used AJAX to do that but does not seem to work. Nothing happens on change.
Below is my PHP code:
function products_selection()
{
$args = array(
'post_type' => 'seller',
'taxonomy' => 'category',
'hide_empty' => 0,
'exclude' => 1,1078,1079
);
$products = get_categories( $args );
if ( $products ) {
echo '<select id="products-select">';
echo '<option selected="" disabled="" value="0"><span>Προϊόντα</span></option>';
foreach ($products as $product) {
echo '<option class="product-name" id="'. $product->term_id .'">'. $product->name .'</option>';
}
echo '</select>';
}
}
function nomoi()
{
$args = array(
'post_type' => 'seller',
'taxonomy' => 'nomos',
'hide_empty'=> 0,
'parent' => 0
);
$categories = get_categories( $args );
if ( $categories ) {
echo '<select id="nomoi-select">';
echo '<option selected="0" value="-1"><span>Νομοί</span></option>';
foreach ( $categories as $category ) {
$id = $category->term_id;
$name = $category->name;
$taxonomy = $category->taxonomy;
echo '<option class="nomos" id="'. $id .'">'. $name .'</option>';
}
echo '</select>';
}
echo '<select id="town-select">';
echo '<option selected="" disabled="" value="0"><span>Πόλεις</span></option>';
echo '</select>';
}
function my_ajax() {
if(isset($_POST['main_catid']))
{
$args = array(
'order_by' => 'name',
'hide_empty' => 0,
'exclude' => 1,
'taxonomy' => 'nomos',
'name' => 'town-select',
'hierarchical' => 1,
'show_option_none' => 'Πόλεις',
'selected' => -1,
'child_of' => $_POST['main_catid'],
'echo' => 1
);
$categories = get_categories( $args );
foreach ( $categories as $cat ) {
$cat_name = $cat->name;
$id = $cat->cat_ID;
echo '<option class="town" id="'. $category->id .'">'. $category->name .'</option>';
}
die();
} // end if
}
My script:
jQuery(document).ready(function() {
// Avoid conflicts
$ = jQuery;
$('#nomoi-select').change(function() {
$mainCat = $('#nomoi-select option:selected').attr('id');
console.log('$mainCat: ' + $mainCat);
// call ajax
$("#town-select").empty();
$.ajax
(
{
url:'index.php',
type:'POST',
// Use an object literal
data: {
"action" : "my_ajax()",
"main_catid" : $mainCat
},
success:function( results )
{
// alert(results);
alert('Successfully called');
$("#town-select").append( results );
},
error:function( exception )
{
alert('Exception: ' + exception);
}
}
);
});
});
And the function to register my script:
function my_scripts() {
wp_enqueue_script( 'header-form', get_template_directory_uri() . '/js/headerform.js', array(), '1.0.0', true );
}
add_action( 'wp_enqueue_scripts', 'my_scripts' );
Since you are working with WordPress, I suspect you could be having jQuery conflict issues. To confirm this, you can try changing all instances of $ to jQuery and see if you get the same errors.
Also - if you are running this script from a .js file, the PHP wont evaluate, but keeping the URL relative should still work fine.
I have made a few changes to the script which you can try:
jQuery(document).ready(function() {
// Avoid conflicts
$ = jQuery;
$('#main_cat').change(function() {
$mainCat = $('#main_cat option:selected').val();
// call ajax
$("#sub_cat").empty();
$.ajax
(
{
url:"/wp-admin/admin-ajax.php",
type:'POST',
// Use an object literal
data: {
"action" : "my_ajax",
"main_catid" : $mainCat
},
success:function( results )
{
// alert(results);
$("#sub_cat").removeAttr("disabled").append( results );
}
}
);
});
});
From the fiddle you provided, simply adding console.log('$mainCat: ' + $mainCat); (see this modified fiddle) ensures that the change event fires as expected.
Beyond that we get a 404 not found error, which is pretty normal in the current state of the fiddle example.
So it is certain that your issue comes from something with the Ajax called script or its returned data.
You only said that "Nothing happens on change", without any precision. In fact you should now use Firebug or similar to look at error messages, which may be, either:
an URL generation error: in this case you should get a 404 not found error too
an error in the server script you're invoking: in this case you should get a 500 server error error
a bad (malformed) return from the server: in this case you should get a JS error
Also note that:
it cannot be an empty return from the server, or your #sub_cat element would have already lost its disabled attribute before a JS error happens
at the opposite (even if unlikely) it also might be an Ajax error: so to be sure you should add an error: or always: member to the $.ajax() argument
i am working on a plugin in wordpress to vote up a post or vote down using ajax.
Everything is working fine but the problem is am not able to disable the onclick eventhandler after first click so whenever someone voting a post , he can add vote multiple times. I want to ignore that so i should be able to vote only once. If i click on vote up then the voteup anchor tag should be disable and votedown anchor tag should be enable. At the same time if i click on the votedown anchor tag then votedown should be disable and voteup should be enable. Also i want to enable the voting feature only if the user is logged in the wordrpess.
I have a function to show a popup if the user is not logged in.
i.e login_open();
If user is not logged in and try to vote up then this function should execute login_open();
Otherwise user should be able to vote or downvote only once ..
Here is my code //
php
//Defining Base Paths
define('VOTEUPURL', WP_PLUGIN_URL."/".dirname( plugin_basename( __FILE__ ) ) );
define('VOTEUPPATH', WP_PLUGIN_DIR."/".dirname( plugin_basename( __FILE__ ) ) );
//Enqueue Script for the Admin Ajax and Cutom Js File
function voteme_enqueuescripts()
{
wp_enqueue_script('voteme', VOTEUPURL.'/js/voteup.js', array('jquery'));
wp_localize_script( 'voteme', 'votemeajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
wp_localize_script( 'votedown', 'votedownajax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
}
add_action('wp_enqueue_scripts', voteme_enqueuescripts);
//Adding Vote up links to all the posts.
function voteme_getvotelink(){
$votemelink = "";
$post_ID = get_the_ID();
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$link = $votemecount.' '.'Vote Up'.'';
$link .=' '.'Vote Down'.'';
$votemelink = '<div id="voteme-'.$post_ID.'">';
$votemelink .= '<span>'.$link.'</span>';
$votemelink .= '</div>';
return $votemelink;
}
//Function to get the count
function get_current_vote_count(){
$voteup_count = "";
$post_ID = get_the_ID();
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$votelink = '<span class="vote_count">'. $votemecount .'</span>';
return $votelink;
die($votelink);
}
//Add Vote Function
function voteme_addvote()
{
$results = '';
global $wpdb;
$post_ID = $_POST['postid'];
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$votemecountNew = $votemecount + 1;
update_post_meta($post_ID, '_votemecount', $votemecountNew);
$results.=$votemecountNew;
// Return the String
die($results);
}
// creating Ajax call of ADD VOTE for WordPress
add_action( 'wp_ajax_nopriv_voteme_addvote', 'voteme_addvote' );
add_action( 'wp_ajax_voteme_addvote', 'voteme_addvote' );
//Add Vote Function
function voteme_downvote()
{
$results = '';
global $wpdb;
$post_ID = $_POST['postid'];
$votemecount = get_post_meta($post_ID, '_votemecount', true) != '' ? get_post_meta($post_ID, '_votemecount', true) : '0';
$votemecountNew = $votemecount - 1;
update_post_meta($post_ID, '_votemecount', $votemecountNew);
$results.= $votemecountNew;
// Return the String
die($results);
}
// creating Ajax call of DOWN VOTE for WordPress
add_action( 'wp_ajax_nopriv_voteme_downvote', 'voteme_downvote' );
add_action( 'wp_ajax_voteme_downvote', 'voteme_downvote' );
//Javascript and Ajax Calls
function votemeaddvote(postId)
{
jQuery.ajax({
type: 'POST',
url: votemeajax.ajaxurl,
data: {
action: 'voteme_addvote',
postid: postId
},
success:function(data, textStatus, XMLHttpRequest){
var vote_count_id = jQuery('.vote_count');
jQuery(vote_count_id).html('');
jQuery('.vote_count').append(data);
var thisr = jQuery('.voter button:first-child')
thisr.disable = true;
// add any additional logic here
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert(errorThrown);
}
});
}
function votemedownvote(postId)
{
jQuery.ajax({
type: 'POST',
url: votemeajax.ajaxurl,
data: {
action: 'voteme_downvote',
postid: postId
},
success:function(data, textStatus, XMLHttpRequest){
var vote_count_id = jQuery('.vote_count');
jQuery(vote_count_id).html('');
jQuery('.vote_count').append(data);
},
error: function(MLHttpRequest, textStatus, errorThrown){
alert(errorThrown);
}
});
}
//HTML For Adding Votes
<div class="voter">
<a onclick="votemeaddvote(<?php echo $post_ID; ?>);">VoteUp</a>
<a onclick="votemedownvote(<?php echo $post_ID; ?>)">Vote Down</a>
</div>
Simplely using .one() instead of .on()
Try something like this,
$(".voter a:last-child").one( "click", function() {
console.log("click");
var data = $(this).data();
console.log(data);
votemedownvote(data.id);
});
So what you could do is change some of your code
Change the html to this:
<div class="voter">
<a data-id="<?php echo $post_ID; ?>">VoteUp</a>
<a data-id="<?php echo $post_ID; ?>">Vote Down</a>
</div>
And change your javascript like this since you are using jquery:
$(".voter a").on( "click", function() {
console.log("click");
var data = $(this).data();
console.log(data);
votemeupvote(data.id);
$(this).off();
});
So var data get has the post id in json form to be sent.
Using "this" you are able to target this specific element and turn its on click off. I removed your on embedded click events because usually you want to bootstrap those triggers so you can turn them off, which was your problem.
You can do this by using jquery .on and .off methods.
Edit: Forgot to add your function call. I added it. I will also add how your votedown can work:
$(".voter a:last-child").on( "click", function() {
console.log("click");
var data = $(this).data();
console.log(data);
votemedownvote(data.id);
$(this).off();
});
Edit 2: Oh and I forgot to mention that this is only good for the front end. So in the backend you need someway to track if the person voted or not, maybe a table with user id, post id and voted true or false. That way you can track it when the ajax call comes and have php update the database.
Fiddle
I am using a static .js file that is registered for a TinyMCE plugin. You click on the new button and it opens up the modal window, with a form in it, that I use to generate a Shortcode. The problem is that I need some of my form fields to be populated from PHP functions. I've been looking at articles on this for hours and haven't found a workable solution. Right now my php function is a Shortcode, so I need to adapt it to be a regular old function. But the big challenge is figuring out how to arrange this so that the .js file can take the function in the form. Here's the basic stuff. First, some chunks of the .js file:
(function(){
// creates the plugin
tinymce.create('tinymce.plugins.myshortcode', {
// creates control instances based on the control's id.
createControl : function(id, controlManager) {
if (id == 'myshortcode') {
// creates the button
var button = controlManager.createButton('myshortcode', {
title : 'My Shortcode', // title of the button
image : '../wp-content/plugins/my-shortcode/js/images/myshortcode.png', // path to the button's image
onclick : function() {
// triggers the thickbox
var width = jQuery(window).width(), H = jQuery(window).height(), W = ( 720 < width ) ? 720 : width;
W = W - 80;
H = H - 80;
tb_show( 'My Shortcode', '#TB_inline?width=' + W + '&height=' + H + '&inlineId=myshortcode-form' );
}
});
return button;
}
return null;
}
});
// registers the plugin.
tinymce.PluginManager.add('myshortcode', tinymce.plugins.myshortcode);
jQuery(function(){
var form = jQuery(' \
\
The HTML Web Form all goes in here.\
\
');
var table = form.find('table');
form.appendTo('body').hide();
form.find('#myshortcode-submit').click(function(){
var options = {
'att1' : '',
'att2' : '',
'att3' : '',
'att4' : '',
};
var shortcode = '[myshortcode';
for( var index in options) {
var value = table.find('#myshortcode-' + index).val();
if ( value !== options[index] && value != null )
shortcode += ' ' + index + '="' + value + '"';
}
shortcode += '] content here. [/myshortcode]';
tinyMCE.activeEditor.execCommand('mceInsertContent', 0, shortcode);
tb_remove();
});
});
})()
But in that spot where it says, "The HTML Web Form goes in here," I need to have a couple of fields that are generated based on PHP functions. I've only written one of the two so far, and as I said, it's currently written as a Shortcode, so I need to change it (not sure the best way to do that given the other big questions here). But here it is:
add_shortcode('rolescapsdropdown', 'sc_rolescapsdropdown');
function sc_rolescapsdropdown($attr) {
global $wp_roles;
$all_roles = $wp_roles->roles;
$editable_roles = apply_filters('editable_roles', $all_roles);
$user = new WP_User( 1 );
$capslist = $user->allcaps;
$dropdown = '<select multiple>';
foreach($editable_roles as $role=>$theroles){
$dropdown .= '<option value="'.$role.'">'.$role.'</option>';
}
foreach($capslist as $cap=>$caps){
if($cap !== 'administrator' && $cap !== 'level_0' && $cap !== 'level_1' && $cap !== 'level_2' && $cap !== 'level_3' && $cap !== 'level_4' && $cap !== 'level_5' && $cap !== 'level_6' && $cap !== 'level_7' && $cap !== 'level_8' && $cap !== 'level_9' && $cap !== 'level_10'){
$dropdown .= '<option value="'.$cap.'">'.$cap.'</option>';
}
}
$dropdown .= '</select>';
return $dropdown;
}
I'm hoping to avoid having to learn Ajax here. But I tried making the .js file a .php file and just wrapping the JavaScript in <script> tags, but then all the TinyMCE buttons disappeared, so apparently it won't let me use a .php file to register the plugin.
Update 1
One idea I have is to try to move the web form to a php file, and just have the .js file that registers the TMCE plugin call it up, but I wouldn't know if that would work, nor how to get the .js file to recognize the existence of the form in an external php file.
Update 2
Based on ScottA's help, here's how I'm trying to work this:
I've added this to my static .js file that has the form:
$.get( "ajax/test.php", function( data ) {
var options = data.options;
for(row in options) {
$("#option-list").append("<option value=" + options[row].value + ">" + options[row].name + "</option>");
// debug for unexpected results
console.log(data.options);
}
}, "json" );
I've created this test.php file in a subdirectory called "ajax":
function rolescapsdropdown() {
global $wp_roles;
$all_roles = $wp_roles->roles;
$editable_roles = apply_filters('editable_roles', $all_roles);
$user = new WP_User( 1 );
$capslist = $user->allcaps;
$all_options = $editable_roles . $capslist;
$all_options[]['value'] = $value;
$all_options[]['name'] = $name;
echo json_encode( array('options' => $all_options) );
}
And I added this HTML to the form in the static .js file:
<select id="option-list"></select>
What I'm getting is a blank modal window. None of the HTML is showing up at all when I include the $.get function.
Update 3
Still getting a blank modal window. I converted it back to a shortcode to see what it outputs. This...
add_shortcode('rolesdropdown', 'sc_rolesdropdown');
function sc_rolesdropdown() {
global $wp_roles;
$all_roles = $wp_roles->roles;
$editable_roles = apply_filters('editable_roles', $all_roles);
$user = new WP_User( 1 );
$capslist = $user->allcaps;
foreach ($editable_roles as $role=>$theroles){
$all_options = $role;
}
foreach ($capslist as $cap=>$caps){
$all_options .= $cap;
}
echo json_encode( array('options' => $all_options) );
}
outputs this on the page:
{"options":"trollswitch_themesedit_themesactivate_pluginsedit_pluginsedit_usersedit_filesmanage_optionsmoderate_commentsmanage_categoriesmanage_linksupload_filesimportunfiltered_htmledit_postsedit_others_postsedit_published_postspublish_postsedit_pagesreadlevel_10level_9level_8level_7level_6level_5level_4level_3level_2level_1level_0edit_others_pagesedit_published_pagespublish_pagesdelete_pagesdelete_others_pagesdelete_published_pagesdelete_postsdelete_others_postsdelete_published_postsdelete_private_postsedit_private_postsread_private_postsdelete_private_pagesedit_private_pagesread_private_pagesdelete_userscreate_usersunfiltered_uploadedit_dashboardupdate_pluginsdelete_pluginsinstall_pluginsupdate_themesinstall_themesupdate_corelist_usersremove_usersadd_userspromote_usersedit_theme_optionsdelete_themesexportbe_trollexec_phpedit_others_phpadministrator"}
But when in the modal window on the backend, the window is just blank when the $.get is calling the file with that function in it.
You say you don't want to learn AJAX, but you should not be afraid. jQuery's $.get() function makes it very easy to get and process data from an external file. If your PHP functions reside in a separate file, you could make the $.get() call to that file and populate the form in the same jQuery function.
Your jQuery could be as simple as:
$.get( "ajax/test.php", function( data ) {
$( ".result" ).html( data );
});
Say your file, test.php returned a JSON array, or even plain text based off parameters you pass in the URL (ie: "ajax/test.php?userid=1&get=name") you could use jQuery to populate the form.
Your jQuery:
$.get( "ajax/test.php?userid=1&get=name", function( data ) {
$( "#myform input.firstname").val( data.firstname );
$( "#myform input.lastname").val( data.lastname );
}, "json" );
test.php could look like:
<?php
// your function to retrieve the data from the database, a file, etc.
echo json_encode(array(
"firstname" => "Burt",
"lastname" => "Bartigan"
));
?>
You say you don't want to use AJAX, but that's the easiest way you will solve this problem.
More information on $.get();
More information on PHP json functions
-- EDIT --
To answer your comment below:
your php:
$all_options[]['value'] = $value;
$all_options[]['name'] = $name;
// or however you can best get it
// from the database into an array
echo json_encode( array('options' => $all_optoins) );
your jQuery:
$.get( "ajax/test.php", function( data ) {
var options = data.options;
for(row in options) {
// append will place this inside the <select> HTML element
$("#option-list").append("<option value=" + options[row].value + ">" + options[row].name + "</option>");
// debug for unexpected results?
console.log(data.options);
}
}, "json" );
your HTML:
<select id="option-list"></select>
I just had the same issue and this is how I solved it. First, we need to pass some PHP values to the JavaScript file. As wp_localize_script cannot be used (we're not enqueueing the script), we'll print it directly in admin_head:
foreach( array('post.php','post-new.php') as $hook )
add_action( "admin_head-$hook", 'admin_head_js_vars' );
/**
* Localize Script
*/
function admin_head_js_vars()
{
$img = plugins_url( '/js/images/myshortcode.png', __FILE__ );
?>
<!-- TinyMCE Shortcode Plugin -->
<script type='text/javascript'>
var b5f_mce_config = {
'tb_title': '<?php _e('Roles Shortcode'); ?>',
'button_img': '<?php echo $img; ?>',
'ajax_url': '<?php echo admin_url( 'admin-ajax.php')?>',
'ajax_nonce': '<?php echo wp_create_nonce( '_nonce_tinymce_shortcode' ); ?>'
};
</script>
<!-- TinyMCE Shortcode Plugin -->
<?php
}
With this, the button creation looks like:
title: b5f_mce_config.tb_title, // title of the button
image: b5f_mce_config.button_img, // path to the button's image
Now, we'll add an Ajax action:
add_action( 'wp_ajax_b5f_tinymce_shortcode', 'b5f_tinymce_shortcode' );
function b5f_tinymce_shortcode()
{
$do_check = check_ajax_referer( '_nonce_tinymce_shortcode', 'security', false );
if( !$do_check )
echo 'error';
else
include_once 'my-form.php';
exit();
}
Back to JS (noting that my example is based on this):
jQuery(function($)
{
/* Used in Ajax and Callback */
var table;
/**
* Get the ThickBox contents wit Ajax
*/
var data_alt = {
action: 'b5f_tinymce_shortcode',
security: b5f_mce_config.ajax_nonce
};
$.post(
b5f_mce_config.ajax_url,
data_alt,
function( response )
{
if( 'error' == response )
{
$('<div id="mygallery-form"><h1 style="color:#c00;padding:100px 0;width:100%;text-align:center">Ajax error</h1></div>')
.appendTo('body').hide();
}
else
{
form = $(response);
table = form.find('table');
form.appendTo('body').hide();
form.find('#mygallery-submit').click(b5f_submit_gallery);
}
}
);
/**
* Callback for submit click
*/
function b5f_submit_gallery()
{
// Options defined in admin_head
var shortcode = '[my_shortcode]';
// inserts the shortcode into the active editor
tinyMCE.activeEditor.execCommand('mceInsertContent', 0, shortcode);
// closes Thickbox
tb_remove();
}
});
Finally, the file myform.php, included with Ajax, can contain any WordPress functions:
<?php
/**
* Used by Ajax
*/
?>
<div id="mygallery-form">
<?php echo site_url(); ?>
</div>