<?php
/* wppa-filter.php
* Package: wp-photo-album-plus
*
* get the albums via shortcode handler
* Version: 9.2.02.004
*
*/

if ( ! defined( 'ABSPATH' ) ) exit();

// Declare action hook actions
add_action('init', 'wppa_do_filter');

function wppa_do_filter() {

	add_filter( 'the_content', 'wppa_add_shortcode_to_post' );
}

// Add a specific shortcode at the end of a post in runtime
// The content filter must be executed ( normal priority 10 )
// before shortcode processing ( normal at priority 11 )
// for this to work
function wppa_add_shortcode_to_post( $post ) {

	$new_post = $post;
	if ( ! wppa( 'ajax' ) && wppa_switch( 'add_shortcode_to_post' ) ) {
		$id = wppa_get_the_ID();
		$p = get_post( $id );
		if ( $p['post_type'] == 'post' ) $new_post .= wppa_opt( 'shortcode_to_add' );
	}
	return $new_post;
}

// Shortcode [wppa_div style="{style specs}"][/wppa_div]
function wppa_shortcode_div( $xatts, $content = '' ) {
static $seqno;
global $wppa_current_shortcode;
global $wppa_current_shortcode_atts;

	// Init
	$wppa_current_shortcode_atts = $xatts;
	$wppa_current_shortcode = sanitize_text_field( stripslashes( wppa_get_shortcode( 'wppa_div', $xatts ) ) );

	if ( ! $seqno ) $seqno = 0;
	$seqno++;

	$atts = shortcode_atts( array(
		'class' 		=> '',
//		'nicescroll' 	=> '',
		'height' 		=> '',
		'max-height' 	=> '',
//		'overflow' 		=> '',
		), $xatts );

	// Use nicescroller?
	$nice = wppa_is_nice();
	if ( $nice ) {
		$style = 'clear:both;position:relative;overflow:hidden;';
	}
	else {
		$style = 'clear:both;position:relative;overflow:auto;';
	}

	// Class
	$class = trim( $atts['class'] . ' wppa-div' );

	// Height
	$height = $atts['height'];
	if ( wppa_is_int( $height ) ) {
		$style .= 'height:' . $height . 'px;';
	}
	else {
		$style .= 'height:' . $height . ';';
	}

	// Max-height
	$data_maxheight = '';
	$max_height = $atts['max-height'];
	if ( $max_height ) {
		if ( $max_height > 1 ) {
			$style .= 'max-height:' . strval( intval( $max_height ) ) . 'px;';
		}
		else {
			$class .= ' wppa-autodiv';
			$data_maxheight = ' data-max-height="' . esc_attr( $max_height ) . '"';
		}
	}

	// Open the div
	$result = '
	<div
		id="wppa-div-' . $seqno . '"
		style="' . esc_attr( $style ) . '"
		class="' . esc_attr( $class ) . '" ' .
		$data_maxheight . '
		>' .

		// Open nice wrapper
		( $nice ? '<div class="wppa-divnicewrap" >' : '' ) .

			// Content
			do_shortcode( $content ) .

		// Close nice wrapper
		( $nice ? '</div>': '' ) .

	// Close the div
	'</div>';

	// The nivescroller js
	if ( $nice  ) {
		$the_js = 'jQuery(document).ready(function(){
			if ( jQuery().niceScroll )
			jQuery("#wppa-div-' . $seqno . '").niceScroll(".wppa-divnicewrap",{' . wppa_opt( 'nicescroll_opts' ) . '});});';
		wppa_add_inline_script( 'wppa', $the_js, true );
	}

	return $result;
}

add_shortcode( 'wppa_div', 'wppa_shortcode_div' );

