I am creating a WordPress widget that shows and advert. When the advert is clicked I want to record the clicks with some detail.
The database table is already created and entries can be saved correctly using the function f1_add_advert_click($advert_id) in save-advert-click.php, which resides in the same directory as the Widget's PHP that I want to call it from (the plugin's root directory).
Requirements:
link will be on a piece of text, just a plain a href
a visitor should see the target link when he hovers his cursor over the link, not appended by a parameter for the next page
no 'middle' page that registers the click then redirects onto the target page. Just straight from the origin to the target.
secure: the advert ID is passed on to the f1_add_advert_click function and then inserted into the database. I would like to be sure that it's the correct ID (not something a visitor could change).
there can be multiple instances of this Widget on a page
I have seen and tried a lot of examples on Stackoverflow, but either I don't get it or the situation there is different from mine. Would gladly appreciate a well commented code example that works in my situation. Please be aware that I am not a seasoned programmer, especially 'green' when it comes to JavaScript and jQuery.
From what I have read on the web I think I should be using AJAX to first register the click, then send the browser to the target page. Not sure if I have to use onclick or not, based on the bottom answer of this post.
Have put in about four hours so far on this part. Now asking for help. Not much code to show, because I deleted everything that didn't work.
This is what I have currently got within the widget function of the plugin (left out the regular php showing title and so on):
<script type="text/javascript">
function myAjax() {
$.ajax({
type: "POST",
url: './wp-content/plugins/facilitaire-advert-widget/save-advert-click.php',
data:{action:'call_this'},
success:function(html) {
alert(html);
}
});
}
</script>
Followed by the link and the click action
<p>Link of Advert
Then these are my contents for save-advert-click.php
// check for action signal
if($_POST['action'] == 'call_this') {
f1_add_advert_click ();
}
/**
* Records a click event in the database
*/
function f1_add_advert_click ()
{
$advert_id = random_int(1,300); // change to $clicked_advert_id later
$user_ip = get_user_ip();
global $wpdb;
$table_name = $wpdb->prefix . 'f1_advert_clicks';
$wpdb->insert( $table_name, array(
'advert_id'=> $advert_id,
'user_agent'=> $_SERVER['HTTP_USER_AGENT'],
'ip_address'=> $user_ip
),
array(
'%d',
'%s',
'%s'
)
);
}
/**
* Get user IP
*/
function get_user_ip()
{
$client = #$_SERVER['HTTP_CLIENT_IP'];
$forward = #$_SERVER['HTTP_X_FORWARDED_FOR'];
$remote = $_SERVER['REMOTE_ADDR'];
if ( filter_var($client, FILTER_VALIDATE_IP) ) {
$ip = $client;
} elseif ( filter_var($forward, FILTER_VALIDATE_IP) ) {
$ip = $forward;
} else {
$ip = $remote;
}
return $ip;
}
UPDATE WITH SOLUTION
Thanks to #mplungjan's suggestion I updated my code to the following, working code. Please note some differences with #mplungjan's code, because I had to make some adjustments to make it work in WordPress.
contents of bottom part of show-advert.php
<script>
jQuery(function() {
jQuery(".advertLink").on("click",function(e) {
e.preventDefault(); // stop the link unless it has a target _blank or similar
var href = this.href;
var id= <?php echo $advert_id; ?>;
jQuery.post("<?php echo get_home_url(); ?>/wp-content/plugins/facilitaire-advert-widget/save-advert-click.php",
{ "action":"register_click", "advert_id":id },
function() {
location=href;
}
);
});
});
</script>
Link of Advert<br />
<?php
Then in the top part of save-advert-click.php I have
<?php
// check for action signal
if($_POST['action'] == 'register_click') {
f1_add_advert_click( $_POST["advert_id"] );
}
/**
* Records a click event in the database
*/
function f1_add_advert_click ( $advert_id )
{
$user_ip = get_user_ip();
// need to load WordPress to be able to access the database
define( 'SHORTINIT', true );
require_once( '../../../wp-load.php' ); // localhost needs this, production can have require_once( $_SERVER['DOCUMENT_ROOT'] . '/wp-load.php' );
global $wpdb;
$table_name = $wpdb->prefix . 'f1_advert_clicks';
$wpdb->insert( $table_name, array(
'advert_id'=> $advert_id,
'user_agent'=> $_SERVER['HTTP_USER_AGENT'],
'ip_address'=> $user_ip
),
array(
'%d',
'%s',
'%s'
)
);
}
You will want to do something like
$(function() {
$(".advertLink").on("click",function(e) {
e.preventDefault(); // stop the link unless it has a target _blank or similar
var href = this.href;
var id=this.id; // or $(this).data("advertid") if you have data-advertid="advert1" on the link
$.post("./wp-content/plugins/facilitaire-advert-widget/save-advert-click.php",
{ "action":"call_this", "advert_ID":id },
function() {
location=href; // or window.open
}
);
});
});
using
Link of Advert
Related
I have about 60 landing pages that use different phone numbers on them. I am using a combination of WordPress and Advanced Custom Fields to place the phone numbers on their respective pages.
I am being asked to show a <div> based on the landing page URL that will not only show the phone number assigned to that page, but, keep showing the <div> (and phone number) regardless of what page the user navigates to on the website.
I have found little to no support on how to make the <div> remain visible throughout the entire session until the user closes the window.
I am thinking that this will somehow revolve around a cookie and Dynamic Number Insertion but I have no real progress to speak of. Should this be done using PHP or JS? Does a plugin exist that would allow for this on WordPress? I'm open to all suggestions.
Please try this code. Like #John C mentioned, WP Engine doesn't recommend Cookie nor PHP Session for the sake of performance and security. This is pure JavaScript code, and I think this will solve your problem.
Code in your Post/Page template file:
<div id="phone-number"></div>
<?php if( get_field('phone_number') ): ?>
<script type="text/javascript">
let phone_number = "<?php the_field('phone_number'); ?>";
</script>
<?php endif; ?>
Code in your theme JavaScript file:
<script type="text/javascript">
// in the case of the div data is persistent on the same site
// let storage = localStorage;
// in the case of the div data is persistent in the same tab, but not in new tab
let storage = sessionStorage;
let key = "phone_number"; // storage key
var global_phone_number = storage.getItem(key);
// check if storage data is set before
if (null === global_phone_number) {
// if not set the data on page into storage
global_phone_number = phone_number ? phone_number : '';
storage.setItem(key, global_phone_number);
}
document.getElementById('phone-number').innerHTML = global_phone_number;
</script>
You should use PHP and capture the session.
(untested code warning)
add_action('wp_footer', 'dynamic_phone_div');
function dynamic_phone_div() {
session_start;
if(isset($_SESSION['phone_div']) ? $phone_div = $_SESSION['phone_div'] :
$phone_div = '';
if($phone_div != '') {
echo '<div class="that_div_thing">';
echo $phone_div;
echo '</div>';
} else {
$_SESSION['phone_div'] = 123456789;
echo '<div class="that_div_thing">';
echo '123456789';
echo '</div>';
}
}
This is only raw logic. I am not sure where your div is (header/footer/page) - depending on where it is you should either use a hook (header/footer) or code it into a template (page/post).
The session will be destroyed after the user closes the tab/window.
I would probably do this with client side session storage. Providing all pages open in the same tab, the value will remain for the session, then be removed.
PHP code (in your functions.php file?) would be something like this:
function phone_script() {
$params = array(
'phone_number' => null, // Insert logic for current number. Can stay null if this is running on a non-landing page
'is_landing_page' => false // Change to true/false based on is current page a landing one or not
);
$params = json_encode( $params );
echo <<< EOT
<script>
let settings = $params;
document.addEventListener("DOMContentLoaded", function() {
if( settings.is_landing_page ) {
window.sessionStorage.setItem( 'phone-number', settings.phone_number );
} else {
settings.phone_number = window.sessionStorage.getItem( 'phone-number' );
}
if( settings.phone_number ) {
let div = document.createElement('div');
div.classList.add('phone-div');
// or add inline style
// div.style.cssText = 'position:fixed'; //etc
// Some logic here to actually add the number and any other content to the div
div.innerHTML = `The Phone number is: ${settings.phone_number}`;
document.body.appendChild(div);
}
});
</script>
EOT;
}
add_action( 'wp_footer', 'phone_script');
Note that the EOT; line MUST have no leading or trailing spaces.
The above is untested.
I have two forms in my wordpress website. I need to redirect users to another page after submitting just only one form. So tried with this javascript if condition with contact form 7 ID.
document.addEventListener( 'wpcf7mailsent', function( event ) {
setTimeout(function(){
location = 'https://example.com/';
}, 2500);
}, false );
Above code applied for all pages so I modified it with if condition this way.
document.addEventListener( 'wpcf7mailsent', function( event ) {
if('2168' == event.detail.contactFormId){
setTimeout(function(){
location = 'https://example.com/';
}, 2500) } ;
}, false );
But surprisingly it didn't work. Any ideas?
Above code applied for all pages so I modified it with if condition this way.
this is inefficient, you should target the page where your form is being displayed using:
add_filter('do_shortcode_tag', 'redirect_form_script', 10,3);
function redirect_form_script($output, $tag, $attrs){
//check this is your form, assuming form id = 1, replace it with your id.
if($tag != "contact-form-7" || $attrs['id']!= 2168) return $output;
$script = '<script>'.PHP_EOL;
$script .= 'document.addEventListener( "wpcf7mailsent", function( event ){'.PHP_EOL;
//add your redirect page url.
$script .= ' location = "http://example.com/submitted/?cf7="'.PHP_EOL;
$script .= ' }'.PHP_EOL;
$script .= '</script>'.PHP_EOL;
return $output.PHP_EOL.$script;
}
Poor me. I was using an old version of contact form 7. After plugin upgrade, it works.
I've got a complicated little problem here.
I'm building a WordPress plugin where I select a "parent" post (of a custom type that I made called 'step') and then an AJAX function shows a new select bar with all of the children of that parent. I do this by outputting the new and elements in the PHP file that's called in the AJAX function. This works, but now I want to repeat the process to run a function from the same JQuery file when this new outputted element is added to the page. (See Javascript code)
Main php plugin file (in a folder within the plugin directory):
<?php
/*
Plugin Name: n8jadams Step by Step Plugin (WIP)
Plugin URI:
Description:
Author: Nathan James Adams
Author URI: http://nathanjamesadams.com
Version: 0.0.1a
*/
//Exit if accessed directly
if(!defined('ABSPATH')) {
exit;
}
//My custom post type, it works fine
require_once(plugin_dir_path(__FILE__).'n8jadams-step-funnel-cpt.php');
require_once(plugin_dir_path(__FILE__).'n8jadams-ajax.php');
//Add my javascript
function n8jadams_init_javascript() {
wp_register_script('n8jadams_javascript', plugin_dir_url(__FILE__).'n8jadams-scripts.js', array('jquery'),'1.1', false);
wp_enqueue_script('n8jadams_javascript');
}
add_action('wp_enqueue_scripts', 'n8jadams_init_javascript');
//Adds a plugin menu to the wordpress sidebar
function n8jadams_add_plugin_menu() {
add_menu_page('', 'Steps Settings', 4, 'steps-settings', 'n8jadams_steps_settings', '');
}
add_action('admin_menu', 'n8jadams_add_plugin_menu');
//The actual function for the menu page
function n8jadams_steps_settings() {
//Access the database and the tables we want
global $wpdb;
$posts = $wpdb->prefix.'posts';
//Get the user id
$user = wp_get_current_user();
$userid = $user->ID;
//Initialize javascript (it works here!)
n8jadams_init_javascript();
/* Get all the parents */
$parentsquery = "
SELECT `ID`, `post_title`
FROM $posts
WHERE `post_author` = $userid
AND `post_parent` = 0
AND `post_status` = 'publish'
AND `post_type` = 'step'
";
$parentsarray = $wpdb->get_results($parentsquery);
?>
<h4>My Forms:</h4>
<select id="parentselect">
<option id="-1"> - Select Your Step Form - </option>
<?php
//output the parents
for($i=0;$i<sizeof($parentsarray);$i++) {
echo '<option id="'.$parentsarray[$i]->ID.'">'.$parentsarray[$i]->post_title.'</option>';
}
?>
</select>
<div id="displayChildren"></div>
<?php
}
?>
Javascript (n8jadams-scripts.js):
(function($){
$('#parentselect').change(function(s) {
var thisID = s.target[s.target.selectedIndex].id;
var outputDisplay = document.getElementById('displayChildren');
if(thisID != '-1') {
$.ajax({
type: 'POST',
url: 'admin-ajax.php',
data: {
action: 'n8jadams_get_children',
id: thisID
},
success: function(response){
if(response == "") {
outputDisplay.textContent = "This form has no children. Add them in the sidebar menu of this step form.";
} else {
outputDisplay.innerHTML = response;
}
},
error: function(errorThrown) {
alert(errorThrown);
}
});
} else {
outputDisplay.textContent = '';
}
});
// I want this function to work
/*
$('#childselect').change(function(t) {
console.log("test");
});
*/
})(jQuery);
PHP file called by AJAX (n8jadams-ajax.php):
<?php
function n8jadams_get_children() {
//Get the id of the parent
$parent_post_id = $_POST['id'];
//Sanitize the input (Added after question was answered)
$parent_post_id = preg_replace("/[^0-9]/","",$parent_post_id);
//Access database
global $wpdb;
$posts = $wpdb->prefix.'posts';
$user = wp_get_current_user();
$userid = $user->ID;
$childrenquery = "
SELECT `ID`, `post_title`,`post_content`
FROM $posts
WHERE `post_parent` = $parent_post_id
AND `post_status` = 'publish'
AND `post_type` = 'step'
AND `post_author` = $userid
";
//Retrieve the children associated with this parent
$childrenarray = $wpdb->get_results($childrenquery);
//Initialize Javascript (it doesn't work here!)
n8jadams_init_javascript();
if(!empty($childrenarray)) { ?>
<h4>My Steps:</h4>
<select id="childselect">
<option id="-1"> - Select Your Step - </option>
<?php
//output the children of the parent
for($i=0;$i<sizeof($childrenarray);$i++) {
echo '<option id="'.$childrenarray[$i]->ID.'">'.$childrenarray[$i]->post_title.'</option>';
} ?>
</select>
<?php wp_die();
}
}
add_action('wp_ajax_n8jadams_get_children', 'n8jadams_get_children');
add_action('wp_ajax_nopriv_n8jadams_get_children', 'n8jadams_get_children');
?>
Screenshot of Plugin Menu
I cannot figure out why my javascript file isn't working in the PHP file that's called by AJAX. Maybe the vast wisdom of the StackOverflow can help me. Thanks for the help in advance. :)
You are hooking into wp_enqueue_scripts, which is only run for the frontend of Wordpress (the part the average visitor sees). If you want to load a script into wp-admin, the backend of Wordpress, use the admin_enqueue_scripts action.
Since this code does not work in /wp-admin/, you don't need to use admin_enqueue_scripts. I guess the whole problem would be that you are attaching a handler to $('#childselect'), while no such element exists on the page at that time. Use deferring with $(..).on(..):
$(document).on('change', '#childselect', function(e) {
//Black magic
});
Side note: As already mentioned in the comments, the following part contains an unsanitised variable which will allow an attacker to perform sql injections.
$childrenquery = "
SELECT `ID`, `post_title`,`post_content`
FROM $posts
WHERE `post_parent` = $parent_post_id
AND `post_status` = 'publish'
AND `post_type` = 'step'
AND `post_author` = $userid
";
Use WP_Query if at all possible. If this is only used from the backend of Wordpress, don't use wp_ajax_nopriv_*, because users that are not logged in into your site have no right to use that anyway.
Should be fairly simple and have had a good search around the web, but most solutions are too complex.
Trying to implement a jquery menu system and need to add a body ID to the main body of my Wordpress site in order to target by ID, easier I think that way.
I would like to add this via functions.php to avoid touching the theme header files directly in child theme incase of updates etc.
So far I have the below - doesn't seem to be working though haha, so I've clearly missed something obvious!
Trying to target all pages, then add the id 'st-container'
Thanks in advance:
// create a custom function
function my_custom_body_id($id) {
if ( is_page() ) $id = 'st-container';
return $id;
};
add_filter('body_id','my_custom_body_id');
From https://codex.wordpress.org/Function_Reference/body_class
add_filter( 'body_class', 'my_class_names' );
function my_class_names( $classes ) {
// add 'st-container' to the $classes array
if(is_page()) {
$classes[] = 'st-container';
}
// return the $classes array
return $classes;
}
Give that a go - you need to return an array
template (header.php)
<body <?php body_id(); ?>>
functions.php
function body_id() {
if( is_page_template('page-service.php') ) {
$id = 'id="service-page"';
}
echo $id;
}
my view-source output was
<body id="service-page">
I cant understand why my code does not work.
I have a tabel wp_subscibe with id, user_id and post_id. I want after click on button to add this data to my db by ajax. Please, look at my code.
This is my html in single.php:
<button type="submit" name="subscribe" id="subscribe">Subscribe</button>
<input id="postId" type="hidden" value="<?php the_ID(); ?>" />
My subscribe.js:
onSubscribe: function() {
var $onSubscr = $('#subscribe');
$onSubscr.on('click', function() {
var $el = $(this),
post_id = $('#postId').val(),
$.ajax({
type:"POST",
url: admin_url.ajaxurl,
dataType:"json",
//data : 'action=subscribeOn&post_id='+post_id
data: {
action: 'subscribeOn',
post_id: post_id
},
cache: false
});
return false;
});
}
And functions.php:
wp_register_script( 'subscribe', THEME_DIR . '/js/subscribe.js', array(), '', false );
wp_enqueue_script( 'subscribe' );
wp_localize_script( 'subscribe', 'admin_url', array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ));
function subscribeOn() {
global $wpdb, $user_id, $post_id;
$user_id = get_current_user_id();
$post_id = $_POST['post_id'];
// $table_name = $wpdb->prefix . "subscribe";
$wpdb->insert("wp_subscribe", array( 'user_id'=>$user_id, 'post_id'=>$post_id), array('%s','%s'));
}
add_action( 'wp_ajax_nopriv_subscribeOn', 'subscribeOn' );
add_action('wp_ajax_subscribeOn', 'subscribeOn)');
Can anybody tell me where is my problem? Nothing happens in wp_subscribe in db. I try so many ways, but nothing works.
For debug of javascript you need to get used to using the console (for chrome, right click on the page and "inspect element" you will see console on the top of the pop up. This will list any errors or outputs from js.
A common mistake with jQuery and wordpress is to use $ without defining it, so you need $='jQuery'; before you can use the $ operator to refer to jQuery or substitute the use of $ for the word jQuery. Look up no conflict jQuery for more information.
Another common error in wp ajax and localize script is ajaxurl. For the moment enter in the static value which is www.yourserver.com/wp-admin/admin-ajax.php in most set ups, the wp-admin folder could be somewhere else on your server of course. You should test using console.log(admin_url.ajaxurl); the output will appear in the console mentioned earlier.
Updated code (dont wrap in a function and assign to a variable, just use it as is.
$=jQuery;
$(document).on('click', '#subscribe', function() {
var post_id = $('#postId').val();
$.ajax({
type:"POST",
url: '/wp-admin/admin-ajax.php', // common error is ajax.url undefined (insert your home url into the start of the string, we will eliminate any possibility of mistake by using a static url.
//dataType:"json",
//data : 'action=subscribeOn&post_id='+post_id
data: {
action: 'subscribeOn',
post_id: post_id
},
success: function(data) {
console.log(data); //this writes any output from the server into the console, so if theres a respose you know ajaxurl and jquery is more or less correct, so its good to return something whilst testing...
},
cache: false
});
});
now for the server. When testing you should return something (any data you output using echo var_dump etc will be returned and as we added a command in our browser code to output this to the console we can check for it there.
function subscribeOn() {
global $wpdb, $user_id, $post_id;
$user_id = get_current_user_id();
$post_id = $_POST['post_id'];
// we insert this to test the jQuery settings are correct. if one of the below does not appear in the console, we have issues in jQuery.
if($post_id):
echo $post_id;
else:
echo 'no post id is being submitted check selectors';
endif;
$success= $wpdb->insert("wp_subscribe",
array( 'user_id'=>$user_id, 'post_id'=>$post_id),
array('%s','%s')
);
if($success):
echo 'successfully inserted';
else:
echo 'not inserted, is the table name correct, etc? does the function work elsewhere?';
endif;
}
add_action( 'wp_ajax_nopriv_subscribeOn', 'subscribeOn' );
add_action('wp_ajax_subscribeOn', 'subscribeOn)');
hopefully this will sort it. If it does hit the correct icon beside this answer :)
I found the right way myself. it was just because one bracket after subscribeOn!
add_action('wp_ajax_subscribeOn', 'subscribeOn)');