Title: Using javascript in Shortcode Callback when creating new plugin
Last modified: January 2, 2023

---

# Using javascript in Shortcode Callback when creating new plugin

 *  [devgirl](https://wordpress.org/support/users/elfynity5/)
 * (@elfynity5)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/)
 * Hi everyone, I hope I can get some help with this. I am developing a new plugin
   and have created it inside a shortcode function. Inside this function, I am also
   using some javascript. When I use the shortcode on a page, it works no problem,
   but if I try run it twice, the second instance gives me an error that my let 
   variable inside my javascript has already been declared.
 * So I could move the javascript to an external file using enqueue so it only calls
   it once, but the javascript doesn’t work unless I am inside the shortcode callback
   function. I know it is because I have saved a shortcode attribute into a variable
   called $time, and this $time variable basically populates the entire javascript
   block.
 * I don’t know how to solve this so that I can have multiple shortcodes on one 
   page, and not have a javascript variable redeclaration problem.
 * Here is my code:
 *     ```wp-block-code
       function devgirl_countdown_clock_function($atts = '', $content = null) { 
       	$value = shortcode_atts( array(
       		'time' => "5 December 2023 8:00",
       		'end-notice' => "Countdown Ended",
       		'clock-colour' => "#011c25",
       		'text-colour' => "DarkTurquoise",
       	), $atts, 'devgirl_countdown_clock_function' );
   
       	$time = sanitize_text_field($value['time']);	
       	$end_notice = sanitize_text_field($value['end-notice']);	
       	$clock_colour = sanitize_text_field($value['clock-colour']);
       	$text_colour = sanitize_text_field($value['text-colour']);
   
   
       ?>
   
   
   
   
   
       	<h2 class="end-notice"></h2>
   
   
   
   
       	<div class="devgirl-countdown-clock border-radius">
       		<?php 
       		if ( ! function_exists( 'countdownBlocks' ) ) {
       		function countdownBlocks($clock_colour, $text_colour, $date_value, $date_value_title) { ?>
   
       			<div class="countdown-block" style="background:<?php echo esc_html($clock_colour); ?>; color:<?php echo esc_html($text_colour); ?>">
       				<div class="clock <?php echo esc_html($date_value); ?>-clock-value"></div>
       				<div class="text"><?php echo esc_html($date_value_title); ?></div>
       			</div><!---countdown-block-->
       			<div class="separators">:</div>
   
   
       		<?php }
   
   
       		countdownBlocks($clock_colour, $text_colour, 'days', 'Days');
       		countdownBlocks($clock_colour, $text_colour, 'hours', 'Hours');
       		countdownBlocks($clock_colour, $text_colour, 'mins', 'Mins');
       		countdownBlocks($clock_colour, $text_colour, 'secs', 'Secs');
   
       		} else {
       			echo 'The function name already exists and cannot be run. Plese check all your plugins function names to find the conflict.';
       		}
       		?>
   
       	</div><!---devgirl-countdown-clock-->
   
   
   
   
   
   
       <script type="text/javascript">
       // Set the date we're counting down to
       const countDownDate = new Date('<?php echo $time; ?>').getTime();
   
       // Update the count down every 1 second
       let x = setInterval(function() {
   
         // Get today's date and time
         let now = new Date().getTime();
   
         // Find the distance between now and the count down date
         let distance = countDownDate - now;
   
         // Time calculations for days, hours, minutes and seconds
         let days = Math.floor(distance / (1000 * 60 * 60 * 24));
         let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
         let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
         let seconds = Math.floor((distance % (1000 * 60)) / 1000);
   
         // Output the result in an element with id="demo"
   
       	document.querySelector('.devgirl-countdown-clock').style.display = 'flex';
       	document.querySelector('.days-clock-value').innerHTML = days;
       	document.querySelector('.hours-clock-value').innerHTML = hours;
       	document.querySelector('.mins-clock-value').innerHTML = minutes;
       	document.querySelector('.secs-clock-value').innerHTML = seconds;
   
         // If the count down is over, write some text 
         if (distance < 0) {
           clearInterval(x);
           document.querySelector("h2.end-notice").textContent = '<?php echo $end_notice; ?>';
       		document.querySelector('.devgirl-countdown-clock').style.display = 'none';
         }
       }, 1000);
       </script>	
   
   
   
       <?php } //END devgirl_countdown_clock_function
   
       add_shortcode('devgirl-countdown-clock', 'devgirl_countdown_clock_function');
   
   
   
   
   
   
   
       // front end stylesheet
       function devgirl_countdown_clock_frontend_style() {
           wp_enqueue_style( 'countdown-clock-frontend', plugins_url( '/style/countdown-clock-frontend.css' , __FILE__ ) );
       }
       add_action( 'wp_enqueue_scripts', 'devgirl_countdown_clock_frontend_style' );
   
   
   
       // backend admin stylesheet
       function devgirl_countdown_clock_backend_style() {
           wp_enqueue_style( 'countdown-clock-backend', plugins_url( '/style/countdown-clock-backend.css' , __FILE__ ) );
       }
       add_action( 'admin_enqueue_scripts', 'devgirl_countdown_clock_backend_style' );
   
       ?>
       ```
   
 *  And then the user can call the shortcode in WordPress using something as simple
   as this:
 *     ```wp-block-code
       [devgirl-countdown-clock time="3 Jul 2023 8:00"]
       ```
   

