Exchange HTML in for AMP Pages - php

Is there a way to change HTML in AMP Pages? Example:
Make every <span class="example1">...</span> to ...
Or even better, change specific Shortcodes in Wordpress to ...?

I found a solution to switch shortcodes:
// AMP change thrive-shortcode to landingpage link
function add_shortcode_amp($content) {
if (function_exists( 'is_amp_endpoint' ) && is_amp_endpoint()) {
/// Define shortcode-name
$mb_shortc = 'thrive_2step';
/// Define Mappings (thrive_2step id => Target URL for links in AMP)
$ampMappings = array(
"17503" => 'https://www.test.de/schreibtisch-workout-2',
"17505" => 'https://www.test.de/merkmale-arbeitsplatz-kostenlos',
"17506" => 'https://www.test.de/hoehenverstellbarer-schreibtisch-rentenverischerung-antrag');
/// Init Regex arrays
$mb_rexp = array();
$subst = array();
foreach ($ampMappings as $key => $value) {
$mb_rexp[] = '/\[('.$mb_shortc.').*?.id=[\'"]'.$key.'[\'"].*?\](.*?)\[\/\1\]?/';
$subst[] = '${2}';
}
/// Process Content
return preg_replace($mb_rexp, $subst, $content);
}
return $content;
}
add_filter( 'the_content', 'add_shortcode_amp', 6);
function mbtest_hello_world() {
return '<a>Hello World</a>';
}
add_shortcode('AMPTEST', 'mbtest_hello_world');
function shortcode_switch4amp( $atts) {
extract( shortcode_atts( array(
'regular' => 'regular',
'amp' => 'amp'
), $atts ) );
if (function_exists( 'is_amp_endpoint' ) && is_amp_endpoint()) {
return do_shortcode(str_replace(array("{","}"), array("[","]"),$amp));
} else {
return do_shortcode(str_replace(array("{","}"), array("[","]"), $regular));
}
}
add_shortcode('switch4amp', 'shortcode_switch4amp');

Related

Function inside the same function PHP

I'm busy with cleaning a WordPress parse_blocks() array.
Array:
Parse blocks
blockName
attrs
innerBlocks (0)
InnerBlocks (0)
blockName
attrs
innerBlocks (1)
InnerBlocks (1)
blockName
attrs
innerBlocks (2)
What I want is making a function which repeats each innerblock.
As you see above the array Parse block has innerblocks and those can get also innerblocks (2 times).
I made a simple function cleanBlock($block)
function cleanBlock($block)
{
if (isset($block['blockName']) && $block['blockName'] != '') {
$splitType = explode('/', $block['blockName']);
$innerBlocks = $block['innerBlocks'];
$block = array(
'type' => $splitType[1],
'attrs' => '',
'innerblocks' => $innerBlocks,
);
return $block;
}
}
There you find "innerblock" my idea was to run the cleanBlock($innerBlocks) again, but if I do that it doesn't work because the $block is made before I can get the innerblock, it's hard to explain I hope you know what I mean.
This is what I want, but this code doesn't work at all:
function cleanBlock($block)
{
if (isset($block['blockName']) && $block['blockName'] != '') {
$splitType = explode('/', $block['blockName']);
$block = array(
'type' => $splitType[1],
'attrs' => '',
'innerblocks' => cleanBlock($block['innerBlocks']),
);
return $block;
}
}
After the function I make the final array:
$newPDFarray = [];
foreach ($parseBlocks as $key => $group) {
$block = cleanBlock($group);
$newPDFarray[] = $block;
}
Don't know if this is the right or short solution but for me it works:
function cleanBlock($block)
{
if (isset($block['blockName']) && $block['blockName'] != '') {
$splitType = explode('/', $block['blockName']);
$innerBlocks = [];
foreach ($block['innerBlocks'] as $block) {
$innerBlocks[] = cleanBlock($block);
}
$block = array(
'type' => $splitType[1],
'attrs' => $block['attrs'],
'innerBlocks' => $innerBlocks,
);
return $block;
}
}
$newPDFarray = [];
foreach ($parseBlocks as $key => $group) {
if ($group['blockName'] != '') {
$questionGroup = cleanBlock($group);
$newPDFarray[] = $questionGroup;
}
}

