We all may know the following snippet that gets the first entry of the media field of a page to e.g. display a header image on a page.
10 = IMAGE
10.file {
import = uploads/media/
import.data = levelmedia: 0, slide
import.listNum = 0
}
I am creating an extension (plugin, no ItemuserFunc etc) which needs to work with this media. I don't want to process dozens of typoscript directives in php to create this images. How can I use the example above to process the media field through typoscript, using core functionality instead of reinventing the wheel?
So now I'm in my extension code, having an array of page records. How to get further? The code below doesn't provide the functionality I need because I am not working on the page level (like I would when using the TS from above in a TMENU).
$content .= $this->cObj->stdWrap($page['media'], $this->conf['media_stdWrap.']);
Having an array of page records ($pages) with the associative keys same as the field names in the database, mainly the media field, you would simply walk through the array and create the images using the Typoscript configuration.
Example 1 (a programmer sets the rendering)
foreach($pages as $value) {
$mediaField = t3lib_div::trimExplode(',', $value['media']);
if(!$mediaField[0]) continue;
$imageConf = array(
'file' => 'uploads/media/' . $mediaField[0],
);
$content .= $this->cObj->cObjGetSingle('IMAGE', $imageConf);
}
Example 2 (an editor sets the rendering)
foreach($pages as $value) {
$this->cObj->data = $value;
$content .= $this->cObj->stdWrap($value['media'], $this->conf['media_stdWrap.']);
}
It sets the page data so that they are available as field in Typoscript. The configuration would then look something like this:
{
media_stdWrap {
cObject = IMAGE
cObject {
file {
import = uploads/media/
import.field = media
import.listNum = 0
}
}
}
}
Example 3 (combination of the previous 2 examples)
foreach($pages as $value) {
$mediaField = t3lib_div::trimExplode(',', $value['media']);
$mediaOutput = '';
// Creating the output with a default rendering
if($mediaField[0]) {
$imageConf = array(
'file' => 'uploads/media/' . $mediaField[0],
);
$mediaOutput = $this->cObj->cObjGetSingle('IMAGE', $imageConf);
}
// Allowing custom Typoscript to completely modify the media part
if(array_key_exists('media_stdWrap.', $this->conf)) {
$this->cObj->data = $value;
$mediaOutput = $this->cObj->stdWrap($mediaOutput, $this->conf['media_stdWrap.']);
}
$content .= $mediaOutput;
}
NOTE: These examples are completely untested. I've came up with them out of my head.
Related
As mentioned in the title. I try to change the image source to a default image, if an image's expiration date is expired.
I used ACF and added a new date field to all media files.
I then created the following function:
function check_expiration_date($post) {
$url = get_the_post_thumbnail_url($post->ID);
$thumbnail_id = get_post_thumbnail_id( $post->ID );
$today = date('d/m/Y');
$expire = get_field('expiration_date', $thumbnail_id);
if( $expire < $today && $expire!="" )
{
$url = "default.jpg";
}
return $url;
}
Now this function works for images that I add sepcifically in template files
but this will not work for images that have been added via the editor on post pages.
I tried to to use various hooks to change the html markup first before attempting to get the meta information but none of those had any effect on the outcome. Here an example:
function change_image_markup($html, $id, $caption, $title, $align, $url) {
$html5 = "<section>";
$html5 .= "<figure id='post-$id media-$id' class='align-$align'>";
$html5 .= "<img src='$url' alt='$title' />";
if ($caption) {
$html5 .= "<figcaption>$caption</figcaption>";
}
$html5 .= "</figure>";
$html5 .= "<section>";
return $html5;
}
add_filter( 'image_send_to_editor', 'change_image_markup', 10, 9 );
Is there a specific hook that can alter the html markup of images?
I am using Wordpress 5.5.1
any hint or tip is appreciated.
As the question is a month old and I did not receive any answers, I figured I would answer my own question. There is a difference in the requirements though. Instead of changing the image to a default one, I removed the image completely. Both can be achieved though.
So there was no real hook that could me out, as those hooks only call the action when actually inserting the image.
In my case everytime the post is being loaded the images had to be checked if they are expired or not.
Instead of working with hooks I created my own function and call that function inside single.php
In the single.php usually there is something like echo post->post_content;
Instead I call my function and give the post content as a value.
add_post_based_on_expiration_date($post->post_content);
And my function looks something like this:
function add_post_based_on_expiration_date($post_content){
$search_pattern = '/<figure(.*)\/figure>/'; //<figure(.*)/figure> /wp-image-(\d+)/
preg_match_all( $search_pattern, $post_content, $embedded_images );
$embedded_images_count = count( $embedded_images[0] );
$new_content = $post_content;
if ( $embedded_images_count > 0 ) {
for ( $i=0; $i < $embedded_images_count ; $i++ ) {
$dom = new DOMDocument;
#$dom->loadHTML($embedded_images[0][$i]);
$image = $dom->getElementsByTagName('img');
$imageId = str_replace("wp-image-" , "" , $image[0]->getAttribute('class'));
if(check_expiration_date_get_by_id($imageId)){
$new_content = str_replace($embedded_images[0][$i],"",$new_content);
}
};
};
echo $new_content;
}
It looks a bit messy but it does it's job. What I do is using regex to look for the image mark up <figure..... and save it in an array. Afterwards by using the DOM class I get the class, which contains the media ID. Then I call my function which is an alteration of the one above in the question. The function just returns true or false depeding on the expiration date. If it is true I remove it from the content and at the end I return it.
Therefore if an image is expired the image markup gets completely removed.
The downside of this aside from the messy code is the processing time. Since it it always called when opening a post site.
I am new to scraping website and I was interested in getting the ticket prices from this website.
https://www.cheaptickets.com/events/tickets/firefly-music-festival-4-day-pass-2867495
I see the ticket prices in the p#price-selected-label.filters-selected-label tag, but I cant seem to access it. I tried a few things and looked at a few tutorials, but either I get a blank returned or some error. The code is based off http://blog.endpoint.com/2016/07/scrape-web-content-with-php-no-api-no.html
<?php
require('simple_html_dom.php');
// Create DOM from URL or file
$html = file_get_html('https://www.cheaptickets.com/events/tickets/firefly-music-festival-4-day-pass-2867495');
// creating an array of elements
$videos = [];
// Find top ten videos
$i = 1;
$videoDetails = $html->find('p#price-selected-label.filters-selected-label')-> innertext;
// $videoDetails = $html->find('p#price-selected-label.filters-selected-label',0);
echo $videoDetails;
/*
foreach ($html->find('li.expanded-shelf-content-item-wrapper') as $video) {
if ($i > 10) {
break;
}
// Find item link element
$videoDetails = $video->find('a.yt-uix-tile-link', 0);
// get title attribute
$videoTitle = $videoDetails->title;
// get href attribute
$videoUrl = 'https://youtube.com' . $videoDetails->href;
// push to a list of videos
$videos[] = [
'title' => $videoTitle,
'url' => $videoUrl
];
$i++;
}
var_dump($videos);
*/
You can't get it because javascript renders it, so it's not available in the original html that your library get.
Use phantomjs(will execute javascript);
Download phantomjs and place the executable in a path that your PHP binary can reach.
Place the following 2 files in the same directory:
get-website.php
<?php
$phantom_script= dirname(__FILE__). '/get-website.js';
$response = exec ('phantomjs ' . $phantom_script);
echo htmlspecialchars($response);
?>
get-website.js
var webPage = require('webpage');
var page = webPage.create();
page.open('https://www.cheaptickets.com/events/tickets/firefly-music-festival-4-day-pass-2867495', function(status) {
if (status === "success") {
page.includeJs('http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js', function() {
var myElem = $('p#price-selected-label.filters-selected-label');
console.log(myElem);
});
phantom.exit();
}
});
Browse to get-website.php and the target site, https://www.cheaptickets.com/events/tickets/firefly-music-festival-4-day-pass-2867495 contents will return after executing inline javascript. You can also call this from a command line using php /path/to/get-website.php.
I am creating wordpress theme option panel and want to use some icons. I have one directory dedicated for icon into my theme folder. What I want to do is if user add any new image into that folder it will automatic appear into dropdown selection list into theme option panel.
Is there any way to do this in PHP with Wordpress? I believe that is possible as I saw one theme has the same option but it was so complex so couldn't figured out that and don't remember theme name too now.
I have to use it with below type of code
$video_tax = array(-1 => 'Choose a category');
$video_terms = get_terms('video_category');
if ($video_terms) {
foreach ($video_terms as $video_term) {
$video_tax[$video_term->term_id] = $video_term->name;
}
}
You might want to start by having a look at scandir. This will list all the contents of a folder on your system. From there it would just be a matter of putting the correct path, url or whatever you want in the the value of your options.
EDIT: Here's some sample code from one of my plugins:
function icons_meta(){
global $post;
$custom = get_post_custom($post->ID);
$link = $custom["icon"][0];
$files = scandir(PATH."/icons");
$selected = '';
echo "<select name='icon'>";
foreach($files as $file){
if($file == $link){
$selected = 'selected="selected"';
} else {
$selected = '';
}
echo "<option value='$file' $selected>".$file."</option>";
}
echo "</select>";
}
Is there any way to keep my GET parameters when paginating.
My problem is that I have a few different urls i.e
questions.php?sort=votes&author_id=1&page=3
index.php?sort=answers&style=question&page=4
How in my pagination class am I supposed to create a link to the page with a different page number on it but yet still keep the other parts of the url?
If you wanted to write your own function that did something like http_build_query, or if you needed to customize it's operations for some reason or another:
<?php
function add_edit_gets($parameter, $value) {
$params = array();
$output = "?";
$firstRun = true;
foreach($_GET as $key=>$val) {
if($key != $parameter) {
if(!$firstRun) {
$output .= "&";
} else {
$firstRun = false;
}
$output .= $key."=".urlencode($val);
}
}
if(!$firstRun)
$output .= "&";
$output .= $parameter."=".urlencode($value);
return htmlentities($output);
}
?>
Then you could just write out your links like:
Click to go to page 2
You could use http_build_query() for this. It's much cleaner than deleting the old parameter by hand.
It should be possible to pass a merged array consisting of $_GET and your new values, and get a clean URL.
$new_data = array("currentpage" => "mypage.html");
$full_data = array_merge($_GET, $new_data); // New data will overwrite old entry
$url = http_build_query($full_data);
In short, you just parse the URL and then you add the parameter at the end or replace it if it already exists.
$parts = parse_url($url) + array('query' => array());
parse_str($parts['query'], $query);
$query['page'] = $page;
$parts['query'] = http_build_str($query);
$newUrl = http_build_url($parts);
This example code requires the PHP HTTP module for http_build_url and http_build_str. The later can be replaced with http_build_query and for the first one a PHP userspace implementation exists in case you don't have the module installed.
Another alternative is to use the Net_URL2 package which offers an interface to diverse URL operations:
$op = new Net_URL2($url);
$op->setQueryVariable('page', $page);
$newUrl = (string) $op;
It's more flexible and expressive.
How about storing your page parameter in a session, so you don't have to modify every single page url?
I have a page that displays XML info in a table. The XML files are server side and I'm using PHP to get the file names and data using a drop down box. JSON is used to put the names in the dropdown and DOM to send the XML across. That works fine in all browsers.
There is an issue with my adding entries feature. When I add an entry in Chrome or Firefox it shows up the next time that table is selected. It doesn't work in IE9 though. The entries are added to the xml file but to view these changes in IE I have to open a new tab. Simply refreshing doesn't work. To redirect in this script I use the header function:
header('Location: ./client2.html');
Is there something that needs to be added here for IE or is there an issue somewhere else. I've added the php that gets the data when the file is chosen.
ini_set('display_errors',1);
error_reporting(E_ALL);
/* gets the selected file to use to return data */
$xml_filename = './XML/'.$_REQUEST['file'];
$xml = simplexml_load_file($xml_filename);
/* gets the root of the selected file */
$rootname = $xml->getName();
/* gets the children in that root */
$children = $xml->children();
$firstchild = $children[0];
// gets the table headings
$data = '{"headings":[';
foreach ($firstchild as $elem)
{
$data = $data.'"'.$elem->getName().'",';
}
// removes trailing ','
$data = substr_replace($data,"",-1);
$data = $data.'],';
// gets the cell values
$data = $data. '"vals":[';
foreach ($children as $child)
{
$data = $data.'[';
foreach ($child as $elem => $vals)
{
$data = $data.'"'.$vals.'",';
}
$data = substr_replace($data,"",-1);
$data = $data.'],';
}
// removes trailing ','
$data = substr_replace($data,"",-1);
$data = $data.']}';
/* sends created JSON string back to client */
echo $data;
If it's a caching problem, you could try adding a random string in the header() call, like this:
$random_str = sha1(uniqid(mt_rand(), true));
header('Location: ./client2.html?' . $random_str);
exit();
Turns out it was a caching issue. I had to add this: $.ajaxSetup({cache:false}) to the document.ready() section of the JavaScript. Nothing else seemed to work