Viewing 8 replies - 1 through 8 (of 8 total)

 *  [Jayson Gumanid](https://wordpress.org/support/users/jaygumanid/)
 * (@jaygumanid)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16335128)
 * The problem is that the `countdownBlocks` function and the `let x` variable are
   defined within the `devgirl_countdown_clock_function` function, but they are 
   not marked as local to the function by using the `local` keyword. As a result,
   when the function is called multiple times, these variables are re-declared and
   you get an error because the `let` keyword does not allow re-declaration of the
   same variable.
 * To fix this, you can wrap the entire block of code in the `devgirl_countdown_clock_function`
   function in a block like this:
 * {
   // code here}
 * And then mark the `countdownBlocks` function and the `let x` variable as local
   to the block by using the `local` keyword like this:
 *     ```wp-block-code
       local function countdownBlocks($clock_colour, $text_colour, $date_value, $date_value_title) {
         // code here
       }
   
       local x = setInterval(function() {
         // code here
       });
       ```
   
 * This will ensure that the `countdownBlocks` function and the `let x` variable
   are only visible within the block, and are not re-declared when the `devgirl_countdown_clock_function`
   function is called multiple times.
 *  Thread Starter [devgirl](https://wordpress.org/support/users/elfynity5/)
 * (@elfynity5)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16335200)
 * Jay, thank you so much for your reply. I am having a hard time following your
   directives and implementing it into my code, I’m not really sure where everything
   is supposed to go and just got critical errors all around. I tried to use “local”
   in front of my function and also got an error. I’m just not sure what local even
   is. Is this kind of what you meant – however, it gives me a critical error:
 *     ```wp-block-code
       function devgirl_countdown_clock_function($atts = '', $content = null) { 
   
       		$value = shortcode_atts( array(
       			'time' => "5 December 2023 8:00",
       			'end-notice' => "Countdown Ended",
       			'clock-colour' => "#011c25",
       			'text-colour' => "DarkTurquoise",
       		), $atts, 'devgirl_countdown_clock_function' );
   
       		$time = sanitize_text_field($value['time']);	
       		$end_notice = sanitize_text_field($value['end-notice']);	
       		$clock_colour = sanitize_text_field($value['clock-colour']);
       		$text_colour = sanitize_text_field($value['text-colour']);
   
   
       		{
       	?>
   
   
   
   
   
       		<h2 class="end-notice"></h2>
   
   
   
   
       		<div class="devgirl-countdown-clock">
       			<?php 
       			if ( ! function_exists( 'countdownBlocks' ) ) {
       			local function countdownBlocks($clock_colour, $text_colour, $date_value, $date_value_title) { ?>
   
       				<div class="countdown-block" style="background:<?php echo esc_html($clock_colour); ?>; color:<?php echo esc_html($text_colour); ?>">
       					<div class="clock <?php echo esc_html($date_value); ?>-clock-value"></div>
       					<div class="text"><?php echo esc_html($date_value_title); ?></div>
       				</div><!---countdown-block-->
       				<div class="separators">:</div>
   
   
       			<?php }
   
   
       			countdownBlocks($clock_colour, $text_colour, 'days', 'Days');
       			countdownBlocks($clock_colour, $text_colour, 'hours', 'Hours');
       			countdownBlocks($clock_colour, $text_colour, 'mins', 'Mins');
       			countdownBlocks($clock_colour, $text_colour, 'secs', 'Secs');
   
       			} else {
       				echo 'The function name already exists and cannot be run. Plese check all your plugins function names to find the conflict.';
       			}
       			?>
   
       		</div><!---devgirl-countdown-clock-->
   
   
   
   
   
   
       	<script type="text/javascript">
       	// Set the date we're counting down to
       	const countDownDate = new Date('<?php echo esc_html($time); ?>').getTime();
   
       		// Update the count down every 1 second
       		local x = setInterval(function() {
   
       		// Get today's date and time
       		let now = new Date().getTime();
   
       		// Find the distance between now and the count down date
       		let distance = countDownDate - now;
   
       		// Time calculations for days, hours, minutes and seconds
       		let days = Math.floor(distance / (1000 * 60 * 60 * 24));
       		let hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
       		let minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
       		let seconds = Math.floor((distance % (1000 * 60)) / 1000);
   
       		// Output the result in an element with id="demo"
   
       		document.querySelector('.devgirl-countdown-clock').style.display = 'flex';
       		document.querySelector('.days-clock-value').innerHTML = days;
       		document.querySelector('.hours-clock-value').innerHTML = hours;
       		document.querySelector('.mins-clock-value').innerHTML = minutes;
       		document.querySelector('.secs-clock-value').innerHTML = seconds;
   
       		// If the count down is over, write some text 
       		if (distance < 0) {
       			clearInterval(x);
       			document.querySelector("h2.end-notice").textContent = '<?php echo esc_html($end_notice); ?>';
       			document.querySelector('.devgirl-countdown-clock').style.display = 'none';
       		}
       	}, 1000);
       	</script>	
   
   
   
       	<?php 
       		}
   
       } //END devgirl_countdown_clock_function
   
       add_shortcode('devgirl-countdown-clock', 'devgirl_countdown_clock_function');
       ```
   
 * I’m sorry, I’m just really new to all this so my understanding is limited to 
   basics.
 *  Moderator [bcworkz](https://wordpress.org/support/users/bcworkz/)
 * (@bcworkz)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16339460)
 * > I’m just not sure what local even is
 * Then it’s time to learn 🙂 Local, or more broadly, [“variable scope”](https://www.w3schools.com/js/js_scope.asp)
   is a very important concept to grasp. Once you have a good understanding, hopefully
   Jay’s suggestions will make more sense.
 * You’e encountered a common problem with shortcodes and JS. You can include JS
   within shortcode output, but then it needs to be specially written so that multiple
   instances of the JS code can occur on the same page without error. Plus it’s 
   wasteful to have the same code over and over on one page.
 * As you surmised, you could enqueue your JS instead. But then, if the page has
   no shortcodes the JS is needed for, it’s wasteful to enqueue it anyway. Many 
   plugins do this anyway. It’s also inefficient to have code that verifies a shortcode
   is in use prior to enqueuing the related JS. Blindly enqueuing, whether needed
   or not is the lesser of two evils?
 * I’ve not done so (JS isn’t my forte), but I believe it’s feasible for your shortcode
   to include a brief JS snippet to check if the bulk of your JS has been loaded,
   and if not, dynamically load it at run time. Then it’ll be available for other
   shortcode instances without needing to declare the same code over and over. Nor
   would you need to load it when it’s not needed at all. Clearly a more advanced
   approach. You might not be in a good place to try something like this. But it’s
   possibly the best approach if you’re willing to dive in deep.
 *  Thread Starter [devgirl](https://wordpress.org/support/users/elfynity5/)
 * (@elfynity5)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16339565)
 * Hi bcworkz, so I actually found an example script that I want to run past you
   two and see if I am on the right track here with regards to localization. I am
   beginning to understand the concept, but just hoping that I am looking into the
   right way to do it if I implement something based on the following example:
 *     ```wp-block-code
       <?php
   
       // Step 1: Enqueue the script in the shortcode function
   
       function my_shortcode_function($atts) {
         wp_enqueue_script('my-script');
   
         // Step 2: Localize the script to pass data from PHP to JavaScript
         wp_localize_script(
           'my-script',
           'my_shortcode_data',
           array(
             'items' => $items, // An array of items to be passed to the script
           )
         );
   
   
       // Step 3: Output the HTML for the shortcode
         ob_start();
         ?>
         <div class="my-shortcode">
           <ul>
             <?php foreach ($items as $item): ?>
               <li><?php echo esc_html($item); ?></li>
             <?php endforeach; ?>
           </ul>
         </div>
         <?php
         return ob_get_clean();
       }
       add_shortcode('my_shortcode', 'my_shortcode_function');
   
       Then, in your JavaScript file, you can access the my_shortcode_data object to access the items array. For example:
   
       // Step 4: Use the data in the script
   
       console.log(my_shortcode_data.items); // Outputs the array of items
       ```
   
 *  Thread Starter [devgirl](https://wordpress.org/support/users/elfynity5/)
 * (@elfynity5)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16340829)
 * I have created the simplest form of my plugin that I could to help sort out this
   issue.
 *     ```wp-block-code
       function testing1_shortcode($atts = '', $content = null) { 
   
       	$value = shortcode_atts( array(
       		'seconds' => "2000"
       	), $atts, 'testing1_shortcode' );
   
       	$seconds = $value['seconds'];
   
       ?>
   
       <div class="timer">
       </div><!---timer-->
   
   
   
   
       <?php
       } // END shortcode
   
       add_shortcode('testing-variable-scope', 'testing1_shortcode');
       ?>
   
   
   
       <script type="text/javascript">
       	let time = "<?php echo $seconds; ?>";
       	let timerBlock = document.querySelector(".timer");
   
       	function timer() {
       		timerBlock.innerText = time;
   
       		if (time < 0) {
       			timerBlock.innerText = "Time's up!";
       			clearInterval();
       		}
       		time--;
       	}
   
       	setInterval(timer, 1000);		
   
       </script>	
       ```
   
 * I have moved the js to outside the shortcode block now, and even now, it is still
   not working. I just don’t know what a working example would look like to replicate
   variable scope. Please could someone paste a working code using my above example
   so I can get an idea of what works and learn from it. I have learnt variable 
   scope in the last day, I have understood the concept of redeclaration and still
   I honestly don’t know how to fix this.
 *  Thread Starter [devgirl](https://wordpress.org/support/users/elfynity5/)
 * (@elfynity5)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16341851)
 * I’m trying a new approach. This works in a plain PHP file:
 *     ```wp-block-code
       	<div class="timer1"></div> 	
       	<div class="timer2"></div> 
   
   
   
       	<script type="text/javascript">
   
       	let myTime;
       	let timerDiv;
   
       	function timer(timerDiv, myTime) {
   
       		//myTime = 5000;
       		timerDiv = document.querySelector(timerDiv);
   
   
       		function timer() {
       			timerDiv.innerText = myTime;
   
       			if (myTime < 0) {
       				timerDiv.innerText = "Time's up!";
       				clearInterval();
       			}
       			myTime--;
       		}
   
       		setInterval(timer, 1000);		
   
       	}
   
       		timer('.timer1',5051);
       		timer('.timer2',6000);
   
   
       	</script>
       ```
   
 * But when I implement it on my WordPress shortcode side, it keeps giving me the
   error that TimerDiv is NULL:
 *     ```wp-block-code
       	<?php
       	function testing1_shortcode($atts = '', $content = null) { 
   
       		$value = shortcode_atts( array(
       			'name' => "myTimer",
       			'seconds' => "2000"
       		), $atts, 'testing1_shortcode' );
   
       		echo $name = $value['name'];
       		echo $seconds = $value['seconds'];
   
       	?>
   
   
   
   
       	<div class="<?php echo $name; ?> timer">
       	</div><!---<?php echo $name; ?>-->
   
       	<div class="mynewtimer"></div>
   
   
   
   
       	<script>
   
   
   
       	function timer(timerDiv, myTime) {
   
       		timerDiv = document.querySelector(timerDiv);
   
       		function timer() {
       			timerDiv.innerText = myTime;
   
       			if (myTime < 0) {
       				timerDiv.innerText = "Time's up!";
       				clearInterval();
       			}
       			myTime--;
       		}
   
       		setInterval(timer, 1000);	
       	} // timer	
   
   
   
       	timer('<?php echo $name; ?>',<?php echo $seconds; ?>);
   
       	</script>
   
       	<?php
   
   
   
       	} // END shortcode
   
       	add_shortcode('testing-variable-scope', 'testing1_shortcode');
       ```
   
 * In an external JS file:
 *     ```wp-block-code
       	let myTime;
       	let timerDiv;
       ```
   
 * And using these 2 shortcodes to try display in a page, but the countdown itself
   is not showing:
 * [testing-variable-scope name=”timer1″ seconds=”6000″]
 * [testing-variable-scope name=”timer2″ seconds=”11000″]
    -  This reply was modified 3 years, 5 months ago by [devgirl](https://wordpress.org/support/users/elfynity5/).
    -  This reply was modified 3 years, 5 months ago by [devgirl](https://wordpress.org/support/users/elfynity5/).
    -  This reply was modified 3 years, 5 months ago by [devgirl](https://wordpress.org/support/users/elfynity5/).
 *  Thread Starter [devgirl](https://wordpress.org/support/users/elfynity5/)
 * (@elfynity5)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16341909)
 * I had a mistake in my timerDiv, I fixed it, it works! Instead of
 *     ```wp-block-code
       timerDiv = document.querySelector(timerDiv);
       ```
   
 * I needed to have:
 *     ```wp-block-code
       timerDiv = document.querySelector('.'+timerDiv);
       ```
   
 *     ```wp-block-code
       	function timer(timerDiv, myTime) {
   
       		timerDiv = document.querySelector('.'+timerDiv);
   
       		function timer() {
       			timerDiv.innerText = myTime;
   
       			if (myTime < 0) {
       				timerDiv.innerText = "Time's up!";
       				clearInterval();
       			}
       			myTime--;
       		}
   
       		setInterval(timer, 1000);	
       	} // timer	
   
   
   
       	timer('<?php echo $name; ?>',<?php echo $seconds; ?>);
       ```
   
 *  Moderator [bcworkz](https://wordpress.org/support/users/bcworkz/)
 * (@bcworkz)
 * [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16343014)
 * FWIW, the “localize” in PHP’s `wp_localize_script()` is entirely unrelated to“
   local” and variable scope in JS. Localization (sometimes abbreviated “l10n” because
   there are 10 chars between the l and n) mainly has to do with how certain data
   is formatted on output, like date format, or whether a decimal point is a dot
   or a comma, the local currency sign, etc. We actually slightly misuse `wp_localize_script()`
   by passing arbitrary PHP values to JS that have nothing to do with actual localization.
   But it serves a need, so we use it.
 * Keep in mind that JS isn’t my forte. I think the issue you’re running into is
   the inner declaration of `timer()`. Within its scope, you try to assign something
   to timerDiv.innerText without first establishing what that object is. I’m unclear
   what the inner `timer()` declaration is for, it doesn’t seem to be called anywhere
   in the outer `timer()`.
 * I don’t think it’s good practice to use the same function name in two different
   instances, even if scoping allows it to work. Maybe you’re clear on what’s going
   on, but I’m confused 🙂
 * Since you’re already enqueuing, IMO you may as well enqueue the bulk of your 
   JS. Enqueued functions should not be declared local. The only JS within your 
   shortcode should be the call to your main JS function that’s doing the heavy 
   lifting. Avoid vars in any shortcode script, try to work directly on the related
   DOM objects. If you do need vars within the shortcode, they all should be local
   to that script.
 * I think enqueuing the bulk of your JS is your best chance of getting something
   working. You may or may not choose to make it all more efficient later, but for
   now it’s best to focus on getting something working by the simplest means possible.

Viewing 8 replies - 1 through 8 (of 8 total)

The topic ‘Using javascript in Shortcode Callback when creating new plugin’ is closed
to new replies.

## Tags

 * [javascript](https://wordpress.org/support/topic-tag/javascript/)
 * [plugin-development](https://wordpress.org/support/topic-tag/plugin-development/)

 * In: [Developing with WordPress](https://wordpress.org/support/forum/wp-advanced/)
 * 8 replies
 * 3 participants
 * Last reply from: [bcworkz](https://wordpress.org/support/users/bcworkz/)
 * Last activity: [3 years, 5 months ago](https://wordpress.org/support/topic/using-javascript-in-shortcode-callback-when-creating-new-plugin/#post-16343014)
 * Status: not resolved

## Topics

### Topics with no replies

### Non-support topics

### Resolved topics

### Unresolved topics

### All topics
