I had this very same problem when using Javascript to render data in the HTML and the fields were not showing up in the PDF export. I then scrapped the JS and implemented the data rendering in PHP which works fine but leads to the same outcome. Problem is that when the PDF of the HTML is rendered using DOMPDF library these fields aren't rendered/don't have values. I have tried multiple changes to the code but none have worked yet and I can't seem to find a similar problem online. I don't know if there is anything fundamental that I am missing or not thinking of since I am not very familiar with PHP / DOMPDF. Any insight would be appreciated. [Worpress site with plugin wp-pdf-templates using DOMPDF].
WP PDF Templates Config
<?php
/**
* Plugin Name: WordPress PDF Templates
* Plugin URI: https://github.com/anttiviljami/wp-pdf-templates
* Description: This plugin utilises the DOMPDF Library to provide a URL endpoint e.g. /my-post/pdf/ that generates a downloadable PDF file.
* Version: 1.4.3
* Author: #anttiviljami
* Author URI: https://github.com/anttiviljami
* License: GPLv3
*/
/**
* Copyright 2015-2016 Antti Kuosmanen
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 3, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* WordPress PDF Templates
*
* This plugin utilises the DOMPDF Library to provide a simple URL endpoint
* e.g. http://my-site.com/my-post/pdf/ that generates a downloadable PDF file.
*
* If pretty permalinks are disabled. GET parameters (e.g. ?p=1&pdf) can be used
* instead.
*
* The PDF output can be customized by copying the index-pdf.php file from
* the plugin directory to your theme and creating your own custom template for
* PDF prints.
*
* Stylesheets used on the site are disabled by default, but you can define your
* own stylesheets within the pdf-template.php file. PDF Templates can be
* previewed as raw HTML at the /pdf-preview URL endpoint.
*
* For further information see readme.txt
*/
/**
* Track plugin version number
*/
define('WP_PDF_TEMPLATES_VERSION', '1.4.1');
/**
* Option to disable PDF caching
*
* This can be used for rapidly changing content that's uncacheable, such as
* dynamically generated feeds or user-tailored views.
*/
define('DISABLE_PDF_CACHE', true);
/**
* Option to enable cookies on fetching the PDF template HTML.
*
* This might be useful if the content or access to it depends on browser
* cookies. A possible use scenario for this could be when a login
* authentification is required to access the content.
*/
//define('FETCH_COOKIES_ENABLED', true);
/**
* Set PDF file cache directory
*/
$upload_dir = wp_upload_dir();
if (!defined('PDF_CACHE_DIRECTORY')) {
define('PDF_CACHE_DIRECTORY', $upload_dir['basedir'] . '/pdf-cache/');
}
/**
* Allow remote assets in docs
*/
if (!defined('DOMPDF_ENABLE_REMOTE'))
define('DOMPDF_ENABLE_REMOTE', true);
/**
* Allow remote assets in docs
*/
if (!defined('DOMPDF_ENABLE_HTML5'))
define('DOMPDF_ENABLE_HTML5', true);
/**
* Redefine font directories
*/
if (!defined('DOMPDF_FONT_DIR'))
define('DOMPDF_FONT_DIR', $upload_dir['basedir'] . '/dompdf-fonts/');
if (!defined('DOMPDF_FONT_CACHE'))
define('DOMPDF_FONT_CACHE', $upload_dir['basedir'] . '/dompdf-fonts/');
/**
* This function can be used to set PDF print support for custom post types.
* Takes an array of post types (strings) as input. See defaults below.
*/
function set_pdf_print_support($post_types) {
global $pdf_post_types;
if(is_array($post_types)) {
$pdf_post_types = $post_types;
}
else {
trigger_error('Must supply array as parameter.');
}
}
/**
* Default post types supported are post and page
*/
set_pdf_print_support(array('post', 'page'));
/**
* Adds rewrite rules for printing if using pretty permalinks
*/
add_action('init', '_pdf_rewrite');
function _pdf_rewrite() {
add_rewrite_endpoint('pdf', EP_ALL);
add_rewrite_endpoint('pdf-preview', EP_ALL);
add_rewrite_endpoint('pdf-template', EP_ALL);
}
/**
* Registers print endpoints
*/
add_filter('query_vars', '_get_pdf_query_vars');
function _get_pdf_query_vars($query_vars) {
$query_vars[] = 'pdf';
$query_vars[] = 'pdf-preview';
$query_vars[] = 'pdf-template';
return $query_vars;
}
/**
* Flushes the rewrite rules on plugin activation and deactivation
*/
register_activation_hook(__FILE__, '_flush_pdf_rewrite_rules');
register_deactivation_hook(__FILE__, '_flush_pdf_rewrite_rules');
function _flush_pdf_rewrite_rules() {
// flush rewrite rules
// NOTE: You can also do this by going to Settings > Permalinks and hitting the save button
global $wp_rewrite;
_pdf_rewrite();
$wp_rewrite->flush_rules(false);
}
/**
* Creates a directory for any new fonts the user may upload
*/
register_activation_hook(__FILE__, '_init_dompdf_fonts');
function _init_dompdf_fonts() {
// copy DOMPDF fonts to wp-content/dompdf-fonts/
require_once "vendor/autoload.php";
if(!is_dir(DOMPDF_FONT_DIR)) {
#mkdir(DOMPDF_FONT_DIR);
}
if(!file_exists(DOMPDF_FONT_DIR . '/dompdf_font_family_cache.dist.php')) {
copy(
dirname(__FILE__) . 'vendor/dompdf/dompdf/lib/fonts/dompdf_font_family_cache.dist.php',
DOMPDF_FONT_DIR . '/dompdf_font_family_cache.dist.php'
);
}
}
/**
* Applies print templates
*/
add_action('template_redirect', '_use_pdf_template');
function _use_pdf_template() {
global $wp_query, $pdf_post_types;
if(in_array(get_post_type(), $pdf_post_types)) {
if (isset($wp_query->query_vars['pdf-template'])) {
// Substitute the PDF printing template
// disable scripts and stylesheets
// NOTE: We do this because in most cases the stylesheets used on the site
// won't automatically work with the DOMPDF Library. This way you have to
// define your own PDF styles using <style> tags in the template.
add_action('wp_print_styles', '_remove_dep_arrays', ~PHP_INT_MAX);
add_action('wp_print_scripts', '_remove_dep_arrays', ~PHP_INT_MAX);
add_action('wp_print_footer_scripts', '_remove_dep_arrays', ~PHP_INT_MAX);
// disable the wp admin bar
add_filter('show_admin_bar', '__return_false');
remove_action('wp_head', '_admin_bar_bump_cb');
// use the print template
add_filter('template_include', '_locate_pdf_template');
}
// our post permalink
$url = parse_url(get_the_permalink());
// we use localhost to make sure we're requesting the page from this wordpress instance
$link = $url['scheme'] . '://localhost' . $url['path'];
$link = $link . (strpos($link, '?') === false ? '?' : '&') . 'pdf-template';
if(isset($wp_query->query_vars['pdf']) || isset($wp_query->query_vars['pdf-preview'])) {
// we want a html template
$header = 'Accept:text/html' . "\n";
// since we're always requesting this from localhost, we need to set the Host
// header for WordPress to route our request correctly
$header = 'Host:' . $url['host'] . "\n";
if( defined('FETCH_COOKIES_ENABLED') && FETCH_COOKIES_ENABLED ) {
// pass cookies from current request
if( isset( $_SERVER['HTTP_COOKIE'] ) ) {
$header .= 'Cookie: ' . $_SERVER['HTTP_COOKIE'] . "\n";
}
}
// create a request context for file_get_contents
$context = stream_context_create(array(
'http' => array(
'method' => 'GET',
'header' => $header,
),
'ssl' => array(
'verify_peer' => false, // since we're using localhost, HTTPS doesn't need peer verification
'verify_peer_name' => false,
),
));
// load the generated html from the template endpoint
$html = file_get_contents( $link, false, $context );
if( empty( $html ) ) {
// sometimes the ssl module just fails, fall back to http insted
$html = file_get_contents( str_ireplace( 'https://', 'http://', $link ), false, $context );
}
if( empty( $html ) ) {
// if all else fails, try the public site url (not localhost)
$link = get_the_permalink();
$link = $link . (strpos($link, '?') === false ? '?' : '&') . 'pdf-template';
$html = file_get_contents( $link , false, $context );
}
// process the html output
$html = apply_filters('pdf_template_html', $html);
// pass for printing
_print_pdf($html);
}
}
}
/**
* Locates the theme pdf template file to be used
*/
function _locate_pdf_template($template) {
// locate proper template file
// NOTE: this only works if the standard template file exists as well
// i.e. to use single-product-pdf.php you must also have single-product.php
// #TODO: Utilise a template wrapper like this one: https://roots.io/sage/docs/theme-wrapper/
$pdf_template = str_replace('.php', '-pdf.php', basename($template));
if(file_exists(get_stylesheet_directory() . '/' . $pdf_template)) {
$template_path = get_stylesheet_directory() . '/' . $pdf_template;
}
else if(file_exists(get_template_directory() . '/' . $pdf_template)) {
$template_path = get_template_directory() . '/' . $pdf_template;
}
else if(file_exists(plugin_dir_path(__FILE__) . $pdf_template)) {
$template_path = plugin_dir_path(__FILE__) . $pdf_template;
}
else if(file_exists(get_stylesheet_directory() . '/' . 'index-pdf.php')) {
$template_path = get_stylesheet_directory() . '/' . 'index-pdf.php';
}
else if(file_exists(get_template_directory() . '/' . 'index-pdf.php')) {
$template_path = get_template_directory() . '/' . 'index-pdf.php';
}
else {
$template_path = plugin_dir_path(__FILE__) . 'index-pdf.php';
}
return $template_path;
}
/**
* Removes all scripts and stylesheets
*/
function _remove_dep_arrays() {
global $wp_scripts, $wp_styles;
$wp_scripts = $wp_styles = array();
}
/**
* Filters the html generated from the template for printing
*/
add_filter('pdf_template_html', '_process_pdf_template_html');
function _process_pdf_template_html($html) {
// relative to absolute links
$html = preg_replace('/src\s*=\s*"\//', 'src="' . home_url('/'), $html);
$html = preg_replace('/src\s*=\s*\'\//', "src='" . home_url('/'), $html);
return $html;
}
/**
* Handles the PDF Conversion
*/
function _print_pdf($html) {
global $wp_query;
if (isset($wp_query->query_vars['pdf'])) {
// convert to PDF
$filename = sanitize_file_name(get_the_title());
$cache_id = substr(md5(get_the_modified_time()), -6);
$filename = apply_filters('pdf_template_filename', $filename);
$cache_id = apply_filters('pdf_template_cache_id', $cache_id);
$cached = PDF_CACHE_DIRECTORY . $filename . '-' . $cache_id . '.pdf';
$filename .= '.pdf';
// check if we need to generate PDF against cache
if(( defined('DISABLE_PDF_CACHE') && DISABLE_PDF_CACHE ) || ( isset($_SERVER['HTTP_PRAGMA']) && $_SERVER['HTTP_PRAGMA'] == 'no-cache' ) || !file_exists($cached) ) {
// we may need more than 30 seconds execution time
//set_time_limit(60);
// include the library
require_once 'vendor/autoload.php';
// html to pdf conversion
$dompdf = new Dompdf\Dompdf();
$dompdf->setPaper(
defined('DOMPDF_PAPER_SIZE') ? DOMPDF_PAPER_SIZE : DOMPDF_DEFAULT_PAPER_SIZE,
defined('DOMPDF_PAPER_ORIENTATION') ? DOMPDF_PAPER_ORIENTATION : 'portrait');
$options = $dompdf->getOptions();
$options->set(array(
'fontDir' => DOMPDF_FONT_DIR,
'fontCache' => DOMPDF_FONT_CACHE,
'isHtml5ParserEnabled' => DOMPDF_ENABLE_HTML5,
'isRemoteEnabled' => DOMPDF_ENABLE_REMOTE,
));
// allow setting a different DPI value
if( defined('DOMPDF_DPI') ) $options->set(array('dpi' => DOMPDF_DPI));
$dompdf->setOptions($options);
// allow other plugins to filter the html before passing it to dompdf
$html = apply_filters('pdf_html_to_dompdf', $html);
$dompdf->loadHtml($html);
//$dompdf->setBasePath(get_stylesheet_directory_uri());
$dompdf->render();
if(defined('DISABLE_PDF_CACHE') && DISABLE_PDF_CACHE) {
//just stream the PDF to user if caches are disabled
return $dompdf->stream($filename, array("Attachment" => false));
}
// create PDF cache if one doesn't yet exist
if(!is_dir(PDF_CACHE_DIRECTORY)) {
#mkdir(PDF_CACHE_DIRECTORY);
}
//save the pdf file to cache
file_put_contents($cached, $dompdf->output());
}
//read and display the cached file
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Content-Length: ' . filesize($cached));
header('Accept-Ranges: bytes');
readfile($cached);
}
else {
// print the HTML raw
echo $html;
}
// kill php after output is complete
die();
}
Page Template:
**SOME CONTENT OMITTED**
<?php
$cookie_name = "userScore";
$userScoreCookie = $_COOKIE[$cookie_name];
if(isset($userScoreCookie)) {
// ENCODE
$encodedArray = json_encode($userScoreCookie, true);
// DECODE
$decodedArray = json_decode($encodedArray, true);
// GET NUMBERS FROM OUTPUT
$int_var = preg_replace('/[^0-9]/', '', $decodedArray);
// CONVERT TO INTEGERS
$int_var_sanitize = (int)filter_var($int_var, FILTER_SANITIZE_NUMBER_INT);
$testarray = str_split((string)$int_var_sanitize);
// Filter answers
$count = 0;
foreach($testarray as $value) {
if($value == 1) {
if($count == 0) {
$exportAnswer1 = 'STRONGLY DISAGREE';
} else if($count == 1) {
$exportAnswer2 = 'STRONGLY DISAGREE';
} else if($count == 2) {
$exportAnswer3 = 'STRONGLY DISAGREE';
} else if($count == 3) {
$exportAnswer4 = 'STRONGLY DISAGREE';
} else if($count == 4) {
$exportAnswer5 = 'STRONGLY DISAGREE';
}
$count++;
} else if($value == 2) {
if($count == 0) {
$exportAnswer1 = 'DISAGREE';
} else if($count == 1) {
$exportAnswer2 = 'DISAGREE';
} else if($count == 2) {
$exportAnswer3 = 'DISAGREE';
} else if($count == 3) {
$exportAnswer4 = 'DISAGREE';
} else if($count == 4) {
$exportAnswer5 = 'DISAGREE';
}
$count++;
} else if($value == 3) {
if($count == 0) {
$exportAnswer1 = 'UNCERTAIN';
} else if($count == 1) {
$exportAnswer2 = 'UNCERTAIN';
} else if($count == 2) {
$exportAnswer3 = 'UNCERTAIN';
} else if($count == 3) {
$exportAnswer4 = 'UNCERTAIN';
} else if($count == 4) {
$exportAnswer5 = 'UNCERTAIN';
}
$count++;
} else if($value == 4) {
if($count == 0) {
$exportAnswer1 = 'AGREE';
} else if($count == 1) {
$exportAnswer2 = 'AGREE';
} else if($count == 2) {
$exportAnswer3 = 'AGREE';
} else if($count == 3) {
$exportAnswer4 = 'AGREE';
} else if($count == 4) {
$exportAnswer5 = 'AGREE';
}
$count++;
} else if($value == 5) {
if($count == 0) {
$exportAnswer1 = 'STRONGLY AGREE';
} else if($count == 1) {
$exportAnswer2 = 'STRONGLY AGREE';
} else if($count == 2) {
$exportAnswer3 = 'STRONGLY AGREE';
} else if($count == 3) {
$exportAnswer4 = 'STRONGLY AGREE';
} else if($count == 4) {
$exportAnswer5 = 'STRONGLY AGREE';
}
$count++;
}
}
}
?>
<!-- Input answers -->
<div class="answer" id="export-answer-1"><?php echo $exportAnswer1 ?></div>
<div class="answer" id="export-answer-2"><?php echo $exportAnswer2 ?></div>
<div class="answer" id="export-answer-3"><?php echo $exportAnswer3 ?></div>
<div class="answer" id="export-answer-4"><?php echo $exportAnswer4 ?></div>
<div class="answer" id="export-answer-5"><?php echo $exportAnswer5 ?></div>
**SOME CONTENT OMITTED**
Rendered HTML
<div id="page-wrap" class="container">
<div id="content">
<div id="exportContent">
<div class="container">
<div class="center section-break m-container">
<div class="divider"></div>
<div class="qna-container">
<div class="question">
<span class="blue-text bold mr-5">1.</span> Using my Blue Inhaler Reliever to treat symptoms is the best way to keep on top of my asthma
</div>
<div class="answer" id="export-answer-1">DISAGREE</div>
</div>
<div class="divider"></div>
<div class="qna-container">
<div class="question">
<span class="blue-text bold mr-5">2.</span> I don’t worry about asthma when I have my Blue Reliever Inhaler around
</div>
<div class="answer" id="export-answer-2">UNCERTAIN</div>
</div>
<div class="divider"></div>
<div class="qna-container">
<div class="question">
<span class="blue-text bold mr-5">3.</span> My Blue Reliever Inhaler is the only asthma treatment I can really rely on
</div>
<div class="answer" id="export-answer-3">AGREE</div>
</div>
<div class="divider"></div>
<div class="qna-container">
<div class="question">
<span class="blue-text bold mr-5">4.</span> The benefits of using my Blue Reliever Inhaler easily outweigh any risks
</div>
<div class="answer" id="export-answer-4">UNCERTAIN</div>
</div>
<div class="divider"></div>
<div class="qna-container">
<div class="question">
<span class="blue-text bold mr-5">5.</span> I prefer to rely on my Blue Reliever Inhaler rather than my Steroid Preventer Inhaler
</div>
<div class="answer" id="export-answer-5">DISAGREE</div>
</div>
</div>
</div>
</div>
</div>
</div>
Related
I am making a plugin with a custom post_type called circular I use a meta box to upload PDF or image file now I can retrive the url of the file but how can I get the file name and size from my custom post_type meta field .
Here is my Meta Box code
function add_custom_meta_boxes() {
// Define the custom attachment for posts
add_meta_box(
'wp_custom_attachment',
'Custom Attachment',
'wp_custom_attachment',
'circular',
'side'
);
} // end add_custom_meta_boxes
add_action('add_meta_boxes', 'add_custom_meta_boxes');
function wp_custom_attachment() {
wp_nonce_field(plugin_basename(__FILE__), 'wp_custom_attachment_nonce');
$html = '<p class="description">';
$html .= 'Upload your PDF here.';
$html .= '</p>';
$html .= '<input type="file" id="wp_custom_attachment" name="wp_custom_attachment" value="" size="25" />';
echo $html;
} // end wp_custom_attachment
function save_custom_meta_data($id) {
/* --- security verification --- */
if(!wp_verify_nonce($_POST['wp_custom_attachment_nonce'], plugin_basename(__FILE__))) {
return $id;
} // end if
if(defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return $id;
} // end if
if('circular' == $_POST['post_type']) {
if(!current_user_can('edit_page', $id)) {
return $id;
} // end if
} else {
if(!current_user_can('edit_page', $id)) {
return $id;
} // end if
} // end if
/* - end security verification - */
// Make sure the file array isn't empty
if(!empty($_FILES['wp_custom_attachment']['name'])) {
// Setup the array of supported file types. In this case, it's just PDF.
$supported_types = array('application/pdf');
// Get the file type of the upload
$arr_file_type = wp_check_filetype(basename($_FILES['wp_custom_attachment']['name']));
$uploaded_type = $arr_file_type['type'];
// Check if the type is supported. If not, throw an error.
if(in_array($uploaded_type, $supported_types)) {
// Use the WordPress API to upload the file
$upload = wp_upload_bits($_FILES['wp_custom_attachment']['name'], null, file_get_contents($_FILES['wp_custom_attachment']['tmp_name']));
if(isset($upload['error']) && $upload['error'] != 0) {
wp_die('There was an error uploading your file. The error is: ' . $upload['error']);
} else {
add_post_meta($id, 'wp_custom_attachment', $upload);
update_post_meta($id, 'wp_custom_attachment', $upload);
} // end if/else
} else {
wp_die("The file type that you've uploaded is not a PDF.");
} // end if/else
} // end if
} // end save_custom_meta_data
add_action('save_post', 'save_custom_meta_data');
function update_edit_form() {
echo ' enctype="multipart/form-data"';
} // end update_edit_form
add_action('post_edit_form_tag', 'update_edit_form');
do out put the link of that file
<?php $img = get_post_meta(get_the_ID(), 'wp_custom_attachment', true); ?>
Download PDF Here
First need to get the file url the we can get the size and name . here wp_custom_attachment is the custom field id.
// retrieve file of the custom field
$file = get_post_meta(get_the_ID(), 'wp_custom_attachment', true);
//get the url
$url = $file['url'];
//Replace url to directory path
$path = str_replace( site_url('/'), ABSPATH, esc_url( $url) );
if ( is_file( $path ) ){
$filesize = size_format( filesize( $path ) );
$filename = basename($path);
}
echo '<p>Name: ' . $filename . '</p>';
echo '<p>Size: ' . $filesize . '</p>';
If you can get the attachment ID number ($attachment_id below) you should be able to do something like this to get the name/size:
$attachment_id = 'YOUR_PDF_ID';
$attahment_file = get_attached_file( $attachment_id );
function getSize($file) {
$bytes = filesize($file);
$s = array('b', 'Kb', 'Mb', 'Gb');
$e = floor(log($bytes)/log(1024));
return sprintf( '%.2f ' . $s[$e], ( $bytes/pow( 1024, floor($e) ) ) );
}
echo '<p>Name: ' . basename( $attahment_file ) . '</p>';
echo '<p>Size: ' . getSize( $attahment_file ) . '</p>';
I found the "getSize" function on another post here. It was more accurate than using the native PHP "filesize" function in terms of matching the size shown in the WP media library meta.
The following code will set the class nav on the first level UL
$mainNav = public_nav_main();
$mainNav->setUlClass('nav')->setUlId('main-menu-left');
However im using bootstrap and so want the second level ul to have the class 'dropdown-menu'
I cant seem to find a reference to get this sorted.
Zend is being used as the base structure in the software im using, Omeka. Unfortunately Omeka doesnt have a way to do this natively so I am having to dive into the underlying Zend FW although I dont want to modify that too much as it might be changed.
You might just want to write a totally new View Helper based off Zend_View_Helper_Navigation_HelperAbstract.
Looking on GitHub for a bootstrap compatible helper based on that abstract I did encounter this: https://github.com/michaelmoussa/zf1-navigation-view-helper-bootstrap/blob/master/library/ZFBootstrap/View/Helper/Navigation/Menu.php which takes an interesting approach, post processing the markup generated from the out-of-the-box helpers.
I took a slightly different approach recently and just hacked the heck out of Zend_View_Helper_Navigation_Menu. Here is a unified diff summarizing those changes: http://pastebin.com/mrJG8QCt Better though to extend the class...
I didn't deal with sub-menus, however the issues I ran into were...
Way to add aria-role to <li> elements.
Avoid collision when rendering the menu twice - two representations - collapsed bootstrap style and traditional one for larger viewports. -Maybe ZF already offered something to work around this? Didn't jump out at me if there was.
This code shows the methods you need to tweak:
class MyMenu extends Zend_View_Helper_Navigation_Menu
{
/**
* Want a way to set aria role on menu li elements because its 2015 yo
*
* #var string
*/
protected $_liRole = '';
/**
* Workaround so I can render the damn thing twice on the same page and not collide IDs on the <a>'s
* Issue arose when adopting bootstrap and rendering both full page nav and collapsed nav bar
*
* #var string
*/
protected $_idAlias = '';
public function setLiRole($liRole)
{
if (is_string($liRole)) {
$this->_liRole = $liRole;
}
return $this;
}
public function getLiRole()
{
return $this->_liRole;
}
public function setIdAlias($alias)
{
$this->_idAlias = $alias;
return $this;
}
public function getIdAlias()
{
return $this->_idAlias;
}
public function renderMenu(Zend_Navigation_Container $container = null, array $options = array())
{
$this->setLiRole($options['liRole']);
$this->setIdAlias($options['idAlias']);
return parent::renderMenu($container, $options);
}
/**
* Returns an HTML string containing an 'a' element for the given page if
* the page's href is not empty, and a 'span' element if it is empty
*
* Overrides {#link Zend_View_Helper_Navigation_Abstract::htmlify()}.
*
* #param Zend_Navigation_Page $page page to generate HTML for
* #return string HTML string for the given page
*/
public function htmlify(Zend_Navigation_Page $page)
{
// get label and title for translating
$label = $page->getLabel();
$title = $page->getTitle();
// translate label and title?
if ($this->getUseTranslator() && $t = $this->getTranslator()) {
if (is_string($label) && !empty($label)) {
$label = $t->translate($label);
}
if (is_string($title) && !empty($title)) {
$title = $t->translate($title);
}
}
// get attribs for element
$attribs = array(
'id' => $this->getIdAlias() . $page->getId(),
'title' => $title,
'class' => $page->getClass()
);
// does page have a href?
if ($href = $page->getHref()) {
$element = 'a';
$attribs['href'] = $href;
$attribs['target'] = $page->getTarget();
} else {
$element = 'span';
}
return '<' . $element . $this->_htmlAttribs($attribs) . '><span class="span-nav-icon"></span><span>'
. str_replace(chr(32), ' ', $this->view->escape($label))
. '</span></' . $element . '>';
}
/**
* Normalizes given render options
*
* #param array $options [optional] options to normalize
* #return array normalized options
*/
protected function _normalizeOptions(array $options = array())
{
if (isset($options['indent'])) {
$options['indent'] = $this->_getWhitespace($options['indent']);
} else {
$options['indent'] = $this->getIndent();
}
if (isset($options['ulClass']) && $options['ulClass'] !== null) {
$options['ulClass'] = (string) $options['ulClass'];
} else {
$options['ulClass'] = $this->getUlClass();
}
if (isset($options['liRole']) && $options['liRole'] !== null) {
$options['liRole'] = (string) $options['liRole'];
} else {
$options['liRole'] = $this->getLiRole();
}
if (isset($options['idAlias']) && $options['idAlias'] !== null) {
$options['idAlias'] = (string) $options['idAlias'];
} else {
$options['idAlias'] = '';
}
if (array_key_exists('minDepth', $options)) {
if (null !== $options['minDepth']) {
$options['minDepth'] = (int) $options['minDepth'];
}
} else {
$options['minDepth'] = $this->getMinDepth();
}
if ($options['minDepth'] < 0 || $options['minDepth'] === null) {
$options['minDepth'] = 0;
}
if (array_key_exists('maxDepth', $options)) {
if (null !== $options['maxDepth']) {
$options['maxDepth'] = (int) $options['maxDepth'];
}
} else {
$options['maxDepth'] = $this->getMaxDepth();
}
if (!isset($options['onlyActiveBranch'])) {
$options['onlyActiveBranch'] = $this->getOnlyActiveBranch();
}
if (!isset($options['renderParents'])) {
$options['renderParents'] = $this->getRenderParents();
}
return $options;
}
/**
* Renders the deepest active menu within [$minDepth, $maxDeth], (called
* from {#link renderMenu()})
*
* #param Zend_Navigation_Container $container container to render
* #param array $active active page and depth
* #param string $ulClass CSS class for first UL
* #param string $indent initial indentation
* #param int|null $minDepth minimum depth
* #param int|null $maxDepth maximum depth
* #return string rendered menu
*/
protected function _renderDeepestMenu(Zend_Navigation_Container $container,
$ulClass,
$indent,
$minDepth,
$maxDepth)
{
if (!$active = $this->findActive($container, $minDepth - 1, $maxDepth)) {
return '';
}
// special case if active page is one below minDepth
if ($active['depth'] < $minDepth) {
if (!$active['page']->hasPages()) {
return '';
}
} else if (!$active['page']->hasPages()) {
// found pages has no children; render siblings
$active['page'] = $active['page']->getParent();
} else if (is_int($maxDepth) && $active['depth'] +1 > $maxDepth) {
// children are below max depth; render siblings
$active['page'] = $active['page']->getParent();
}
$ulClass = $ulClass ? ' class="' . $ulClass . '"' : '';
$html = $indent . '<ul' . $ulClass . '>' . self::EOL;
$liRole = (! empty($this->getLiRole())) ? "role=\"{$this->getLiRole()}\"" : "";
foreach ($active['page'] as $subPage) {
if (!$this->accept($subPage)) {
continue;
}
$liClass = $subPage->isActive(true) ? ' class="active"' : '';
$html .= $indent . ' <li' . $liClass . ' ' . $liRole . '>' . self::EOL;
$html .= $indent . ' ' . $this->htmlify($subPage) . self::EOL;
$html .= $indent . ' </li>' . self::EOL;
}
$html .= $indent . '</ul>';
return $html;
}
/**
* Renders a normal menu (called from {#link renderMenu()})
*
* #param Zend_Navigation_Container $container container to render
* #param string $ulClass CSS class for first UL
* #param string $indent initial indentation
* #param int|null $minDepth minimum depth
* #param int|null $maxDepth maximum depth
* #param bool $onlyActive render only active branch?
* #return string
*/
protected function _renderMenu(Zend_Navigation_Container $container,
$ulClass,
$indent,
$minDepth,
$maxDepth,
$onlyActive)
{
$html = '';
// find deepest active
if ($found = $this->findActive($container, $minDepth, $maxDepth)) {
$foundPage = $found['page'];
$foundDepth = $found['depth'];
} else {
$foundPage = null;
}
// create iterator
$iterator = new RecursiveIteratorIterator($container,
RecursiveIteratorIterator::SELF_FIRST);
if (is_int($maxDepth)) {
$iterator->setMaxDepth($maxDepth);
}
// iterate container
$prevDepth = -1;
foreach ($iterator as $page) {
$depth = $iterator->getDepth();
$isActive = $page->isActive(true);
if ($depth < $minDepth || !$this->accept($page)) {
// page is below minDepth or not accepted by acl/visibilty
continue;
} else if ($onlyActive && !$isActive) {
// page is not active itself, but might be in the active branch
$accept = false;
if ($foundPage) {
if ($foundPage->hasPage($page)) {
// accept if page is a direct child of the active page
$accept = true;
} else if ($foundPage->getParent()->hasPage($page)) {
// page is a sibling of the active page...
if (!$foundPage->hasPages() ||
is_int($maxDepth) && $foundDepth + 1 > $maxDepth) {
// accept if active page has no children, or the
// children are too deep to be rendered
$accept = true;
}
}
}
if (!$accept) {
continue;
}
}
$liRole = (! empty($this->getLiRole())) ? "role=\"{$this->getLiRole()}\"" : "";
// make sure indentation is correct
$depth -= $minDepth;
$myIndent = $indent . str_repeat(' ', $depth);
if ($depth > $prevDepth) {
// start new ul tag
if ($ulClass && $depth == 0) {
$ulClass = ' class="' . $ulClass . '"';
} else {
$ulClass = '';
}
$html .= $myIndent . '<ul' . $ulClass . '>' . self::EOL;
} else if ($prevDepth > $depth) {
// close li/ul tags until we're at current depth
for ($i = $prevDepth; $i > $depth; $i--) {
$ind = $indent . str_repeat(' ', $i);
$html .= $ind . ' </li>' . self::EOL;
$html .= $ind . '</ul>' . self::EOL;
}
// close previous li tag
$html .= $myIndent . ' </li>' . self::EOL;
} else {
// close previous li tag
$html .= $myIndent . ' </li>' . self::EOL;
}
// render li tag and page
$liClass = $isActive ? ' class="active"' : '';
$html .= $myIndent . ' <li' . $liClass . ' ' . $liRole . '>' . self::EOL
. $myIndent . ' ' . $this->htmlify($page) . self::EOL;
// store as previous depth for next iteration
$prevDepth = $depth;
}
if ($html) {
// done iterating container; close open ul/li tags
for ($i = $prevDepth+1; $i > 0; $i--) {
$myIndent = $indent . str_repeat(' ', $i-1);
$html .= $myIndent . ' </li>' . self::EOL
. $myIndent . '</ul>' . self::EOL;
}
$html = rtrim($html, self::EOL);
}
return $html;
}
}
Admittedly a lot of code. Might be good to diff the class you have now against this http://pastebin.com/qiD2ULsz - and then seeing what the touch points are, creating a new extending class. Really just the new properties and some "tweaks" to the string concatenation it does to render the markup.
I don't specifically address class on "second level ul's" but passing in an additional property would be trivial and follow the same changes I did make.
Hope this helps some. ZF 1.x shows its age a bit and these view helpers were never that great. The underlying Nav code isn't too bad, so again, maybe just start from scratch and write your own code to render a Zend Nav Container. Good luck.
This is admittedly an ugly hack, but you could do it by processing the output of public_nav_main() with a regular expression. So in the header.php file you would replace:
echo public_nav_main();
with
echo preg_replace( "/(?<!\/)ul(?!.*?nav)/", 'ul class="dropdown-menu"', public_nav_main() );
This will only work if you only have 2 levels in your menu, since the above regular expression will also add the class="dropdown-menu" to all ul elements below the top level ul.
Benefits
Simple
Achieves what you want to do
Doesn't require writing helpers or modifying the underlying framework
Should not break when the underlying framework is updated unless the update renders something other than a string from public_nav_main()
Downsides
Won't work if your menu has more than two levels
Will result in having two class attributes in your 2nd and lower level ul elements in the event that they already have a class attribute
I want to display Download Android App message(An image) to users browsing from Android device. For that i have created a content plugin but it is not working properly. It is showing Message to desktop users as well and only at the place of article content. I want to display this image in full page body and no other content(like headers,menus,footer,sidebars) should be displayed other than it.I am a newbie to joomla development so please help.
here's my androidmsg.php
<?php
defined('_JEXEC') or die;
defined('JPATH_BASE') or die;
jimport('joomla.plugin.plugin');
class plgcontentandroidmsg extends JPlugin {
function __construct(&$subject, $params) {
parent::__construct($subject, $params);
}
function onContentPrepare($context, &$article, &$params, $offset = 0) {
$app = JFactory::getApplication();
if ($app->isAdmin()) {
return;
}
$title = &$article->title;
$text = &$article->text;
$uri = JFactory::getURI();
if (isset($_SERVER['HTTP_USER_AGENT'])) {
$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
if (stripos($ua, 'android') !== false) {
if (isset($_COOKIE["user"])) {
$app->redirect($uri);
} else {
$expire = time() + 60 * 60 * 24 * 30;
setcookie("user", "app_android", $expire);
$text = '<div><img src="'. JPATH_BASE .'/abc/abc.png"/></div>';
}
}
}
return true;
}
}
My host confirmed that Zend 2.3 is installed. I then proceeded to check the installation was working by uploading this script:
http://www.jarodmorris.com/zend_check.php
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to license#zend.com so we can send you a copy immediately.
*
* #category Zend
* #package Zend_Gdata
* #subpackage Demos
* #copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
* #license http://framework.zend.com/license/new-bsd New BSD License
*/
/**
* Simple class to verify that the server that this is run on has a correct
* installation of the Zend Framework Gdata component.
*/
class InstallationChecker {
const CSS_WARNING = '.warning { color: #fff; background-color: #AF0007;}';
const CSS_SUCCESS = '.success { color: #000; background-color: #69FF4F;}';
const CSS_ERROR = '.error { color: #fff; background-color: #FF9FA3;}';
const PHP_EXTENSION_ERRORS = 'PHP Extension Errors';
const PHP_MANUAL_LINK_FRAGMENT = 'http://us.php.net/manual/en/book.';
const PHP_REQUIREMENT_CHECKER_ID = 'PHP Requirement checker v0.1';
const SSL_CAPABILITIES_ERRORS = 'SSL Capabilities Errors';
const YOUTUBE_API_CONNECTIVITY_ERRORS = 'YouTube API Connectivity Errors';
const ZEND_GDATA_INSTALL_ERRORS = 'Zend Framework Installation Errors';
const ZEND_SUBVERSION_URI = 'http://framework.zend.com/download/subversion';
private static $REQUIRED_EXTENSIONS = array(
'ctype', 'dom', 'libxml', 'spl', 'standard', 'openssl');
private $_allErrors = array(
self::PHP_EXTENSION_ERRORS => array(
'tested' => false, 'errors' => null),
self::ZEND_GDATA_INSTALL_ERRORS => array(
'tested' => false, 'errors' => null),
self::SSL_CAPABILITIES_ERRORS => array(
'tested' => false, 'errors' => null),
self::YOUTUBE_API_CONNECTIVITY_ERRORS => array(
'tested' => false, 'errors' => null)
);
private $_sapiModeCLI = null;
/**
* Create a new InstallationChecker object and run verifications.
* #return void
*/
public function __construct()
{
$this->determineIfInCLIMode();
$this->runAllVerifications();
$this->outputResults();
}
/**
* Set the sapiModeCLI variable to true if we are running CLI mode.
*
* #return void
*/
private function determineIfInCLIMode()
{
if (php_sapi_name() == 'cli') {
$this->_sapiModeCLI = true;
}
}
/**
* Getter for sapiModeCLI variable.
*
* #return boolean True if we are running in CLI mode.
*/
public function runningInCLIMode()
{
if ($this->_sapiModeCLI) {
return true;
} else {
return false;
}
}
/**
* Run verifications, stopping at each step if there is a failure.
*
* #return void
*/
public function runAllVerifications()
{
if (!$this->validatePHPExtensions()) {
return;
}
if (!$this->validateZendFrameworkInstallation()) {
return;
}
if (!$this->testSSLCapabilities()) {
return;
}
if (!$this->validateYouTubeAPIConnectivity()) {
return;
}
}
/**
* Validate that the required PHP Extensions are installed and available.
*
* #return boolean False if there were errors.
*/
private function validatePHPExtensions()
{
$phpExtensionErrors = array();
foreach (self::$REQUIRED_EXTENSIONS as $requiredExtension) {
if (!extension_loaded($requiredExtension)) {
$requiredExtensionError = $requiredExtension .
' extension missing';
$documentationLink = null;
if ($requiredExtension != 'standard') {
$documentationLink = self::PHP_MANUAL_LINK_FRAGMENT .
$requiredExtension . '.php';
$documentationLink =
$this->checkAndAddHTMLLink($documentationLink);
} else {
$documentationLink = self::PHP_MANUAL_LINK_FRAGMENT .
'spl.php';
$documentationLink =
$this->checkAndAddHTMLLink($documentationLink);
}
if ($documentationLink) {
$phpExtensionErrors[] = $requiredExtensionError .
' - refer to ' . $documentationLink;
}
}
}
$this->_allErrors[self::PHP_EXTENSION_ERRORS]['tested'] = true;
if (count($phpExtensionErrors) > 0) {
$this->_allErrors[self::PHP_EXTENSION_ERRORS]['errors'] =
$phpExtensionErrors;
return false;
}
return true;
}
/**
* Validate that the Gdata component of Zend Framework is installed
* properly. Also checks that the required YouTube API helper methods are
* found.
*
* #return boolean False if there were errors.
*/
private function validateZendFrameworkInstallation()
{
$zendFrameworkInstallationErrors = array();
$zendLoaderPresent = false;
try {
$zendLoaderPresent = #fopen('Zend/Loader.php', 'r', true);
} catch (Exception $e) {
$zendFrameworkInstallationErrors[] = 'Exception thrown trying to ' .
'access Zend/Loader.php using \'use_include_path\' = true ' .
'Make sure you include the Zend Framework in your ' .
'include_path which currently contains: "' .
ini_get('include_path') . '"';
}
if ($zendLoaderPresent) {
#fclose($zendLoaderPresent);
require_once('Zend/Loader.php');
require_once('Zend/Version.php');
Zend_Loader::loadClass('Zend_Gdata_YouTube');
Zend_Loader::loadClass('Zend_Gdata_YouTube_VideoEntry');
$yt = new Zend_Gdata_YouTube();
$videoEntry = $yt->newVideoEntry();
if (!method_exists($videoEntry, 'setVideoTitle')) {
$zendFrameworkMessage = 'Your version of the ' .
'Zend Framework ' . Zend_Version::VERSION . ' is too old' .
' to run the YouTube demo application and does not' .
' contain the new helper methods. Please check out a' .
' newer version from Zend\'s repository: ' .
checkAndAddHTMLLink(self::ZEND_SUBVERSION_URI);
$zendFrameworkInstallationErrors[] = $zendFrameworkMessage;
}
} else {
if (count($zendFrameworkInstallationErrors) < 1) {
$zendFrameworkInstallationErrors[] = 'Exception thrown trying' .
' to access Zend/Loader.php using \'use_include_path\' =' .
' true. Make sure you include Zend Framework in your' .
' include_path which currently contains: ' .
ini_get('include_path');
}
}
$this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['tested'] = true;
if (count($zendFrameworkInstallationErrors) > 0) {
$this->_allErrors[self::ZEND_GDATA_INSTALL_ERRORS]['errors'] =
$zendFrameworkInstallationErrors;
return false;
}
return true;
}
/**
* Create HTML link from an input string if not in CLI mode.
*
* #param string The error message to be converted to a link.
* #return string Either the original error message or an HTML version.
*/
private function checkAndAddHTMLLink($inputString) {
if (!$this->runningInCLIMode()) {
return $this->makeHTMLLink($inputString);
} else {
return $inputString;
}
}
/**
* Create an HTML link from a string.
*
* #param string The string to be made into link text and anchor target.
* #return string HTML link.
*/
private function makeHTMLLink($inputString)
{
return '<a href="'. $inputString . '" target="_blank">' .
$inputString . '</a>';
}
/**
* Validate that SSL Capabilities are available.
*
* #return boolean False if there were errors.
*/
private function testSSLCapabilities()
{
$sslCapabilitiesErrors = array();
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Http_Client');
$httpClient = new Zend_Http_Client(
'https://www.google.com/accounts/AuthSubRequest');
$response = $httpClient->request();
$this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['tested'] = true;
if ($response->isError()) {
$sslCapabilitiesErrors[] = 'Response from trying to access' .
' \'https://www.google.com/accounts/AuthSubRequest\' ' .
$response->getStatus() . ' - ' . $response->getMessage();
}
if (count($sslCapabilitiesErrors) > 0) {
$this->_allErrors[self::SSL_CAPABILITIES_ERRORS]['errors'] =
$sslCapabilitiesErrors;
return false;
}
return true;
}
/**
* Validate that we can connect to the YouTube API.
*
* #return boolean False if there were errors.
*/
private function validateYouTubeAPIConnectivity()
{
$connectivityErrors = array();
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_YouTube');
$yt = new Zend_Gdata_YouTube();
$topRatedFeed = $yt->getTopRatedVideoFeed();
if ($topRatedFeed instanceof Zend_Gdata_YouTube_VideoFeed) {
if ($topRatedFeed->getTotalResults()->getText() < 1) {
$connectivityErrors[] = 'There was less than 1 video entry' .
' in the \'Top Rated Video Feed\'';
}
} else {
$connectivityErrors[] = 'The call to \'getTopRatedVideoFeed()\' ' .
'did not result in a Zend_Gdata_YouTube_VideoFeed object';
}
$this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] =
true;
if (count($connectivityErrors) > 0) {
$this->_allErrors[self::YOUTUBE_API_CONNECTIVITY_ERRORS]['tested'] =
$connectivityErrors;
return false;
}
return true;
}
/**
* Dispatch a call to outputResultsInHTML or outputResultsInText pending
* the current SAPI mode.
*
* #return void
*/
public function outputResults()
{
if ($this->_sapiModeCLI) {
print $this->getResultsInText();
} else {
print $this->getResultsInHTML();
}
}
/**
* Return a string representing the results of the verifications.
*
* #return string A string representing the results.
*/
private function getResultsInText()
{
$output = "== Ran PHP Installation Checker using CLI ==\n";
$error_count = 0;
foreach($this->_allErrors as $key => $value) {
$output .= $key . ' -- ';
if (($value['tested'] == true) && (count($value['errors']) == 0)) {
$output .= "No errors found\n";
} elseif ($value['tested'] == true) {
$output .= "Tested\n";
$error_count = 0;
foreach ($value['errors'] as $error) {
$output .= "Error number: " . $error_count . "\n--" .
$error . "\n";
}
} else {
$output .= "Not tested\n";
}
$error_count++;
}
return $output;
}
/**
* Return an HTML table representing the results of the verifications.
*
* #return string An HTML string representing the results.
*/
private function getResultsInHTML()
{
$html = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" " .
"\"http://www.w3.org/TR/html4/strict.dtd\">\n".
"<html><head>\n<title>PHP Installation Checker</title>\n" .
"<style type=\"text/css\">\n" .
self::CSS_WARNING . "\n" .
self::CSS_SUCCESS . "\n" .
self::CSS_ERROR . "\n" .
"</style></head>\n" .
"<body>\n<table class=\"verification_table\">" .
"<caption>Ran PHP Installation Checker on " .
gmdate('c') . "</caption>\n";
$error_count = 0;
foreach($this->_allErrors as $key => $value) {
$html .= "<tr><td class=\"verification_type\">" . $key . "</td>";
if (($value['tested'] == true) && (count($value['errors']) == 0)) {
$html .= "<td class=\"success\">Tested</td></tr>\n" .
"<tr><td colspan=\"2\">No errors found</td></tr>\n";
} elseif ($value['tested'] == true) {
$html .= "<td class=\"warning\">Tested</td></tr>\n";
$error_count = 0;
foreach ($value['errors'] as $error) {
$html .= "<tr><td class=\"error\">" . $error_count . "</td>" .
"<td class=\"error\">" . $error . "</td></tr>\n";
}
} else {
$html .= "<td class=\"warning\">Not tested</td></tr>\n";
}
$error_count++;
}
$html .= "</body></html>";
return $html;
}
}
$installationChecker = new InstallationChecker();
Go to the above link to see the results. Specifically, I'm interested in this error message:
Exception thrown trying to access Zend/Loader.php using 'use_include_path' = true.
Make sure you include Zend Framework in your include_path which currently contains:
.:/usr/lib/php:/usr/local/lib/php
Here is the link to my php info printout: http://www.jarodmorris.com/cms/phpinfo.php
I've obtained the Zend Framework from the zend website and uploaded it to a /zend folder on my website. For whatever reason, my host won't give me access to the php.ini file. I have purchased a reseller account with my host.
I'm doing all of this because I want to integrate Google Calendar API into an application I'm building on one of my websites. Maybe there is a simpler solution to my ultimate goal, but I don't see it.
Thanks for pointing me in the right direction.
EDITED TO SHOW CURRENT PHP CODE WHERE INCLUDE IS CONCERNED:
set_include_path(get_include_path() . PATH_SEPARATOR . "/home/jarodmo/public_html/zend/library");
echo get_include_path();
echo "<br>";
///home/jarodmo/public_html/zend/library/Zend
Add the dir to your include path:
set_include_path(
get_include_path()
. PATH_SEPARATOR
. '/whatever/your/zend/dir/is');
My application allows registered users to post stuff. On the top bar, like many social apps, when logged in one can see their avatar etc.
My issue is that the user-specific content in the header gets cached when using CodeIgniter's output cache.
This is because first I load user-specific logic via a MY_Controller, which is then extended by all other controllers.
When I place
$this->output->cache(MINUTES);
in the controller that loads my home page, it also ends up caching the avatar and name of the user that generated that cached page.
Does anyone have a suggestion on what would be the best way to selectively cache only the public content? Glad to post more code if needed.
I'm sure someone will correct me if I'm wrong but I believe codeigniter caching only allows the caching of full pages. There are some additional libraries which enable partial page caching, check out phil sturgeons effort here:
http://getsparks.org/packages/cache/show
My personal approach is to not bother with page caching and just use database caching which is more selective - but if you want/need page caching then I think the above is the only way to go
Codeigniter do not separate cache by visitor and authenticated user.
Otherwise you can do it by yourself by override output class.
Create MY_Output.php in CI/application/core
This is my code for latest project.
class MY_Output extends CI_Output
{
/**
* Write Cache
*
* #param string $output Output data to cache
* #return void
*/
public function _write_cache($output)
{
$CI =& get_instance();
//-XXX CUSTOM------------------------------------
$cache_path = $this->cachePath();
//-----------------------------------------------
if ( ! is_dir($cache_path) OR ! is_really_writable($cache_path))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
$uri = $CI->config->item('base_url')
.$CI->config->item('index_page')
.$CI->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
$cache_path .= md5($uri);
if ( ! $fp = #fopen($cache_path, 'w+b'))
{
log_message('error', 'Unable to write cache file: '.$cache_path);
return;
}
if ( ! flock($fp, LOCK_EX))
{
log_message('error', 'Unable to secure a file lock for file at: '.$cache_path);
fclose($fp);
return;
}
// If output compression is enabled, compress the cache
// itself, so that we don't have to do that each time
// we're serving it
if ($this->_compress_output === TRUE)
{
$output = gzencode($output);
if ($this->get_header('content-type') === NULL)
{
$this->set_content_type($this->mime_type);
}
}
$expire = time() + ($this->cache_expiration * 60);
// Put together our serialized info.
$cache_info = serialize(array(
'expire' => $expire,
'headers' => $this->headers
));
$output = $cache_info.'ENDCI--->'.$output;
for ($written = 0, $length = self::strlen($output); $written < $length; $written += $result)
{
if (($result = fwrite($fp, self::substr($output, $written))) === FALSE)
{
break;
}
}
flock($fp, LOCK_UN);
fclose($fp);
if ( ! is_int($result))
{
#unlink($cache_path);
log_message('error', 'Unable to write the complete cache content at: '.$cache_path);
return;
}
chmod($cache_path, 0640);
log_message('debug', 'Cache file written: '.$cache_path);
// Send HTTP cache-control headers to browser to match file cache settings.
$this->set_cache_header($_SERVER['REQUEST_TIME'], $expire);
}
// --------------------------------------------------------------------
/**
* Update/serve cached output
*
* #uses CI_Config
* #uses CI_URI
*
* #param object &$CFG CI_Config class instance
* #param object &$URI CI_URI class instance
* #return bool TRUE on success or FALSE on failure
*/
public function _display_cache(&$CFG, &$URI)
{
//-XXX CUSTOM------------------------------------
$cache_path = $this->cachePath($CFG);
//$cache_path = ($CFG->item('cache_path') === '') ? APPPATH.'cache/' : $CFG->item('cache_path');
//-----------------------------------------------
// Build the file path. The file name is an MD5 hash of the full URI
$uri = $CFG->item('base_url').$CFG->item('index_page').$URI->uri_string;
if (($cache_query_string = $CFG->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
$filepath = $cache_path.md5($uri);
if ( ! file_exists($filepath) OR ! $fp = #fopen($filepath, 'rb'))
{
return FALSE;
}
flock($fp, LOCK_SH);
$cache = (filesize($filepath) > 0) ? fread($fp, filesize($filepath)) : '';
flock($fp, LOCK_UN);
fclose($fp);
// Look for embedded serialized file info.
if ( ! preg_match('/^(.*)ENDCI--->/', $cache, $match))
{
return FALSE;
}
$cache_info = unserialize($match[1]);
$expire = $cache_info['expire'];
$last_modified = filemtime($filepath);
// Has the file expired?
if ($_SERVER['REQUEST_TIME'] >= $expire && is_really_writable($cache_path))
{
// If so we'll delete it.
#unlink($filepath);
log_message('debug', 'Cache file has expired. File deleted.');
return FALSE;
}
// Send the HTTP cache control headers
$this->set_cache_header($last_modified, $expire);
// Add headers from cache file.
foreach ($cache_info['headers'] as $header)
{
$this->set_header($header[0], $header[1]);
}
//-XXX CUSTOM------------------------------------
$exTime = $this->executionTime();
setcookie('exe_time', "$exTime", time()+120, '/');
//-----------------------------------------------
// Display the cache
$this->_display(self::substr($cache, self::strlen($match[0])));
log_message('debug', 'Cache file is current. Sending it to browser.');
return TRUE;
}
// --------------------------------------------------------------------
/**
* Delete cache
*
* #param string $uri URI string
* #return bool
*/
public function delete_cache($uri = '')
{
$CI =& get_instance();
//-XXX CUSTOM------------------------------------
$cache_path = $CI->config->item('cache_path');
$cache_path = ($cache_path === '') ? APPPATH.'cache/' : $cache_path;
//-----------------------------------------------
if ( ! is_dir($cache_path))
{
log_message('error', 'Unable to find cache path: '.$cache_path);
return FALSE;
}
if (empty($uri))
{
$uri = $CI->uri->uri_string();
if (($cache_query_string = $CI->config->item('cache_query_string')) && ! empty($_SERVER['QUERY_STRING']))
{
if (is_array($cache_query_string))
{
$uri .= '?'.http_build_query(array_intersect_key($_GET, array_flip($cache_query_string)));
}
else
{
$uri .= '?'.$_SERVER['QUERY_STRING'];
}
}
}
//-XXX CUSTOM------------------------------------
$passed = TRUE;
$path1 = $cache_path.'xmember/'.md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/'));
if ( ! #unlink($path1))
{
log_message('error', 'Unable to delete cache file for '.$uri);
$passed = FALSE;
}
$path2 = $cache_path.'xvisitor/'.md5($CI->config->item('base_url').$CI->config->item('index_page').ltrim($uri, '/'));
if ( ! #unlink($path2))
{
log_message('error', 'Unable to delete cache file for '.$uri);
$passed = FALSE;
}
//-----------------------------------------------
return $passed;
}
private function cachePath(&$CFG=false)
{
$hasSession = !empty($_COOKIE[COOKIE_CUSTOMER_SESSION_ID]);
if(empty($CFG)) {
$CI =& get_instance();
$CFG = $CI->config;
}
$path = $CFG->item('cache_path');
$path = empty($path) ? APPPATH.'cache/' : $path;
$path .= $hasSession?'xmember/':'xvisitor/';
return $path;
}
function executionTime()
{
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
$total_time = round(($time - LOAD_PAGE_START), 4); //second unit
return $total_time;
}
}