// The shortcode handler
function wppa_shortcodes( $xatts ) {
global $wppa;
global $wppa_postid;
global $wppa_version;
global $wppa_revno;
global $wppa_no_timer;
global $wpdb;
global $wppa_current_shortcode;
global $wppa_current_shortcode_no_delay;
global $wppa_current_shortcode_atts;
global $albums_used;
global $photos_used;
global $other_deps;
global $wppa_runtime_settings;
global $wppa_after_smx;

	// Init
	wppa_reset_occurrance();
	$wppa_current_shortcode_atts 	= (array) $xatts;
	$wppa_no_timer 					= false;
	$is_calendar 					= false;

	// Save shortcode
	$wppa_current_shortcode 			= sanitize_text_field( stripslashes( wppa_get_shortcode( 'wppa', $xatts ) ) );
	$wppa_current_shortcode_no_delay 	= sanitize_text_field( stripslashes( wppa_get_shortcode( 'wppa', $xatts, true ) ) );

	// Check for #me while logged out
	if ( isset( $xatts['album'] ) && strpos( $xatts['album'], '#me' ) !== false && ! is_user_logged_in() ) {
		wppa_reset_occurrance();
		return;
	}

	// Preprocess and completize atts
	$atts = wppa_shortcode_atts( (array) $xatts );

	// If false returned, wo do not do anything (because of login required and not logged in etc). Housekeeping done
	if ( false === $atts ) {
		return '';
	}

	// Interprete $atts into $wppa
	$wppa['cache'] 		= $atts['cache'];
	$wppa['in_widget'] 	= $atts['widget'];
	$wppa['landscape'] 	= $atts['landscape'];
	$wppa['portrait'] 	= $atts['portrait'];
	$wppa['anon'] 		= $atts['anon'];
	$wppa['meonly'] 	= $atts['meonly'];
	$wppa['container-wrapper-class'] = $atts['class'];
	$wppa['targetmocc'] = $atts['targetmocc'];
	$wppa['is_random']  	= $atts['random'];
	$wppa['max'] 		= $atts['max'];
	$wppa['bpprofile'] 	= $atts['bpprofile'];

	// Interprete wppa_set settable runtime settings
	if ( is_array( $wppa_runtime_settings ) ) {
		$wppa = array_merge( $wppa, $wppa_runtime_settings );
	}

	// Assume all toplevel albums used when generic
	if ( $wppa['cache'] && $atts['type'] == 'generic' ) {
		$temp = $wpdb->get_col( "SELECT id FROM $wpdb->wppa_albums WHERE a_parent = 0 ORDER BY id" );
		$albums_used = implode( '.', $temp );
	}

	// Find occur
	if ( wppa_get_the_ID() != $wppa_postid && ! $wppa['in_widget'] ) {		// New post
		$wppa['mocc'] = 0;						// Init this occurance
		$wppa['fullsize'] = '';						// Reset at each post
		$wppa_postid = wppa_get_the_ID();			// Remember the post id
	}
	if ( $wppa['in_widget'] && $wppa['mocc'] < 200 ) {
		$wppa['mocc'] += 200;
	}
	if ( $wppa['in_widget'] ) {
		$wppa['mocc'] ++;
	}
	elseif ( $atts['mocc'] ) {
		$wppa['mocc'] = $atts['mocc'] - 1;
	}

	// Named album?
	if ( substr( $atts['album'], 0, 1 ) == '$' ) {
		$atts['album'] = wppa_album_name_to_number( $atts['album'] );
	}

	// If parent given, overwrite album by children
	if ( $atts['parent'] !== '' ) {

		$temp = explode( ',', $atts['parent'] );

		// Convert possible $names tpo numbers
		foreach( array_keys( $temp ) as $key ) {
			if ( substr( $temp[$key], 0, 1 ) == '$' ) {
				$temp[$key] = wppa_album_name_to_number( $temp[$key] );
			}
		}
		$atts['parent'] = implode( ',', $temp );

		// Test for virtual album
		if ( is_array( $temp ) && count( $temp ) > 1 && wppa_is_enum( $temp[1] ) ) {
			$temp[1] = wppa_alb_to_enum_children( $temp[1] );
			$atts['album'] = implode( ',', $temp );
		}
		elseif ( wppa_is_enum( $atts['parent'] ) ) {
			$atts['album'] = wppa_alb_to_enum_children( $atts['parent'] );
		}
		else {
			wppa_bump_mocc();
			$err = '<span style="color:red">[Error: Syntax error or unsupported parent specification: ' . $atts['parent'] . ']</span>';
			return $err;
		}
	}

	// Find type
	$type = $atts['type'];

	// Delay?
	$void_delay_types = array( 'upload',
							   'tagcloud',
							   'multitag',
							   'bestof',
							   'superview',
							   'search',
							   'supersearch',
							   'choice',
							   'stereo',
							   'grid',
							   'landing',
							   'calendar',
							   'notify',
							   'intro',
							   );
	$void_delay_albums = array( '#me',
								'#upldr',
								'#owner',
								'#potd',
								'#tags',
								);

	switch( wppa_opt( 'delay_overrule' ) ) {

		case 'always':
			$atts['delay'] = 'yes';
			if ( in_array( $type, $void_delay_types ) || in_array( $type, ['photo', 'mphoto', 'xphoto'] ) ) {
				$atts['delay'] = '';
			}

			foreach( $void_delay_albums as $va ) {
				if ( strpos( $atts['album'], $va ) !== false ) {
					$atts['delay'] = '';
				}
			}
			break;
		case 'never':
			$atts['delay'] = '';
			break;
		default:
			if ( $atts['delay'] ) {
				if ( in_array( $type, $void_delay_types ) ) {
					wppa_you_can_not( 'delay', $type );
					$atts['delay'] = false;
				}
				foreach( $void_delay_albums as $va ) {
					if ( strpos( $atts['album'], $va ) !== false ) {
						wppa_you_can_not( 'delay', $va );
						$atts['delay'] = false;
					}
				}
			}
			break;
	}

	// If querystring present, delay will cause looping
	if ( wppa_get( 'occur', 0 ) ) {
		$atts['delay'] = false;
	}

	// If mobile and ignore size align, ignore it
	if ( wppa_is_mobile() && wppa_switch( 'mobile_ignore_sa' ) ) {
		$atts['size'] = 'auto';
		$atts['align'] = '';
	}

	// If album="#tags,#me", translate #me to displayname
	if ( substr( $atts['album'], 0, 9 ) == '#tags,#me' ) {
		if ( is_user_logged_in() ) {
			$unam = wppa_get_user( 'display' );
		}
		else {
			$unam = '';
		}
		$atts['album'] = str_replace( '#me', $unam, $atts['album'] );
	}

	// If album="#posttitle", convert to id, if not found, create it
	if ( $atts['album'] == '#posttitle' ) {
		$post_id = get_the_ID();
		if ( $post_id ) {
			$the_post = get_post( $post_id );
			$the_name = $the_post->post_title;
			$owner_id = $the_post->post_author;
			$albs = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE name = %s", $the_name ) );
			if ( $albs ) {
				$atts['album'] = implode( '.', $albs );
			}
			else {
				switch( wppa_opt( 'posttitle_owner' ) ) {
					case '--- postauthor ---':
						$usr = get_user_by( 'ID', $owner_id );
						$owner = $usr->user_login;
						break;
					case '--- public ---':
						$owner = '--- public ---';
						break;
					default:
						// Should never get here
						wppa_log( 'err', 'Unimplemented #posttitle album owner: '.wppa_opt( 'posttitle_owner' ));
						return "Error. Unimplemented album owner indicator: ".wppa_opt( 'posttitle_owner' );
				}

				$alb = wppa_create_album_entry( ['name' 		=> $the_name,
												 'description' 	=> __( 'Automatically created for post', 'wp-photo-album-plus' ) . ' ' . $the_name,
												 'owner' 		=> $owner,
												 ] );
				if ( $alb ) {
					$atts['album'] = $alb;
				}
				else {
					wppa_log( 'err', 'Could not create album for post ' . $the_name );
					return "Error. Could not create album for this post";
				}
			}
		}
	}

	// Displatch on type
	switch ( $type ) {
		case 'version':
			return $wppa_version;
			break;
		case 'dbversion':
			return $wppa_revno;
			break;
		case 'landing':
			$wppa['is_landing'] = 1;
			break;
		case 'generic':
			break;
		case 'cover':
			$wppa['start_album'] = $atts['album'];
			$wppa['is_cover'] = 1;
			$wppa['albums_only'] = true;
			break;
		case 'album':
		case 'content':
			$wppa['start_album'] = $atts['album'];
			break;
		case 'thumbs':
			$wppa['start_album'] = $atts['album'];
			$wppa['photos_only'] = true;
			break;
		case 'covers':
			$wppa['start_album'] = $atts['album'];
			$wppa['albums_only'] = true;
			break;
		case 'slide':
			$wppa['start_album'] = $atts['album'];
			$wppa['is_slide'] = 1;
			$wppa['start_photo'] = $atts['photo'];
			if ( $atts['button'] ) {
				$wppa['is_button'] = esc_attr( wppa_translate( $atts['button'] ) );
			}
			if ( $atts['timeout'] ) {
				$wppa['timeout'] = strval( intval ( $atts['timeout'] ) );
			}
			break;
		case 'slideonly':
			$wppa['start_album'] = $atts['album'];
			$wppa['is_slideonly'] = 1;
			$wppa['start_photo'] = $atts['photo'];
			if ( $atts['timeout'] ) {
				$wppa['timeout'] = strval( intval ( $atts['timeout'] ) );
			}
			break;
		case 'slideonlyf':
			$wppa['start_album'] = $atts['album'];
			$wppa['is_slideonly'] = 1;
			$wppa['is_slideonlyf'] = 1;
			$wppa['film_on'] = 1;
			$wppa['start_photo'] = $atts['photo'];
			if ( $atts['timeout'] ) {
				$wppa['timeout'] = strval( intval ( $atts['timeout'] ) );
			}
			break;
		case 'slidef':
			$wppa['start_album'] = $atts['album'];
			$wppa['is_slide'] = 1;
			$wppa['film_on'] = 1;
			$wppa['is_slideonly'] = 1;
			$wppa['is_filmonly'] = 1;
			$wppa['start_photo'] = $atts['photo'];
			if ( $atts['timeout'] ) {
				$wppa['timeout'] = strval( intval ( $atts['timeout'] ) );
			}
			break;
		case 'filmonly':
			$wppa['start_album'] = $atts['album'];
			$wppa['is_slideonly'] = 1;
			$wppa['is_filmonly'] = 1;
			$wppa['film_on'] = 1;
			$wppa['start_photo'] = $atts['photo'];
			if ( $atts['timeout'] ) {
				$wppa['timeout'] = strval( intval ( $atts['timeout'] ) );
			}
			break;
		case 'photo':
		case 'sphoto':
			$wppa['single_photo'] = $atts['photo'];
			$wppa['start_photo'] = $atts['photo'];
			$wppa['start_album'] = $atts['album'];
			wppa_make_after_smx( $xatts, $atts['photo'] );
			break;
		case 'mphoto':
			$wppa['single_photo'] = $atts['photo'];
			$wppa['start_photo'] = $atts['photo'];
			$wppa['start_album'] = $atts['album'];
			$wppa['is_mphoto'] = 1;
			wppa_make_after_smx( $xatts, $atts['photo'] );
			break;
		case 'xphoto':
			$wppa['single_photo'] = $atts['photo'];
			$wppa['start_photo'] = $atts['photo'];
			$wppa['start_album'] = $atts['album'];
			$wppa['is_xphoto'] = 1;
			wppa_make_after_smx( $xatts, $atts['photo'] );
			break;
		case 'slphoto':
			$wppa['is_slide'] = 1;
			$wppa['single_photo'] = $atts['photo'];
			$wppa['start_photo'] = $atts['photo'];
			$wppa['start_album'] = $atts['album'];
			$wppa['is_single'] = 1;
			break;
		case 'audio':
			$wppa['is_audioonly'] = 1;
			$wppa['audio_item'] = $atts['audio'];
			$wppa['audio_album'] = $atts['album'];
			$wppa['audio_poster'] = $atts['poster'];
			break;
		case 'autopage':
			$wppa['is_autopage'] = 1;
			break;
		case 'upload':
			if ( $atts['parent'] ) {
				$wppa['start_album'] = wppa_alb_to_enum_children( $atts['parent'] );
			}
			else {
				$wppa['start_album'] = $atts['album'];
			}
			if ( ! $wppa['start_album'] ) {
				$wppa['start_album'] = 0;
			}
			$wppa['is_upload'] = true;
			break;
		case 'multitag':
			$wppa['taglist'] = wppa_sanitize_tags($atts['taglist']);
			$wppa['is_multitagbox'] = true;
			if ( $atts['cols'] ) {
				$cols = explode( ',', $atts['cols'] );
				$col = $cols[0];
				if ( isset( $cols[1] ) && wppa_is_mobile() ) {
					$col = $cols[1];
				}
				if ( ! wppa_is_int( $col ) || $col < 1 ) $col = '2'; // On error use default
				$wppa['tagcols'] = $col;
			}
			break;
		case 'tagcloud':
			$wppa['taglist'] = wppa_sanitize_tags($atts['taglist']);
			$wppa['is_tagcloudbox'] = true;
			break;
		case 'bestof':
			$wppa['bestof'] = true;
			$wppa['bestof_args'] = $atts;
			$photos_used = '*';
			$other_deps = 'R';
			break;
		case 'superview':
			$wppa['is_superviewbox'] = true;
			$wppa['start_album'] = $atts['album'];
			break;
		case 'search':
			$wppa['is_searchbox'] = true;
			$wppa['may_sub'] = $atts['sub'];
			if ( $atts['root'] ) {
				if ( substr( $atts['root'], 0, 1 ) == '#' ) {
					$wppa['forceroot'] = strval( intval( substr( $atts['root'], 1 ) ) );
				}
				else {
					$wppa['may_root'] = $atts['root'];
				}
				$wppa['start_album'] = wppa_alb_to_enum_children( $wppa['forceroot'] );
			}
			$wppa['landingpage'] = $atts['landing'];
			break;
		case 'supersearch':
			$wppa['is_supersearch'] = true;
			break;
		case 'calendar':
			$is_calendar = true;
			$wppa['is_calendar'] = true;
			$wppa['calendar'] = 'timestamp';
			if ( in_array( $atts['calendar'], array( 'exifdtm', 'timestamp', 'modified', 'realexifdtm', 'realtimestamp', 'realmodified' ) ) ) {
				$wppa['calendar'] = $atts['calendar'];
			}
			$wppa['reverse'] 		= $atts['reverse'];
			$wppa['start_album'] 	= $atts['album'];
			if ( $atts['parent'] ) {
				$wppa['start_album'] = wppa_alb_to_enum_children( $atts['parent'] );
			}
			$wppa['year'] = strval( intval( $atts['year'] ) );
			$wppa['month'] = strval( intval( $atts['month'] ) );
			break;
		case 'stereo':
			$wppa['is_stereobox'] = true;
			break;
		case 'url':
			$wppa['is_url'] = true;
			$wppa['single_photo'] = $atts['photo'];
			$wppa_no_timer = true;
			break;
		case 'choice':
			$wppa['is_admins_choice'] = true;
			$wppa['admins_choice_users'] = $atts['admin'];
			break;
		case 'acount':
		case 'pcount':
			$alb = $atts['album'];
			if ( ! $alb || $alb < 1 ) {
				$err = '
				<span style="color:red">
				Error in shortcode spec for type="' . $atts['type'] . '":
				either attribute album="" or parent="" should supply a positive integer or enumeration
				</span>';
				return $err;
			}

			$parent_given = $atts['parent'] != '';
			if ( $parent_given ) {
				$albs = explode( '.', wppa_expand_enum( $atts['parent'] ) );
			}
			else {
				$albs = explode( '.', wppa_expand_enum( $atts['album'] ) );
			}

			$total = 0;
			foreach( $albs as $alb ) {

				$counts = wppa_get_treecounts_a( $alb );

				if ( is_array( $counts ) ) {

					// Parent given
					if ( $parent_given ) {

						// Albums requested
						if ( $type == 'acount' ) {
							$total += $counts['treealbums'];
						}

						// Photos requested
						else {
							$total += $counts['treephotos'];
						}
					}

					// Album given
					else {

						// Albums requested
						if ( $type == 'acount' ) {
							$total += $counts['selfalbums'];
						}

						// Photos requested
						else {
							$total += $counts['selfphotos'];
						}
					}
				}
			}
			return $total;
			break;
		case 'share':
			$result = wppa_get_share_page_html();
			return $result;
			break;
		case 'lastupdate':
			$album = $atts['album'] ? $atts['album'] : 0;
			if ( $album ) {
				$timestamp = $wpdb->get_var( $wpdb->prepare( "SELECT timestamp FROM $wpdb->wppa_photos WHERE album = %d ORDER BY timestamp DESC LIMIT 1", $album ) );
			}
			else {
				$timestamp = $wpdb->get_var( "SELECT timestamp FROM $wpdb->wppa_photos ORDER BY timestamp DESC LIMIT 1" );
			}
			if ( $timestamp ) {
				$result = wppa_local_date( wppa_get_option( 'date_format' ), $timestamp );
				return $result;
			}
			else {
				return ( __( 'Unavailable', 'wp-photo-album-plus' ) );
			}
			break;
		case 'contest':
			$album = $atts['album'] ? $atts['album'] : 0;
			if ( strpos( $album, '..' ) !== false ) {
				$album = wppa_expand_enum( $album );
			}
			if ( ! $album ) {
				$err = '
				<span style="color:red">
				Error in shortcode spec for type="contest":
				Missing or invalid attribute album="<album id>"<br>
				album=' . $atts['album'] . ', parent=' . $atts['parent'] . '</span>';
				return $err;
			}
			$wppa['start_album'] = $atts['album'];
			$wppa['is_contest'] = true;
			break;
		case 'grid':
			$wppa['is_grid'] = true;
			$wppa['photos_only'] = true;
			if ( $atts['photos'] ) {
				$wppa['start_photos'] = $atts['photos'];
			}
			elseif ( $atts['album'] ) {
				$wppa['start_album'] = $atts['album'];
			}
			if ( isset( $atts['cols'] ) ) {
				$cols = explode( ',', $atts['cols'] );
				$col = $cols[0];
				if ( isset( $cols[1] ) && wppa_is_mobile() ) {
					$col = $cols[1];
				}
				if ( ! wppa_is_int( $col ) || $col < 1 ) $col = '2'; // On error use default
				$wppa['gridcols'] = $col;
			}
			break;
		case 'notify':
			$wppa['is_notify'] = true;
			break;
		case 'intro':
			$wppa['is_intro'] = $atts['id'];
			break;

		default:
			wppa_log( 'Err', 'Invalid type: ' . htmlentities( $atts['type'] ) . ' in wppa shortcode ' . $wppa_current_shortcode );
			return '';
	}

	// Count (internally to wppa_albums)

	// Find size. Assume default responsive
	if ( $atts['size'] == 'auto' ) {
		$wppa['auto_colwidth'] = true;
		$wppa['fullsize'] = '';
		$wppa['max_width'] = '';
	}
	elseif ( $atts['size'] && is_numeric( $atts['size'] ) && $atts['size'] < 1.0 ) {
		$wppa['auto_colwidth'] = true;
		$wppa['fullsize'] = $atts['size'];
	}
	elseif ( substr( $atts['size'], 0, 4 ) == 'auto' ) {
		$wppa['auto_colwidth'] = true;
		$wppa['fullsize'] = '';
		$wppa['max_width'] = substr( $atts['size'], 5 );
	}
	else {
		$wppa['auto_colwidth'] = false;
		$wppa['fullsize'] = $atts['size'];
	}

	// Find align
	$wppa['align'] = $atts['align'];

	// Delay
	if ( $atts['delay'] ) {
		if ( substr( $atts['delay'], 0, 3 ) == 'yes' || substr( $atts['delay'], 0, 4 ) == 'text' || substr( $atts['delay'], 0, 6 ) == 'button' ) {
			$wppa['delay'] = $atts['delay'];
		}
	}

	// Can not delay when in ajax
	if ( defined( 'DOING_AJAX' ) ) {
		$wppa['delay'] = '';
	}

	// Remember albums and photos used if caching.
	// This is used to know what caches must be cleared in cas a photo or album gets changed.
	if ( $wppa['cache'] ) {
		$albums_used = wppa_expand_enum( $wppa['start_album'] );
		$photos_used = $atts['photos'] ? wppa_expand_enum( $atts['photos'] ) : $atts['photo'];
	}
	else {
		$albums_used = '';
		$photos_used = '';
		$other_deps  = '';
	}

	// Lightbox timeout if not default
	if ( $atts['lbtimeout'] && wppa_is_posint( $atts['lbtimeout'] ) ) {
		$wppa['lbtimeout'] = $atts['lbtimeout'] * 1000;
	}

	// Lightbox start if not default
	if ( $atts['lbstart'] && ( $atts['lbstart'] == 'yes' || $atts['lbstart'] == 'no' ) ) {
		$wppa['lbstart'] = $atts['lbstart'];
	}

	// Ready to render
	$result =  wppa_albums();						// Get the HTML

	// Calendar needs an extra container
	if ( $is_calendar ) {
		wppa_reset_occurrance();
		wppa_bump_mocc(); //$wppa['mocc'] += 1;
		wppa_container( 'open' );
		wppa_container( 'close' );
		$result .= $wppa['out'];
	}

	// Relative urls?
	$result = wppa_make_relative( $result );

	// Compress
	$result = wppa_compress_html( $result );

	// Done
	return $result;
}