Optimize Php function that is too slow

i made this function to test if the content has 301 redirections..
Please can you help me opimize it better because it's too slow
function contains_http_301_link($content, $current_site){
$pattern = '~<a(.*?)href="([^"]+)"(.*?)>~';
$links = array();
// Check if there is a url in the content
if(preg_match_all($pattern, $content, $urls)) {
foreach($urls[0] as $url){
// get external links
if ( !strpos( $url, $current_site )) { // Is an external link
$vowels = array('"' ,"<a", " ", "href", "=", ">");
$links[] = str_replace($vowels, "", $url);
}
}
}
foreach ($links as $link) {
$_headers = #get_headers($link,1);
if($_headers && strpos( $_headers[0], '301')) {
return true;
}
}
return false;
}
I would change the last for-loop to:
<?php
stream_context_set_default(
array(
'http' => array(
'method' => 'HEAD'
)
))
);
foreach ($links as $link) {
$_headers = get_headers($link,1);
if($_headers && strpos( $_headers[0], '301')) {
return true;
}
}
?>
or as
$context = stream_context_create(array(
'http' => array(
'method' => 'HEAD'
)
);
foreach ($links as $link) {
$_headers = get_headers($link,1, $context);
if($_headers && strpos( $_headers[0], '301')) {
return true;
}
}
By the way: if the first of 10 links found will return 301, your function returns TRUE. The same if it is the last. So your function just checks if at least one has a redirect 301 (and not 302 or 303)

Autogenerate wordpress shortcodes using array?

I was create a shortcode which automatically generate shortcodes with given array key and value. Function names does not generate dynamically.
Note: Array KEY = ShortcodeName and Value = Wordpress Option field.
add_shortcode("auto_gen", "auto_gen");
function auto_gen() {
$a = array(
"get_address" => "mg_admin_address",
"get_phone" => "mg_admin_phone",
"get_fax" => "mg_admin_fax",
"get_email" => "mg_admin_email",
"get_hrs_mon" => "mg_work_hrs_mon_frd",
"get_hrs_sat" => "mg_work_hrs_sat"
);
foreach ($a as $k => $v) {
if(has_shortcode($k)) {
echo "<br>Found: ". $k;
} else {
add_shortcode($k, $k. "_init");
function $k. "_init"() {
return get_option[$v, ''];
}
}
add_shortcode();
echo $k ." -> ". $v. "<br />";
}
}
There is any possible way to do this.
NOTE:
Here, get_address array key is a shortcode. And it is dynamically generate when It pass though loop. get_address is changable. If I change get_address with get_user_address then get_user_address generate generated. "get_address", "get_phone" are CHANGABLE at END LEVEL.
Developer also generate shortcodes to access created wp_options useing get_options, simply pushing elements in array. e.g. "shortcode_name" => "option_name"
The function add_shortcode has a third parameter that contains the current shortcode, so the same callback can be used multiple times:
$all = array( 'address', 'phone', 'fax', 'email', 'hrs_mon', 'hrs_sat' );
foreach ( $all as $s )
add_shortcode( "get_$s", 'general_shortcode' );
function general_shortcode( $atts, $content = '', $shortcode = '' )
{
switch( $shortcode )
{
case 'get_address':
$return = 'ADDRESS';
break;
case 'get_phone':
$return = 'PHONE';
break;
default:
$return = 'OTHER SHORTCODES';
break;
}
return $return;
}
Another possibility:
Class AllShortcodes{
private $all = array(
"get_address" => "mg_admin_address",
"get_phone" => "mg_admin_phone",
"get_fax" => "mg_admin_fax",
"get_email" => "mg_admin_email",
"get_hrs_mon" => "mg_work_hrs_mon_frd",
"get_hrs_sat" => "mg_work_hrs_sat"
);
public function __construct() {
foreach ( $this->all as $key => $value )
add_shortcode( $key, array( $this, 'general_shortcode' ) );
}
public function general_shortcode( $atts, $content = '', $shortcode = '' )
{
return $this->all[$shortcode];
}
}
$myShortcodes = new AllShortcodes;
Try following code:
add_shortcode("auto_gen", "auto_gen");
function auto_gen() {
$a = array(
"get_address" => "mg_admin_address",
"get_phone" => "mg_admin_phone",
"get_fax" => "mg_admin_fax",
"get_email" => "mg_admin_email",
"get_hrs_mon" => "mg_work_hrs_mon_frd",
"get_hrs_sat" => "mg_work_hrs_sat"
);
foreach ($a as $k => $v) {
if(has_shortcode($v,$k)) {
echo "<br>Found: ". $k;
} else {
add_shortcode($k, $k."_init");
$func =$k."_init";
$func($v);
}
echo $k ." -> ". $v. "<br />";
}
}
function get_address_init ($v) {
return get_option($v, '');
}
function get_phone_init ($v) {
return get_option($v, '');
}
function get_fax_init ($v) {
return get_option($v, '');
}
function get_email_init ($v) {
return get_option($v, '');
}
function get_hrs_mon_init ($v) {
return get_option($v, '');
}
function get_hrs_sat_init ($v) {
return get_option($v, '');
}

CakePHP Tags Model

I have a simple app that has Posts and Tags.
A post can have multiple tags and tags can belong to multiple posts. The basic DB schema is like this:
post table:
id
title
slug
content
tag table:
id
title
slug
tag_posts table:
id
tag_id
post_id
So when a user saves a post it will take a list of tags in a field and then first check if the tags exist. If the tag doesn't exist, then create them, or if not get there existing ids. (all tags are lower-cased so you can't have Tag and tag). The tags are then linked to the post by adding the ids into the tag_posts table.
This works so far, but the code to do it is really horrible. I have the following method in the Tag model which takes the list of tags and does the above:
public function savePostTags($postId, $tags)
{
// Explode the topics by comma, so we have an array to run through
$tags = explode(',', $tags);
// Array for collecting all the data
$collection = array();
//debug($tags);
function is_array_empty( $mixed ) {
if ( is_array($mixed) ) {
foreach ($mixed as $value) {
if ( ! is_array_empty($value) ) {
return false;
}
}
} elseif ( ! empty($mixed) ) {
return false;
}
return true;
}
if(is_array_empty($tags) ) {
return false;
}
// First of all we bin off existing associations to make sure we don't duplicate
// NOTE: The false means don't delete the topics or posts related!!! VERY IMPORTANT!
$this->TagPost->deleteAll(array('TagPost.post_id' => $postId), false);
$tags = array_unique($tags);
// Make sure all tags are unique
foreach($tags as $tag)
{
// Trim it so remove unwanted white spaces in the beginning and the end.
$tag = trim($tag);
// If tag is empty exit here
if(empty($tag) ) {
return false;
}
// Make it all lowercase for consistency of tag names
$tag = strtolower($tag);
// Check if we already have a topic like this
$controlFind = $this->find(
'first',
array(
'conditions' => array(
'title' => $tag
)
)
);
//debug($controlFind);
// No record found (create new tag and link it up)
if(!$controlFind)
{
$this->create();
if(
!$this->save(
array(
'title' => $tag,
'slug' => Inflector::slug($tag)
)
)
)
{
// If only one saving fails we stop the whole loop and method.
return false;
}
else
{
$temp = array(
'TagPost' => array(
'tag_id' => $this->id,
'post_id' => $postId
)
);
}
}
else // Or if found link it with the post
{
$temp = array(
'TagPost' => array(
'tag_id' => $controlFind['Tag']['id'],
'post_id' => $postId
)
);
}
$collection[] = $temp;
}
return $this->TagPost->saveAll($collection, array('validate' => false));
}
Any ideas on how to refactor this?
As it feels really long-winded and seems to break the conventions of CakePHP.
Try this
public function savePostTags($postId, $tags)
{
$tags = explode(',', $tags);
foreach($tags as $key=>$value){
$listTags[$key] = trim(strtolower($value));
}
# find the list of existing tags
$listOfExistingTags = $this->find('list',
array('conditions' => array('title' => $tags),
'recursive' => -1));
$newTags = array_diff($tags, $listOfExistingTags);
#save new tags
foreach($newTags as $key=>$value){
$saveData[$key]['Tag']['title'] = $value;
$saveData[$key]['Tag']['slug'] = Inflector::slug($value);
}
if(!empty($saveData))$this->saveAll($saveData);
# this save all the tags
# now save data in tag_posts
$listOfExistingTags = $this->find('list',
array('conditions' =>array('title' => $tags),
'fields'=>array('id','title'),
'recursive' => -1));
$i = 0;
foreach($listOfExistingTags as $key=>$value){
$tagPostData[$i]['TagPost']['tag_id'] = $key;
$tagPostData[$i]['TagPost']['post_id'] = $postId; $i++;
}
if(!empty($tagPostData)){
App::import('model','TagPost');
$TagPost = new TagPost();
$TagPost->saveAll($tagPostData);
}
}
Any ideas on how to refactor this?
Use the CakeDC Tags plugin. It is unit tested and easy to throw in, takes ~15mins. See it's readme.md. Its basically just adding the behavior and adding a field "tags" to your form.

