I'm using Wordpress, and am successful at displaying a map on my site with multiple markers using GMaps. Unfortunately, I was hoping to have the "location name" hyperlinked to the relevant post on my site. For some reason though, I can't add a hyperlink to the infowindow without crashing the whole map.
Below is the functioning code, as soon as I remove the strip_tags(); function the map no longer displays. I'm guessing it's related to having too many ", but I can't figure out how to get it working.
$str = '';
foreach($loop as $p){
//get the meta and taxonomy data
$name = strip_tags(get_the_term_list($p, "mountains"));
$wtr_long = get_post_meta($p,"wtr_longitude",true);
$wtr_lat = get_post_meta($p,"wtr_latitude",true);
//Add to Array
$map_string .= '{latitude: "' . $wtr_lat . '", longitude: "' . $wtr_long . '", html: "' . $name .'"},~!~';
//$map_string .= '{latitude: "' . $wtr_lat . '", longitude: "' . $wtr_long . '", html: "name"},~!~';
}
//Remove last three "~!~" characters from the string not to have one too many arrays when exploding
$clean_map_string = substr($map_string, 0, -3);
//Now I can use explode on ~!~ to get arrays with my string
$map_array = explode('~!~', $clean_map_string);
?>
<!--Map implementation-->
<div id="map" style="width:880px; height: 600px; background-color:grey;"></div>
<script type="text/JavaScript">
$("#map").gMap({
scrollwheel: false,
maptype: G_PHYSICAL_MAP,
markers: [
<?php
$i = 0;
$length = count($map_array)-1;
//Inserts all the markers
foreach($map_array as $value){
if( $i != $length ){
echo $value;
}
else {
echo str_replace("},", "}],", $value);
}
$i++;
}
?>
popup: false,
zoom: 2 });
</script>
InfoWindows usually have no problems with tags. You are trying to create a JSON-string there, use json_encode() instead of this mixture of string-functions to avoid invalid characters inside the string.
<?php
$markers=array();
foreach($loop as $p){
$markers[]=array(
'latitude' => get_post_meta($p,"wtr_latitude",true),
'longitude' => get_post_meta($p,"wtr_longitude",true),
'html' => get_the_term_list($p, "mountains")
);
}
?>
<!--Map implementation-->
<div id="map" style="width:880px; height: 600px; background-color:grey;"></div>
<script type="text/JavaScript">
$("#map").gMap({
scrollwheel: false,
maptype: G_PHYSICAL_MAP,
markers: <?php echo json_encode($markers);?>,
popup: false,
zoom: 2 });
</script>
Related
I have based from my code from https://github.com/eKoopmans/html2pdf.js/issues/181 (odedta) comment and also tried the second users comment below theirs.
I have a script using html2pdf bundle. Which works well. It create a multi page PDF with images.
The content of the PDF is data which is pulled from a WordPress category (using a wp Query) and results in 3-6 Posts being put into a PDF.
HTML for example:
<script type="text/javascript" charset="utf8" src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<div id="PDFcontent">
<h1> PDF tile </h1>
<img src="https://styles.redditmedia.com/t5_2r5i1/styles/communityIcon_x4lqmqzu1hi81.jpg?width=256&s=fc15e67e2b431bbd2e93e980be3090306b78be55">
<div class="html2pdf__page-break"></div>
<h2 class="exhibitied-title"> Page 2 title<h2>
Some text
<div class="html2pdf__page-break"></div>
<h2> Page 3 title<h2>
Some text
</div>
I have my Jquery at the bottom of the page
jQuery(function($) {
window.onload = function() {
let el = document.getElementById('PDFcontent');
var title = $('.exhibitied-title').text();
let opt = {
margin: 0.2,
filename: title + '.pdf',
image: {
type: 'jpeg',
quality: 0.99
},
html2canvas: {
scale: 2,
logging: true,
dpi: 192,
letterRendering: true,
/* useCORS: true*/
},
jsPDF: {
unit: 'mm',
format: 'a4',
orientation: 'portrait'
}
};
html2pdf().set(opt).from(el).toPdf().output('datauristring').save().then(function(pdfAsString) {
title = $('.exhibitied-title').text();
filetitle = title + '.pdf';
let data = {
'action': 'send_email_with_pdf',
'fileDataURI': pdfAsString,
'filetitle': filetitle,
}
$.post(myAjax.ajaxurl, data, function(response) {
console.log(response);
});
});
}
});
.save works perfectly, the PDF is formatted exactly how I want it.
But when it comes to saving or emailing the PDF I am having problems.
The email is does send and a PDF is created. However the pdf in the email is 115bytes and just says "Failed to load PDF document." when you try opening it, and the pdf which is saved in my WP uploads folder is 0 bytes and also "Failed to load PDF document." shows.
Inside my functions.php I have
function send_email_with_pdf() {
$pdfdoc = $_POST['fileDataURI'];
$b64file = trim( str_replace( 'data:application/pdf;base64,', '', $pdfdoc ) );
$b64file = str_replace( ' ', '+', $b64file );
$decoded_pdf = base64_decode( $b64file );
//file_put_contents( $attachment, $decodPdf );
$upload_dir = wp_upload_dir();
$image_data = file_get_contents( $decoded_pdf );
$filename = $_POST['filetitle'];
if ( wp_mkdir_p( $upload_dir['path'] ) ) {
$file = $upload_dir['path'] . '/' . $filename;
}
else {
$file = $upload_dir['basedir'] . '/' . $filename;
}
file_put_contents( $file, $image_data );
$mail = new PHPMailer;
$mail->setFrom( 'me#myemail.com', 'My name' );
$mail->addAddress( 'you#youremail.com', 'your name' );
$mail->Subject = 'Subject';
$mail->Body = $filename;
$mail->addStringAttachment($decoded_pdf, $filename);
$mail->isHTML( false );
if( !$mail->send() ) {
$response = 'Message was not sent.';
$response .= 'Mailer error: ' . $mail->ErrorInfo;
}
else {
$response = 'Message has been sent.';
}
wp_send_json( $response );
}
add_action( 'wp_ajax_send_email_with_pdf', 'send_email_with_pdf' );
add_action( 'wp_ajax_nopriv_send_email_with_pdf', 'send_email_with_pdf' );
Is anyone able to point me in the right direction please, or has anyone come across this issue before?
I have posted as much information as I can, but please let me know if you need more information.
I got this working, for anyone else needing it.
I have added notes in the code for explanation
First add this to the top of your page
<script type="text/javascript" charset="utf8" src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
HTML / Wordpress content loop part
<div id="PDFcontent">
<h1 class="mypdftitle"> PDF tile </h1>
<img src="https://styles.redditmedia.com/t5_2r5i1/styles/communityIcon_x4lqmqzu1hi81.jpg?width=256&s=fc15e67e2b431bbd2e93e980be3090306b78be55">
<div class="html2pdf__page-break"></div>
<h2> Page 2 title<h2>
Some text
<div class="html2pdf__page-break"></div>
<h2> Page 3 title<h2>
Some text
</div>
JQuery - goes at the bottom on the page above the footer
jQuery(function($) {
window.onload = function() {
let el = document.getElementById('PDFcontent');
var title = $('.exhibitied-title').text();
let opt = { //Create/design the pdf
margin: 0.2,
filename: title + '.pdf',
image: {
type: 'jpeg',
quality: 0.99
},
html2canvas: {
scale: 2,
logging: true,
dpi: 192,
letterRendering: true,
},
jsPDF: {
unit: 'mm',
format: 'a4',
orientation: 'portrait'
}
};
html2pdf().from(el).set(opt).toPdf() /*add .save() if you need it to download locally too*/.output('datauristring').then(function(res) {
this.blobString = res;
title = $('mypdftitle').text(); //Get the title from h1 html
filetitle = title; //set the title to be send in the ajax
let data = {
'action': 'send_email_with_pdf', //Name of function in functions.php
'fileDataURI': this.blobString,
'filetitle': filetitle, //name of pdf - you set this above
}
$.post(myAjax.ajaxurl, data, function(response) { //myAjax.ajaxurl see the bottom code comment
console.log(response);
console.log(filetitle);
});
console.log(this.blobString);
});
}
});
```
Now in functions.php
function send_email_with_pdf() {
if (isset($_POST['fileDataURI'])) {
/*** Prepare and decode the uri string ***/
$pdfdoc = $_POST['fileDataURI']; // This looks like data:application/pdf;filename=generated.pdf;base64,JVBERi0xLjMKJbrfrOAKMyAwIG9iago8PC9UeXB....
$b64file = str_replace( 'data:application/pdf;filename=generated.pdf;base64,', '', $pdfdoc ) ; //remove data:application/pdf;filename=generated.pdf;base64,
$decoded_pdf = base64_decode( $b64file ); //decode it
/**** Unique naming ****/
$date = date("d-m-y"); // Today date day month year
$time = date("h:i"); // The time
//Adding date and time to the pdf, will make sure each pdf generated is unique
$ext = ".pdf"; //file extension
$thename = $_POST['filetitle']; //The title sent by ajax from the extension page
$name = str_replace( ' ', '-', $thename ) ; //remove spaces - makes urls better
$filename = $name . '-' . $date . '-' . $time . $ext; // combine the file name
//If you dont want date and time, then do the following $filename = $thename . $ext;
/**** Upload directory *****/
$upload_dir = wp_upload_dir();
if (wp_mkdir_p($upload_dir['path'])) { // Puts the file in wp-content/uploads/year/month
$file = $upload_dir['path'].
'/'.$filename;
} else {
$file = $upload_dir['basedir'].
'/'.$filename;
}
/*** Upload it ****/
file_put_contents($file, $decoded_pdf);
/*** Send the email ****/
$mail = new PHPMailer;
$mail->setFrom( 'me#myemail.com', 'My name' );
$mail->addAddress( 'you#youremail.com', 'your name' );
$mail - > Subject = $filename;
$mail - > Body = $filename; //email text goes here, I have made it the file name for example
$mail - > addStringAttachment($decoded_pdf, $filename);
$mail - > isHTML(false);
if (!$mail - > send()) {
$response = 'Message was not sent.';
$response. = 'Mailer error: '.$mail - > ErrorInfo;
} else {
$response = 'Message has been sent.';
$response = $image_data;
}
wp_send_json($response);
}
}
add_action('wp_ajax_send_email_with_pdf', 'send_email_with_pdf');
add_action('wp_ajax_nopriv_send_email_with_pdf', 'send_email_with_pdf');
For those who are unsure about the myAjax.ajaxurl in the JQuery part, Add this to the top of your functions.php in your WordPress theme, and then when ever you want to call Ajax on your site you can use the myAjax.ajaxurl
add_action( 'init', 'script_enqueuer' );
function script_enqueuer() {
wp_register_script( "liker_script", get_stylesheet_directory_uri().'/js/functionality.js', array('jquery') );
wp_localize_script( 'liker_script', 'myAjax', array( 'ajaxurl' => admin_url( 'admin-ajax.php' )));
wp_enqueue_script( 'jquery' );
wp_enqueue_script( 'liker_script' );
}
protected function render() {
$settings = $this->get_settings_for_display();
// Get image URL
echo '<img src="' . $settings['image']['url'] . '">';
// Get image 'thumbnail' by ID
echo wp_get_attachment_image( $settings['image']['id'], 'thumbnail' );
// Get image HTML
echo \Elementor\Group_Control_Image_Size::get_attachment_image_html( $settings );
}
protected function _content_template() {
?>
<img src="{{ settings.image.url }}">
<?php
}
I was able to get the width and height values in php, but I can't get it for the _content_template() function
$media_image = wp_get_attachment_image_src( $settings['media_image']['id'], 'full' );
$image_width = $media_image[1];
$image_height = $media_image[2];
You have to use the method add_render_attribute to add this into the backbonejs part i.e. inside the _content_template:
$this->add_render_attribute( 'image', 'src', $settings['image']['url'] );
add_render_attribute for reference
Once you added the attribute you can access it in _content_template like this:
settings.image.url
settings.image.url for reference
Therefore, the thing you need to add is add_render_attribute method inside the method render to access in _content_template
Mainly focus on this particular snippet of content template method:
var image = {
id: settings.image.id,
url: settings.image.url,
size: settings.thumbnail_size,
dimension: settings.thumbnail_custom_dimension,
model: view.getEditModel()
};
var image_url = elementor.imagesManager.getImageUrl( image );
var imageHtml = '<img src="' + image_url + '" class="elementor-animation-' + settings.hover_animation + '" />';
I am creating a shortcode that grabs specific content from an url which i passed as a shortcode attribute. The problem happens when this a shortcode is used more than once on a single post. Then the second shortcode overrides the first one. Here is the code. Two values are displayed on the page both both are the same and are pulled from the second shortcode attribute. There should be two separate and different values.
Here is the shortcode code:
<?php
function grabUrl_func( $atts ) {
$url = $atts['url'];
$label = $atts['label'];
$productId = $atts['id'];
?>
<script>
var urlFromSc = <?php echo json_encode($url) ?>;
var buttonLabel = <?php echo json_encode($label) ?>;
jQuery(document).ready(function() {
jQuery.get(urlFromSc, function(response) {
// grab product name
var productName = jQuery(response).find('.product-name');
var productNameContent = productName[1]['innerHTML'];
jQuery('.g-title').append(productNameContent);
// grab image
var productImage = jQuery(response).find('.product-image-gallery');
var productImageContent = productImage[0]['innerHTML'];
jQuery('.g-image').append(productImageContent);
jQuery('.g-image img').slice(1).remove();
// grab price
var productPrice = jQuery(response).find('.price-box');
var productPriceContent = productPrice[0]['innerHTML'];
jQuery('.g-price').append(productPriceContent);
// grab rating
var productRating = jQuery(response).find('.yotpo');
var productRatingContent = productRating[0]['outerHTML'];
var productId = jQuery(productRatingContent).attr('data-product-id');
var link = jQuery('<a class="productLink" href="' + urlFromSc + '">' + buttonLabel + '</a>' );
jQuery('.g-link').append(link);
});
});
</script>
<?php
$output = '<div class="g-wrapper">'
. '<div class="g-image"></div>'
. '<div class="g-title"></div>'
. '<div class="g-price"></div>'
. '<div class="g-rating">'
. '<div class="yotpo yotpo-main-widget" data-product-id="'.$productId.'"></div>'
. '</div>'
.'<div class="g-link"></div>'
.'</div>';
return $output;
}
add_shortcode( 'grabUrl', 'grabUrl_func' );
?>
Thanks in advance for your help!
For the life of me, I can not get this to work. I'm trying to pass the Marker Clusterers to my Google Map - but it's not working. I've got this map set up through Google Maps API and it's for a Wordpress website. The user can add locations using a Custom Post type. There are a lot of locations in close proximities, so I'm trying to use the MarkerCluster to lighten it up a bit. I've never used the MarkerCluster before, so it could be a small thing, too... not sure.
'var mc = new MarkerClusterer(map);' --This draws an error of: "Uncaught ReferenceError: MarkerClusterer is not defined"
Any insight? Any help is greatly appreciated!!
<?php // Index template
get_header(); ?>
<script src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script>
<div class="twelve column">
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>
<div class="intro">
<?php the_excerpt(); ?>
<hr>
</div>
<?php the_content(); ?>
<header class="clearfix"></header>
<div id="mapcanvas"></div>
<?php
// For creating multiple, customized loops.
// http://codex.wordpress.org/Class_Reference/WP_Query
$custom_query = new WP_Query('post_type=locations'); // exclude category 9
while($custom_query->have_posts()) : $custom_query->the_post(); ?>
<?php if(get_field('link')): ?>
<div>
<?php while(has_sub_field('link')): ?>
<div>
<p><?php the_sub_field('url'); ?></p>
</div>
<?php endwhile; ?>
</div>
<?php endif; ?>
<?php endwhile; ?>
<?php wp_reset_postdata(); // reset the query ?>
<?php
function get_single_term($post_id, $taxonomy)
{
$terms = wp_get_object_terms($post_id, $taxonomy);
if(!is_wp_error($terms)) {
return ''.$terms[0]->name.'';
}
}
$i = 0;
// For creating multiple, customized loops.
// http://codex.wordpress.org/Class_Reference/WP_Query
$custom_query = new WP_Query('post_type=location&posts_per_page=-1');
while($custom_query->have_posts()) : $custom_query->the_post();
$title = get_the_title(); // Location title
$map = get_field('location'); // ACF location contains address and coordinates
$terms = strip_tags( get_the_term_list( $post->ID, 'distributors', '', ' & ' )); // Get distributor terms and rm links
$info = '<strong>' . $title . '</strong><br>' . $map['address']; // Info window content
$link = get_field('link');
if($link){
$info .= '<br>'. $link .'';
}
$location[$i][0] = $title; // Store the post title
$location[$i][1] = $map['coordinates']; // Store the ACF coordinates
$location[$i][2] = json_encode($info); // Store info window content
$location[$i][3] = strip_tags( get_single_term( $post->ID, 'distributors' )); // Get first term for marker icon
$i ++;
endwhile; ?>
<?php wp_reset_postdata(); // reset the query ?>
<script>
$(function initialize() {
geocoder = new google.maps.Geocoder();
// Center map on our main location
var myLatLng = new google.maps.LatLng(41.583013,-93.63701500000002);
var bounds = new google.maps.LatLngBounds();
// https://developers.google.com/maps/documentation/javascript/styling
// Create an array of styles.
var styles = [
{
stylers: [
{ saturation: -99.9 }
]
}
];
// Create a new StyledMapType object, passing it the array of styles,
// as well as the name to be displayed on the map type control.
var styledMap = new google.maps.StyledMapType(styles, {name: 'exile'});
// Create a map object, and include the MapTypeId to add
// to the map type control.
var mapOptions = {
mapTypeId: 'roadmap',
center: myLatLng,
zoom: 14,
disableDefaultUI: false,
scrollwheel: true,
draggable: true
};
// Display a map on the page
var map = new google.maps.Map(document.getElementById("mapcanvas"), mapOptions);
var mc = new MarkerClusterer(map);
map.setTilt(45);
//Associate the styled map with the MapTypeId and set it to display.
map.mapTypes.set('exile', styledMap);
map.setMapTypeId('exile');
// Marker icons
typeObject = {
"Others" : {
"icon" : new google.maps.MarkerImage('http://exilebrewing.com/site/img/beer-mug.png', new google.maps.Size(18,26), new google.maps.Point(0,0), new google.maps.Point(9,26)),
"shadow" : new google.maps.MarkerImage('http://maps.google.com/mapfiles/shadow50.png', new google.maps.Size(40,34))
}
}
// http://wrightshq.com/playground/placing-multiple-markers-on-a-google-map-using-api-3/
// Multiple Markers
var markers = [
["Exile Brewing Co", 41.583013,-93.63701500000002,"Others"],
<?php
if (count($location)>0) {
foreach ($location as $key => $value){
if ($key < (count($location)-1)){
echo '["' . $location[$key][0] . '",' . $location[$key][1] . ',"' . $location[$key][3] . '"], ' . "\n";
} else {
echo '["' . $location[$key][0] . '",' . $location[$key][1] . ',"' . $location[$key][3] . '"]';
}
}
}
?>
];
var markers = [];
for (var i = 0; i < 100; i++) {
var latLng = new google.maps.LatLng(data.photos[i].latitude,
data.photos[i].longitude);
var marker = new google.maps.Marker({'position': latLng});
markers.push(marker);
}
var markerCluster = new MarkerClusterer(map, markers);
// Info Window Content
var infoWindowContent = [
["<strong>Exile Brewing Co.</strong><br>1514 Walnut Street, Des Moines"],
<?php
if (count($location)>0) {
foreach ($location as $key => $value){
if ($key < (count($location)-1)) {
echo '[' . $location[$key][2] . '], ' . "\n";
} else {
echo '[' . $location[$key][2] . ']';
}
}
}
?>
];
// Display multiple markers on a map
var infoWindow = new google.maps.InfoWindow(), marker, i;
// Loop through our array of markers & place each one on the map
for( i = 0; i < markers.length; i++ ) {
var position = new google.maps.LatLng(markers[i][1], markers[i][2]); // ACF coordinates
var icon = typeObject[markers[i][3]]['icon'];
var shadow = typeObject[markers[i][3]]['shadow'];
bounds.extend(position);
marker = new google.maps.Marker({
position: position,
map: map,
title: markers[i][0],
icon: icon,
shadow: shadow
});
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infoWindow.setContent(infoWindowContent[i][0]);
infoWindow.open(map, marker);
}
})(marker, i));
// Automatically center the map fitting all markers on the screen
//map.fitBounds(bounds);
}
// Override our map zoom level once our fitBounds function runs (Make sure it only runs once)
var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function(event) {
this.setZoom(15);
google.maps.event.removeListener(boundsListener);
});
});
</script>
<div id="map-canvas"></div>
<footer class="clearfix"></footer>
<?php endwhile;?>
<?php endif; ?>
</div>
</div>
<?php get_footer(); ?>
As per my comments :
You need to download the script ( here ) and then Include it in your page.
Marker clusterer is not a built-in feature of google maps , but an addon script ..
<script src="markerclusterer.js" type="text/javascript"></script>
or in the "correct" wordpress way :
wp_register_script( 'js_marker_clusterer', plugins_url( '/scripts/MarkerClusterer.js', __FILE__ ),'jquery' ); // or other dependencies descendents - preferably map JS or your custom.
wp_enqueue_script('js_marker_clusterer');
( change to your paths )
Also, look at the examples ( HERE ) and check their code ( and includes )
You need to include the third party marker clusterer script if you want to use it.
As specified in the documentation:
Note: Be sure to include markerclusterer.js or markerclusterer_packed.js in your HTML document.
<script src="/path/to/markerclusterer.js" type="text/javascript"></script>
I've created an array from three variables I get through a foreach loop.
//loop through each post
foreach($loop as $p){
//get the meta and taxonomy data
$term_list = get_the_term_list($p, "mountains",true);
$name = trim($term_list, "1");
$wtr_long = get_post_meta($p,"wtr_longitude",true);
$wtr_lat = get_post_meta($p,"wtr_latitude",true);
//Add to Array
$map_array[] = array ($name => $wtr_lat . "|" . $wtr_long);
}
Now this array should then deliver the data that will populate my Google Map, for that I'm using below code.
foreach( $map_array as $a){
foreach ($a as $key => $value) {
$pieces = explode("|", $value);
$trimmed_key = trim($key, "1");
$name = trim($trimmed_key);
?>
{latitude: <?php echo $pieces[0]; ?>,
longitude: <?php echo $pieces[1]; ?>,
html: <?php echo $name; ?>},
<?php }} ?>
This works almost fine (although it's probably not the cleanest code, tips on this would be appreciated too). The issue I'm having is that in the last iteration of the foreach inside the other foreach, I need to add a ], resulting in:
html: <?php echo $name; ?>}],
I can escape a single foreach, but doing it on a foreach inside a foreach is driving me insane. Any help would be greatly appreciated.
I'm not a php develeopor but you may want to build the collection of strings you want to echo first. After the collection is complete you can add the ']' the the last element. Then echo each element in your collection of strings.
atbyrd, your approach gave me a couple new issues, but did in the end lead to a working solution. Thank you for that.
Below the code that fixed the issue, hope it'll be helpful to someone else in the future.
//Add to Array
$map_string .= '{latitude: "' . $wtr_lat . '", longitude: "' . $wtr_long . '", html: "' . $name .'"},~!~';
//$map_string .= '{latitude: "' . $wtr_lat . '", longitude: "' . $wtr_long . '", html: "name"},~!~';
}
//Remove last three "~!~" characters from the string not to have one too many arrays when exploding
$clean_map_string = substr($map_string, 0, -3);
//Now I can explore on ~!~ to get a new array with the correct strings
$map_array = explode('~!~', $clean_map_string);
$i = 0;
$length = count($map_array)-1;
//Inserts all the markers
foreach($map_array as $value){
if( $i != $length ){
echo $value;
}
else {
echo str_replace("},", "}],", $value);
}
$i++;