// Preprocess wppa shortcode atts
function wppa_shortcode_atts( $xatts ) {
global $wppa_set_used;
global $wppa_opt;
global $wppa_forced_mocc;
global $wppa_is_caching;
global $wpdb;

	$atts = [
		'type'  	=> 'generic',
		'album' 	=> '',
		'photo' 	=> '',
		'photos' 	=> '',
		'size'		=> 'auto',
		'align'		=> '',
		'taglist'	=> '',
		'cols'		=> '',
		'sub' 		=> '',
		'root' 		=> '',
		'calendar' 	=> '',
		'reverse' 	=> '',
		'landing' 	=> '',
		'admin' 	=> '',
		'parent' 	=> '',
		'timeout' 	=> '',
		'button' 	=> '',
		'delay' 	=> '',
		'year' 		=> '',
		'month' 	=> '',
		'cache' 	=> false,
		'login' 	=> '',
		'widget' 	=> '',
		'landscape' => false,
		'portrait' 	=> false,
		'audio' 	=> '',
		'poster' 	=> '',
		'lbtimeout' => '',
		'lbstart' 	=> '',
		'mocc' 		=> '',
		'set' 		=> '',
		'anon' 		=> false,
		'meonly' 	=> false,
		'class' 	=> '',
		'targetmocc'	=> '',
		'album_raw' 	=> '',
		'album_arr' 	=> [],
		'random' 		=> '',
		'id' 			=> '0',
		'max' 			=> '0',
		'bpprofile' 	=> '',
	];

	// Shortcode attributes that do not need a value. Convert them to 'attr => 1'
	// To workaround a php bug this is complexer that it should need to be
	$xatts_copy = $xatts;
	$singles = ['landscape', 'portrait', 'cache', 'anon', 'meonly', 'random', 'bpprofile'];
	$no_s = ['no', 'off'];
	foreach ( $singles as $at ) {
		$xatts_temp = $xatts_copy;
		if ( in_array( $at, $xatts_temp ) ) {
			if ( $at == 'random' ) {
				$xatts[$at] = wppa_get_randseed();
			}
			else {
				$xatts[$at] = '1';
			}
		}
		elseif ( isset( $xatts_temp[$at] ) && ! in_array( $xatts_temp[$at], $no_s ) ) {
			$xatts[$at] = false;
		}
	}

	// Login requested?
	if ( in_array( 'login', (array) $xatts ) ) {
		if ( ! is_user_logged_in() ) {
			wppa_bump_mocc();
			return false; // Signal give up
		}
	}
	if ( isset( $xatts['login'] ) ) {
		if ( $xatts['login'] == 'admin' && ! wppa_user_is_admin() ) {
			wppa_bump_mocc();
			return false;
		}
		if ( $xatts['login'] == 'yes' && ! is_user_logged_in() ) {
			wppa_bump_mocc();
			return false;
		}
	}

	// Sanitize input
	foreach ( array_keys( $xatts ) as $key ) {
		$xatts[$key] = wp_strip_all_tags( $xatts[$key] ); // NOT htmlspecialchars because of album="$cat,René" has allowed funny chars
		$xatts[$key] = str_replace( ['%23', 'QUOTE', 'APOS'], ['#', '', "'"], $xatts[$key] ); // Fix for Gutenberg previews
	}
	if ( isset( $xatts['size'] ) && $xatts['size'] == 1 ) {
		$xatts['size'] = 'auto';
	}
	if ( isset( $xatts['class'] ) && $xatts['class'] != '' ) {
		$xatts['class'] = wppa_sanitize_text( $xatts['class'] );
	}
	$voidcache = false;
	if ( isset( $xatts['album'] ) ) {

		// Fix confusion between single and multy tags and cats
		$xatts['album'] = str_replace( ['#cats,', '#tag,'], ['#cat,', '#tags,'], $xatts['album'] );

		// For backward compat change | into &
		$xatts['album'] = str_replace( '|', '&', $xatts['album'] );

		// If tags in album, replace yy and mm

		if ( strpos( $xatts['album'], '#tags,' ) !== false ) {
			$xatts['album'] = wppa_translate_virtual_tags( $xatts['album'] );
		}
	}
	foreach ( ['album', 'parent'] as $key ) {
		if ( isset( $xatts[$key] ) ) {
			$p = strpos($xatts[$key],'#me');
			if ( $p ) {
				$xatts[$key] = str_replace( '#me', wppa_get_user(), $xatts[$key] );
				$voidcache = true;
				$xatts['meonly'] = 1;
			}
		}
	}

	// Album multi virtual
	if ( isset( $xatts['album'] ) ) {
		$atts['album_raw'] = str_replace( '|', '&', $xatts['album'] );
		$atts['album_arr'] = explode( '&', $atts['album_raw'] );
	}

	// If album is encrypted, decrypt it ( happens in cover preview )
	if ( isset( $xatts['album'] ) ) {
		foreach( array_keys( $atts['album_arr'] ) as $key ) {
			$a = false;
			if ( strlen( $atts['album_arr'][$key] ) == 16 && substr( $atts['album_arr'][$key], 0, 1 ) != '#' ) {
				$a = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_albums WHERE crypt = %s", $atts['album_arr'][$key] ) );
				if ( $a ) $atts['album_arr'][$key] = $a;
			}
		}
		$xatts['album'] = implode( '&', $atts['album_arr'] );// ism
	}

	// Caching?
	switch( wppa_opt( 'cache_overrule' ) ) {
		case 'always':
			$xatts['cache'] = 1;
			break;
		case 'never':
			$xatts['cache'] = 0;
			break;
		default:
	}

	// Void caching types
	if ( isset( $xatts['type'] ) ) {
		$void_cache_types = array( 'landing',
								   'upload',
								   'search',
								   'calendar',
								   'tagcloud',
								   'multitag',
								   );
		if ( in_array( $xatts['type'], $void_cache_types ) ) {
			$xatts['cache'] = '';
		}
	}

	// Void caching virtual albums / photos
	if ( isset( $xatts['album'] ) ) {
		if ( strpos( $xatts['album'], '#me' ) !== false ) $xatts['cache'] = 0;
		if ( strpos( $xatts['album'], '#owner' ) !== false ) $xatts['cache'] = 0;
		if ( strpos( $xatts['album'], '#upldr' ) !== false ) $xatts['cache'] = 0;
	}
	if ( isset( $xatts['photo'] ) ) {
		if ( strpos( $xatts['photo'], '#potd' ) !== false ) $xatts['cache'] = 0;
	}

	// Void caching #me shortcodes
	if ( $voidcache ) {
		$xatts['cache'] = 0;
	}

	// Make globally known 'we are building a cache file'
	if ( strpos( wppa_request_uri(), 'wp-admin/widgets.php' ) !== false ) $xatts['cache'] = '';
	if ( strpos( wppa_request_uri(), 'wp-json/wp/v2/widget-types' ) !== false ) $xatts['cache'] = '';
	$wppa_is_caching = isset( $xatts['cache'] ) ? $xatts['cache'] : false;

	// Update usedby fields
	$page = get_the_ID();

	if ( isset( $xatts['photo'] ) ) {
		if ( wppa_is_enum( $xatts['photo']  ) ) {
			wppa_add_usedby( $xatts['photo'], $page, 'photo' );
		}
	}
	if ( isset( $xatts['album'] ) ) {
		foreach( $atts['album_arr'] as $a ) {
			if ( wppa_is_enum( $a ) ) {
				wppa_add_usedby( $a, $page, 'album' );
			}
		}
	}

	// Fix timeout
	if ( isset( $xatts['timeout'] ) ) {
		$xatts['timeout'] = strval( 1000 * intval( $xatts['timeout'] ) );
	}

	// Sanitize mocc, must be 100 <= mocc < 200 or ''
	if ( isset( $xatts['mocc'] ) ) {
		$m = $xatts['mocc'];
		if ( 100 <= $m && $m < 200 ) {
			$xatts['mocc'] = $m;
		}
		else $xatts['mocc'] = '';
		$wppa_forced_mocc = $xatts['mocc'];
	}
	else {
		$xatts['mocc'] = '';
		$wppa_forced_mocc = 0;
	}

	// Look for targetmocc
	if ( ! isset( $xatts['targetmocc'] ) || ! wppa_is_posint( $xatts['targetmocc'] ) ) {
		$xatts['targetmocc'] = false;
	}

	// Reset possible sets in previous sc
	if ( $wppa_set_used ) {
		wppa_initialize_runtime( true, false );
	}

	// Set used this time?
	if ( isset( $xatts['set'] ) ) {
		$wppa_set_used = true;
		$opts_arr = explode( ',', $xatts['set'] );
		foreach( $opts_arr as $opt ) {
			$t = explode( ':', $opt );
			if ( count( $t ) == 2 ) {
				$name = $t[0];
				$value = $t[1];
				wppa_proc_set( ['name' => $name, 'value' => $value] );
			}
		}
	}

	// max
	if ( isset( $xatts['max'] ) ) {
		if ( ! wppa_is_int( $xatts['max'] ) ) {
			$xatts['max'] = '0';
		}
	}

	// bpprofile?
	if ( isset( $xatts['type'] ) && $xatts['type'] == 'upload' && isset( $xatts['bpprofile'] ) ) {
		$xatts['bpprofile'] = '';
		if ( function_exists( 'bp_displayed_user_id' ) ) {
			$user_id = bp_displayed_user_id();
			if ( $user_id ) {
				$usr = get_user_by( 'ID', $user_id );
				if ( $usr ) {
					$xatts['bpprofile'] = $usr->user_login;
				}
			}
		}
	}

	$atts = wp_parse_args( $xatts, $atts );

	return $atts;
}