Generate navigation from a multi-dimensional array

The question: How do I generate navigation, allowing for applying different classes to different sub-items, from a multi-dimensional array?
Here is how I was doing it before I had any need for multi-level navigation:
Home
Pics
About
and was generated by calling nav():
function nav(){
$links = array(
"Home" => "home.php",
"Pics" => "pics.php",
"About" => "about.php"
);
$base = basename($_SERVER['PHP_SELF']);
foreach($nav as $k => $v){
echo buildLinks($k, $v, $base);
}
}
Here is buildLinks():
function buildLinks($name, $page, $selected){
if($selected == $page){
$theLink = "<li class=\"selected\">$name</li>\n";
} else {
$thelink = "<li>$name</li>\n";
}
return $thelink;
}
My question, again:
how would I achieve the following nav (and notice that the visible sub navigation elements are only present when on that specific page):
Home
something1
something2
Pics
About
and...
Home
Pics
people
places
About
What I've tried
From looking at it it would seem that some iterator in the SPL would be a good fit for this but I'm not sure how to approach this. I have played around with RecursiveIteratorIterator but I'm not sure how to apply a different style to only the sub menu items and also how to only show these items if you are on the correct page.
I built this array to test with but don't know how to work with the submenu1 items individually:
$nav = array(
array(
"Home" => "home.php",
"submenu1" => array(
"something1"=>"something1.php",
"something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php")
);
The following will print out the lot in order but how do I apply, say a class name to the submenu1 items or only show them when the person is on, say, the "Home" page?
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($nav));
foreach($iterator as $key=>$value) {
echo $key.' -- '.$value.'<br />';
}
And this gets me:
Home
something1
something2
Pics
About
But I have no way to apply classes to those sub items and no way to only display them conditionally because I don't see how to target just these elements.
Don't reinvent the wheel, use Zend_Navigation and you will be happy.
You were on the right track with RecursiveIteratorIterator. It essentially flattens a recursive iterator. Here is the correct way:
$nav = array(
array(
"Home" => "home.php",
"submenu1" => array(
"something1"=>"something1.php",
"something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php"),
);
$it = new RecursiveIteratorIterator(
new RecursiveArrayIterator($nav),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($it as $k => $v) {
if ($it->getDepth() == 0)
continue;
echo str_repeat(" ", $it->getDepth() - 1) .
"$k => $v\n";
}
gives
Home => home.php
submenu1 => Array
something1 => something1.php
something2 => something2.php
Pics => pics.php
About => about.php
It seems like you might want to do this in a more object oriented way.
If not, it seems like you should at least define an algorithm that makes sense, right now you are just blindly guessing. Instead, DEFINE.
For example:
I am defining my navigation to be a php hash based tree. A navigation item will have the following:
A) if there is a top level link, the array hash will contain an item(sub array) labeled "navigation leaf"
b) A navigation Leaf will contain elements labeled "Display value", "link value", and "alt value". These items will be used to generate an anchor tag.
c) if an element has a submenu, in addition to containing a "Navigation Leaf", a "subnavigation" element will be present. A subnavigation element will have a "Navigation Leaf" if it has a displayable navigation item.
You can then write functions/methods that will display your navigation based on the definition you choose.
What I would do, is something along these lines:
class MenuItem {
protected $active = false;
protected $children = array();
protected $name = '';
protected $link = '';
public function __construct($name, $link, $active) {}
public function __toString() {
//render this item
$out = ''; #render here
if (!$this->isActive()) {
return $out;
}
$out .= '<ul>';
foreach ($this->children as $child) {
$out .= (string) $child;
}
$out .= '</ul>';
return $out;
}
public function isActive() {
if ($this->active) {
return true;
}
foreach ($this->children as $child) {
if ($child->isActive()) {
return true;
}
}
return false;
}
}
Then, all you have is a collection of root menu items in an array... To build your menu, you just do:
$rootItems = array($item1, $item2);
$out = '<ul>';
foreach ($rootItems as $item) {
$out .= (string) $item;
}
$out .= '</ul>';
I'll leave the semantics of constructing the object, adding children, etc to the user...
What about rewrite nav function in the next way:
function nav($links, $level){
foreach($links as $k => $v) {
if (is_array($v)) {
nav($v, $level + 1)
} else {
echo buildLinks($k, $v, $base);
}
}
}
And than call it:
$links = array(
array(
"Home" => "home.php",
"submenu1" => array(
"something1"=>"something1.php",
"something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php")
);
nav($links, 0);
Simplest way, IMHO, is to just make a recursive call, and use a tree structured description of your navigation (that is, nested arrays). Untested example code:
<?php
$links = array(
"Home" => array("home.php", array(
"something1"=> array("something1.php", array()),
"hello"=> array("hello.php", array(
"world" => array("world.php", array()),
"bar" => array("bar.php", array()),
)),
)),
"Pics" => array("pics.php", array(
"people"=>"people.php",
"places" => "places.php",
)),
"About" => array("about.php", array()), // example no subitems
);
// use the following $path variable to indicate the current navigational position
$path = array(); // expand nothing
$path = array('Home'); // expand Home
$path = array('Home', 'hello'); // also expand hello in Home
// map indent levels to classes
$classes = array(
'item',
'subitem',
'subsubitem',
);
// recursive function to build navigation list
function buildNav($links, $path, $classes)
{
// selected page at current level
// NOTE: array_shift returns NULL if $path is empty.
// it also alters the array itself
$selected = array_shift($path);
$class = array_shift($classes);
echo "<ul>\n";
foreach($links as $name => $link)
{
list($href, $sublinks) = $link;
if ($name == $selected)
{
echo "<li class=\"selected $class\">$name\n";
// recursively show subitems
// NOTE: path starts now with the selected subitem
buildNav($sublinks, $path, $classes);
echo "</li>\n";
}
else
{
echo "<li>$name</li>\n";
}
}
echo "<ul>\n";
}
// actually build the navigation
buildNav($links, $path, $classes);
?>
#catchmeifyoutry
Thank you, you saved my life LoL.
I changed your function a little to adapt it to my use and this came out:
$html['navi'] = array(
"Home" => "/home/",
"DJs & Shows" => "/djs-shows/",
"Playlists" => "/playlists/",
"Newsbeat" => "/newsbeat/",
"Reviews" => "/reviews/",
"TV" => "/tv/",
"Contact" => "/contact/",
"Test" => array("/test/",
array("Submenu 1" => "/test/link1",
"Submenu 2" => "/test/link2",
"Submenu 3" => "/test/link3",
"Submenu 4" => "/test/link4",
"Submenu 5" => "/test/link5",
"Submenu 6" => "/test/link6"
)
)
);
$classes = array(
'first-level',
'second-level',
'third-level',
);
function siteNavi($links, $classes) {
// The best way for MultiArray navigation (LOVE IT!)
// Array Shift selects first element and removes it from array
$class = array_shift($classes);
echo "<ul class=\"$class\">\n";
foreach($links as $name => $link) {
if (is_array($link) AND $class != "") {
list($link, $sublinks) = $link;
if ($_GET['site'] == basename($link)) { $selected = ' class="current"'; } else { $selected = ""; }
echo "<li{$selected}>{$name}\n";
// recursively show subitems
// NOTE: path starts now with the selected subitem
siteNavi($sublinks, $classes);
echo "</li>\n";
} else {
if ($_GET['site'] == basename($link)) { $selected = ' class="current"'; } else { $selected = ""; }
echo "<li{$selected}><a href=\"{$link}\" >{$name}</a></li>\n";
}
}
echo "</ul>\n";
}
Thank you very much !
I wonder how much impact does have this kind of code on the page speed tho. Few microseconds of milliseconds :D

Categories