// Declare the shortcode handler
add_shortcode( 'wppa', 'wppa_shortcodes' );

// The runtime modifiable settings are processed by the wppa_set shortcode
function wppa_set_shortcodes( $xatts, $content = '' ) {
global $wppa;
global $wppa_opt;
global $wppa_runtime_settings;
global $wppa_url_set_extension;

	// Init
	// Runtime settings are applied after occurrance reset
	if ( ! $wppa_runtime_settings ) $wppa_runtime_settings = array();

	// All option settings are saved for the url
	if ( ! $wppa_url_set_extension ) $wppa_url_set_extension = '';

	$atts = shortcode_atts( array(
		'name' 		=> '',
		'value' 	=> ''
	), $xatts );

	// Reset after an empty [wppa_set] shortcode
	if ( ! $atts['name'] ) {
		$wppa_opt = false;
		wppa_initialize_runtime();

		// Make sure next occ after reset has no mods
		$wppa_runtime_settings = array();
		$wppa_url_set_extension = '';
		wppa_reset_occurrance();
	}

	// Process item $atts
	else {
		wppa_proc_set( $atts );
	}
}

// Enable wppa_set shortcode handler
add_shortcode( 'wppa_set', 'wppa_set_shortcodes' );

// Process [name => ..., value => ...] array for runtime setting change
function wppa_proc_set( $item ) {
global $wppa_opt;
global $wppa_runtime_settings;
global $wppa_url_set_extension;

	// Are we enabled?
	if ( ! wppa_switch( 'enable_shortcode_wppa_set' ) ) {
		wppa_log( 'war', 'Runtime modifyable settings not enabled (wppa_proc_set)' );
		return;
	}

	// Find out if it is an option or a runtime setting
	$is_opt = false;
	$name 	= $item['name'];
	$value 	= $item['value'];
	if ( isset( $wppa_opt[$name] ) ) {
		$is_opt = true;
	}
	elseif ( isset( $wppa_opt['wppa_' . $name] ) ) {
		$is_opt = true;
		$name = 'wppa_' . $name;
	}

	// Option?
	if ( $is_opt ) {
		$wppa_opt[$name] = $value;
	}

	// Runtime setting
	else {
		$wppa_runtime_settings[$name] = $value;
	}

	// Add it to the extension of the ajax url
	$wppa_url_set_extension .= "$name=$value&amp;"; // "&wppa-set[$name]=$value";

	// Save
	wppa_encrypt_set();

}

// Enable simple photo shortcode handler
add_shortcode( 'photo', 'wppa_photo_shortcodes' );

function wppa_photo_shortcodes( $xatts ) {
global $wppa;
global $wppa_postid;
global $wpdb;
static $seed;
global $wppa_current_shortcode;
global $wppa_current_shortcode_atts;
global $photos_used;
global $wppa_opt;
global $wppa_after_smx;

	if ( ! wppa_switch( 'photo_shortcode_enabled' ) ) {
		wppa_log( 'war', 'Photo shortcode must be enabled before you can use it' );
		return;
	}

	// Init
	wppa_reset_occurrance();
	$wppa_current_shortcode_atts = $xatts;
	$wppa_current_shortcode = sanitize_text_field( stripslashes( wppa_get_shortcode( 'photo', $xatts ) ) );

	// Get and validate photo id
	if ( isset( $xatts[0] ) ) {
		$photo = $xatts[0];
		if ( is_numeric( $photo ) && ! wppa_photo_exists( $photo ) ) {
			/* translators: integer id */
			return sprintf( __( 'Photo %d does not exist', 'wp-photo-album-plus' ), $photo );
		}
	}
	else {
		return __( 'Missing photo id', 'wp-photo-album-plus' );
	}

	// Are we in a widget?
	if ( isset( $xatts['widget'] ) ) {
		$wppa['in_widget'] = $xatts['widget'];
	}

	// Find occur
	if ( wppa_get_the_ID() != $wppa_postid && ! $wppa['in_widget'] ) {		// New post
		$wppa['mocc'] = 0;					// Init this occurance
		$wppa['fullsize'] = '';					// Reset at each post
		$wppa_postid = wppa_get_the_ID();			// Remember the post id
	}
	if ( $wppa['in_widget'] && $wppa['mocc'] < 100 ) {
		$wppa['mocc'] += 100;
	}
	if ( $wppa['in_widget'] ) {
		$wppa['mocc'] ++;
	}

	// Special cases
	if ( $photo == 'last' ) $photo = '#last';
	if ( $photo == 'random' ) $photo = '#random';

	// Random photo?
	if ( $wppa_postid && $photo == '#random' ) {

		if ( ! $seed ) {
			$seed = time();
		}
		$seed = floor( $seed * 0.9 );

		if ( wppa_opt( 'photo_shortcode_random_albums' ) != '-2' ) {
			$albs = explode( '.', wppa_expand_enum( wppa_opt( 'photo_shortcode_random_albums' ) ) );
			$placeholders = implode( ',', array_fill( 0, count( $albs ), '%d' ) );
			$photo_arr = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos WHERE album IN ($placeholders) ORDER BY RAND(%d) LIMIT 1000", array_merge($albs, [$seed] ) ) );
		}
		else {
			$photo_arr = $wpdb->get_col( $wpdb->prepare( "SELECT id FROM $wpdb->wppa_photos ORDER BY RAND(%d) LIMIT 1000", $seed ) );
		}
		$photo = wppa_find_first_visible( $photo_arr );
		if ( $photo ) {
			if ( wppa_switch( 'photo_shortcode_random_fixed' ) ) {
				$post_content = $wpdb->get_var( $wpdb->prepare( "SELECT post_content
																 FROM $wpdb->posts
																 WHERE ID = %d", $wppa_postid ) );
				if ( wppa_switch( 'photo_shortcode_random_fixed_html' ) ) {
					$post_content = preg_replace( '/\[photo random\]/', do_shortcode('[photo '.$photo.']'), $post_content, 1, $done );
				}
				else {
					$post_content = preg_replace( '/\[photo random\]/', '[photo '.$photo.']', $post_content, 1, $done );
				}
				$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts
											   SET post_content = %s
											   WHERE ID = %d", $post_content, $wppa_postid ) );
			}
		}
		else {
			return __( 'No random photo found', 'wp-photo-album-plus' );
		}
	}
	elseif ( $photo == '#last' ) {
		$photo_arr = $wpdb->get_col( "SELECT id FROM $wpdb->wppa_photos ORDER BY timestamp DESC LIMIT 1000" );
		$photo = wppa_find_first_visible( $photo_arr );
	}
	elseif ( ! wppa_is_posint( $photo ) ) {
		return __( 'No photo found', 'wp-photo-album-plus' );
	}

	// Get configuration settings
	$type 	= wppa_opt( 'photo_shortcode_type' );

	// Type may be overruled by shortcode arg type="..."
	if ( isset( $xatts['type'] ) && in_array( $xatts['type'], ['photo', 'mphoto', 'xphoto', 'slphoto'] ) ) {
		$type = $xatts['type'];
	}
	$size 	= wppa_opt( 'photo_shortcode_size' ); // '350';
	$align 	= wppa_opt( 'photo_shortcode_align' ); //'left';

	switch ( $type ) {
		case 'photo':
		case 'sphoto':
			$wppa['single_photo'] 	= $photo;
			$wppa['start_photo'] 	= $photo;
			break;
		case 'mphoto':
			$wppa['single_photo'] 	= $photo;
			$wppa['start_photo'] 	= $photo;
			$wppa['is_mphoto'] 		= 1;
			break;
		case 'xphoto':
			$wppa['single_photo'] 	= $photo;
			$wppa['start_photo'] 	= $photo;
			$wppa['is_xphoto'] 		= 1;
			break;
		case 'slphoto':
			$wppa['is_slide'] 		= 1;
			$wppa['single_photo'] 	= $photo;
			$wppa['start_photo'] 	= $photo;
			$wppa['is_single'] 		= 1;
			break;
		default:
			wppa_log( 'err', "Unimplemented photo_shortcode_type: $type in wppa_photo_shortcodes()" );
			break;
	}

	// Process size
	if ( $size && is_numeric( $size ) && $size < 1.0 ) {
		$wppa['auto_colwidth'] 		= true;
		$wppa['fullsize'] 			= $size;
	}
	elseif ( substr( $size, 0, 4 ) == 'auto' ) {
		$wppa['auto_colwidth'] 		= true;
		$wppa['fullsize'] 			= '';
		$wppa['max_width'] 			= substr( $size, 5 );
	}
	else {
		$wppa['auto_colwidth'] 		= false;
		$wppa['fullsize'] 			= $size;
	}

	// Find align
	$wppa['align'] = $align;

	// Cache?
	if ( isset( $xatts['cache'] ) ) {
		$photos_used = $photo;
		$wppa['cache'] = ! in_array( $xatts['cache'], array( '', 0, 'off', 'no' ) );
	}

	// Delay
	if ( isset( $xatts['delay'] ) ) {
		wppa_you_can_not( 'delay', 'single image' );
		$xatts['delay'] = '';
	}

	// Update used BY
	if ( wppa_is_int( $photo ) ) {
		wppa_add_usedby( $photo, get_the_ID(), 'photo' );
	}

	wppa_make_after_smx( $xatts, $photo );

	$result = wppa_albums();

	// Reset
	$wppa_after_smx = '';

	return $result;
}

function wppa_make_after_smx( $xatts, $photo ) {
global $wppa_after_smx;

	if ( $photo > 0 && isset( $xatts['subtext'] ) ) {
		$text = str_replace( '#owner', wppa_display_name( wppa_get_photo_item( $photo, 'owner' ) ), $xatts['subtext'] );
		$text = str_replace( '#name', wppa_get_photo_item( $photo, 'name' ), $text );
		$text = wppa_filter_iptc( $text, $photo, true );				// 2# tags
		$text = wppa_filter_exif( $text, $photo, true );				// E# tags

		$wppa_after_smx = wp_kses_post( $text );
	}
	else {
		$wppa_after_smx = '';
	}
}

// Yuo can not cache/delay a type xxx shortocde
function wppa_you_can_not( $xaction, $xtype, $useless = true ) {
	$action = wppa_translate( $xaction, 'wp-photo-album-plus' );
	$type   = wppa_translate( $xtype, 'wp-photo-album-plus' );
	/* translators: Example: You can not delay a single image shortcode display */
	$result = sprintf( __( 'You can not %1$s a %2$s shortcode display.', 'wp-photo-album-plus' ), $action, $type ) .
			  ( $useless ? ' ' . __( 'It is useless anyway.', 'wp-photo-album-plus' ) : '' );
	return $result;
}

// This function is no longer needed in 8.0
function wppa_insert_shortcode_output( $result ) {
	wppa_log( 'err', 'wppa_insert_shortcode_output() is deprecated and no longer needed' );
	return $result;
}

// Trans;ate virtual tags
function wppa_translate_virtual_tags( $album ) {

	$result = $album;
	if ( strpos( $album, '$y' ) !== false || strpos( $album, '$m' ) !== false ) {
		$y = wp_date('y');
		$y_ = strval( $y - 1 );
		$Y = wp_date('Y');
		$Y_ = strval( $Y - 1 );
		$m = wp_date('m');
		$m_ = strval( $m - 1 );
		if ( strlen( $m_ ) == 1 ) {
			$m_ = '0'.$m_;
		}
		if ( $m_ == '00' ) {
			$m_ = '12';
			$ym_ = $y_ . $m_;
			$Ym_ = $Y_ . $m_;
		}
		else {
			$ym_ = $y . $m_;
			$Ym_ = $Y . $m_;
		}
		$from = ['$yyyymm-', '$yyyymm', '$yymm-', '$yymm', '$yyyy-', '$yyyy', '$yy-', '$yy'];
		$to   = [ $Ym_,       $Y.$m,     $ym_,     $y.$m,   $Y_,      $Y,      $y_,    $y   ];

		$result = str_replace( $from, $to, $result );
	}
	return $result;
}
