We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 6350
    • 421 Posts
    QuickEdit とか Manager からの編集で単独のドキュメントは更新できるようになりますた。
    残るは、ひとつだけかな ・・・ たぶん、他にもありそうだけど。。
    ドキュメントの追加、編集がブログエントリー一覧に反映できないんですょん

    if ( isUserLoggedIn() )  nocache_headers();
    
    $site_start = $modx->config['site_start'];
    switch ($modx->documentObject['id']) {
    case $site_start:		// ドキュメント以外にカウンタ、最新情報などを含むページ
    case 2:			// ブログ一覧が更新できないんだよ~~っ
    	$modx_last_modified = $modx->runSnippet('Ditto', array( 'parents'=>'0','display'=>'1', 'tpl'=>'@CODE:[+editedon+]','orderBy'=>'editedon DESC') );
    	$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    	$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
    
    		if ( ($client_last_modified) ? ($client_modified_timestamp >= $modx_last_modified) : 0 ) {
    			header("HTTP/1.1 304 Not Modified");
    			header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    			exit;
    		}
    
    	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
    	break;
    case 11:			// RSS のページは常に 200 OK ETag は単なる飾りではない
    	$modx_last_modified = $modx->runSnippet('Ditto', array( 'parents'=>'2','display'=>'1', 'tpl'=>'@CODE:[+editedon+]','orderBy'=>'editedon DESC') );
    	$etag = '"' . md5($modx_last_modified) . '"';
    	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
    	header("ETag: $etag");
    	break;
    default:			// ドキュメント自身が最終更新日となるページ
    	$modx_last_modified = $modx->documentObject["editedon"];
    //	$modx_last_modified = $modx->runSnippet('Ditto', array( 'parents'=>'0','display'=>'1', 'tpl'=>'@CODE:[+editedon+]','orderBy'=>'editedon DESC') );
    	$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
    	$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
    
    		if ( ($client_last_modified) ? ($client_modified_timestamp >= $modx_last_modified) : 0 ) {
    			header("HTTP/1.1 304 Not Modified");
    			header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    			exit;
    		} 
    
    	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
    }
    
    function isUserLoggedIn() {
    	global $modx;
    
    	$userdetails= array ();
    	if ($modx->isFrontend() && isset ($_SESSION['webValidated'])) {
    		// web user
    		$userdetails['loggedIn']= true;
    		$userdetails['id']= $_SESSION['webInternalKey'];
    		$userdetails['username']= $_SESSION['webShortname'];
    		$userdetails['usertype']= 'web'; // added by Raymond
    		return $userdetails;
    	}
    
    	if ($modx->isBackend() && isset ($_SESSION['mgrValidated'])) {
    		// manager user
    		$userdetails['loggedIn']= true;
    		$userdetails['id']= $_SESSION['mgrInternalKey'];
    		$userdetails['username']= $_SESSION['mgrShortname'];
    		$userdetails['usertype']= 'manager'; // added by Raymond
    		return $userdetails;
    	}
    
    	return false;
    }
    
    function nocache_headers() {
    	header ("content-type: text/html");
    	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
    	header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
    	header("Cache-Control: no-store, no-cache, must-revalidate");
    	header("Cache-Control: post-check=0, pre-check=0", false);
    	header("Pragma: no-cache");
    }
    yama さんイジメ過ぎて話してくれないし ・・
      • 33014 ☆ A M B ☆
      • 1,231 Posts
      引っ越しの準備であまり顔を出せないです。しばらくネットも使えないかも。
      304は、リクエストヘッダ・レスポンスヘッダ間のハンドシェイクをちゃんとやったほうがいいかもですよ。
      (条件付きGETと呼ばれる由縁でもありますが)

      追記
      よく見るとempty($_SERVER[’HTTP_IF_MODIFIED_SINCE’])など書いてあるので、考慮してあるのかな
        • 6350
        • 421 Posts
        解決しました。 Ditto の引数に ’depth’=>’2’ を追加しました。
        今回も思い込みによる失敗でした。Ditto はデフォルトではすべての階層が対象になっていると ・・
        case $site_start: // ドキュメント以外にカウンタ、最新情報などを含むページ
        case 2: // ブログ一覧が更新できないんだよ~~っ
        $modx_last_modified = $modx->runSnippet(’Ditto’,
        array (
        ’parents’ => ’0’,
        ’depth’ => ’2’,
        ’display’ => ’1’,
        ’tpl’ => ’@CODE:[+editedon+]’,
        ’orderBy’ => ’editedon DESC’)
        );
        実際のサンプルサイトの例ではすべてのページに news などが含まれているためこちらを default の処理にするのが正しいと思います。

        引き続き ETag 勉強中 ・・・ laugh

        ところで yama さん、引越しの理由とは
        (1)一軒家に引っ越して縁側でペットと一緒に余生を送る
        (2)高階層マンションに引っ越して最上階で余生を送る
        (3)その他(            )
          • 6350
          • 421 Posts
          ログイン時の動作が安定しないので次の部分の修正で改善しました。

          if ( isUserLoggedIn() ) nocache_headers();
          ↓
          if ( isUserLoggedIn() ) return;

          最初は nocache_headers() の部分を exit にしていたのですが exit で抜けると画面が表示できなくなる理由がわからなかったためです。イベント内で exit で抜ける場合と return で抜ける場合の挙動がようやく理解できたというわけです。exit の場合は呼び出し元に false を返しているんでしょうか?

          ユーザのログイン状況をマネージャまで判断しているのはブログコメントのマネージャ管理機能をキャッシュさせないためです。ログインの状態をキャッシュさせたい場合には ETag を使用するのが本来の方法のようですが ETag についてはまだまだ勉強中です。 laugh


          さらに30分後、・・・
          isUserLoggedIn() 内の赤字部分を変更するか削除してください (^。^)y-.。o○
          if ($modx->isBackend() && isset ($_SESSION[’mgrValidated’])) {
          ↓
          if ($modx->isFrontend() && isset ($_SESSION[’mgrValidated’])) {
            • 6350
            • 421 Posts
            一応、最終版です

            プラグインに適当な名前で登録します。
            今回はコメント表示の更新を考慮しますた。 blog 機能を使わない場合今回の機能追加は不要です。
            システムイベントは OnWebPagePrerender でサンプルサイト限定です。
            誰にでも応用しやすくするためショートプログラムとしRSSページの値が固定になっています。

            ※サンプルサイトのようにサイドバーに news などの最新情報を含む場合には case $site_start: の部分を
             case default に置き換えたほうが効率がよくなります。
            ※すべてのページのサイドバーに「最近のコメント」などを表示させる場合にはこのプラグインは役に立ちません。
             キャッシュを利用したい場合 jot_content からコメントの作成時刻を持ってくる必要があります。
            if ( isUserLoggedIn() )  return;		// ログイン中は Last-Modified を出力しない
            
            $isBlog = array(2);				// ブログ対象のドキュメントID 配列(複数の場合は array(2,55,77) のように追加
            $docId = $modx->documentObject['id'];		// 現在のドキュメントID
            $parent = $modx->documentObject['parent'];	// 親のドキュメントID
            if (in_array($docId,$isBlog)) return;		// blog 一覧ではコメント数カウントのため Last-Modified を出力しない
            if (in_array($parent,$isBlog)) return;		// blog 記事の場合はコメント表示更新のため Last-Modified を出力しない
            
            $site_start = $modx->config['site_start'];
            switch ($docId) {
            case $site_start:		// ドキュメント以外にカウンタ、最新情報などを含むページ
            	$modx_last_modified = $modx->runSnippet('Ditto', array( 'parents'=>'0', 'depth'=>'2', 'display'=>'1', 'tpl'=>'@CODE:[+editedon+]', 'orderBy'=>'editedon DESC') );
            	$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
            	$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
            
            	if ( ($client_last_modified) ? ($client_modified_timestamp >= $modx_last_modified) : 0 ) {
            		header("HTTP/1.1 304 Not Modified");
            		header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
            		exit;
            	}
            
            	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
            	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
            	break;
            
            case 11:			// RSS のページは常に 200 OK ETag は単なる飾りではない
            	$modx_last_modified = $modx->runSnippet('Ditto', array( 'parents'=>'2','display'=>'1', 'tpl'=>'@CODE:[+editedon+]','orderBy'=>'editedon DESC') );
            	$etag = '"' . md5($modx_last_modified) . '"';
            	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
            	header("ETag: $etag");
            	break;
            
            default:			// ドキュメント自身が最終更新日となるページ
            	$modx_last_modified = $modx->documentObject["editedon"];
            	$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
            	$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
            
            	if ( ($client_last_modified) ? ($client_modified_timestamp >= $modx_last_modified) : 0 ) {
            		header("HTTP/1.1 304 Not Modified");
            		header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
            		exit;
            	} 
            
            	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
            	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
            }
            
            function isUserLoggedIn() {
            	global $modx;
            
            	$userdetails= array ();
            	if ($modx->isFrontend() && isset ($_SESSION['webValidated'])) {
            		// web user
            		$userdetails['loggedIn']= true;
            		$userdetails['id']= $_SESSION['webInternalKey'];
            		$userdetails['username']= $_SESSION['webShortname'];
            		$userdetails['usertype']= 'web'; // added by Raymond
            		return $userdetails;
            	}
            
            	if ($modx->isFrontend() && isset ($_SESSION['mgrValidated'])) {
            		// manager user
            		$userdetails['loggedIn']= true;
            		$userdetails['id']= $_SESSION['mgrInternalKey'];
            		$userdetails['username']= $_SESSION['mgrShortname'];
            		$userdetails['usertype']= 'manager'; // added by Raymond
            		return $userdetails;
            	}
            	return false;
            }

            テーブルの jot_content にコメントがあるかどうかを調べる方法で考えていたのですが sql を何度も発行するコストとキャッシュしない方法を比較して今回の解決方法を選択しました。

            RSS と 304 Not Modified の関連を調べるためにはじめた勉強ですが最終的にブラウザのキャッシュ制御の話になってしまいました。

            ETag は引き続き勉強中 laugh
              • 6350
              • 421 Posts
              最終版を出した後で大きな間違いに気が付きました。

              編集時刻以外に公開/非公開、削除時刻などは考慮していませんでした。
              特に削除したレコードをゴミ箱で抹消された場合に削除日時は残りません。

              ようするに、最新の更新日時だけ見てたのでは「ダメ」ってこってす

              そこで考えたのが「SHOW TABLE STATUS」これっきゃありません
              残念ながら、Ditto は使えないようです(と思います)

              仕方ないので書き直そうと思います :’(
                • 6350
                • 421 Posts
                新規作成、編集、削除/復活、公開/非公開、コメント記事にも同様にに対応できました。
                今回は MySQL の SHOW TABLE STATUS などというマイナーな方式での対応となっているので自分でも納得のできない解決方法です。

                WordPress を参考にしているのですが CLASS 化が進みすぎて処理の流れがつかみきれません。WordPress を参考にしても SELECT 更新日時 ~ だけで処理しているようで「削除」にどのような方法で対応しているのかまったく理解できないんです。

                さらに SQL を毎回実行しないように メモリキャッシュもまねてみましたが常識で考えればこんな方法でできるわけ有りませんよね。このへんも今後の課題です。WordPress が出力する Last-Modified のフローチャートがものすごく知りたいと思っているこの頃です。

                ブログ一覧表示の部分だけはページ分割時のキャッシュ対応が難しいので今回は未考慮です。WordPress では当然のように対応されているんですが??? こんなことにこだわっていると何も進みません。modx 標準のまま常に 200 OK を返すのが一番楽な方法のようです。

                追記:2009/03/25 14:28
                残念ながらさくらインターネットの MySQL 4.1.22 ではSHOW TABLE STATUS WHERE Name=’modx_site_content’ の赤字部分がサポートされていないようでエラーになるためこの方法は使えないようです。 :’(
                if ( isUserLoggedIn() )  return;			// ログイン中は Last-Modified を出力しない
                
                $isBlog = array(2);					// ブログ対象のドキュメントID 配列
                $docId = $modx->documentObject['id'];			// 現在のドキュメントID
                $parent = $modx->documentObject['parent'];		// 親のドキュメントID
                if (in_array($docId,$isBlog)) return;			// blog 一覧では Last-Modified を出力しない
                // if (in_array($parent,$isBlog)) return;		// blog 記事の場合は Last-Modified を出力しない
                
                $site_start = $modx->config['site_start'];
                switch ($docId) {
                case $site_start:		// ドキュメント以外にカウンタ、最新情報などを含むページ
                case 2:
                //	$modx_last_modified = $modx->runSnippet('Ditto', array( 'parents'=>'0', 'depth'=>'2', 'display'=>'1', 'tpl'=>'@CODE:[+editedon+]', 'orderBy'=>'editedon DESC') );
                	$modx_last_modified = getLastModified('modx_site_content');
                	$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
                	$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
                
                	if ( ($client_last_modified) ? ($client_modified_timestamp >= $modx_last_modified) : 0 ) {
                		header("HTTP/1.1 304 Not Modified");
                		header("Expires: Mon, 26 Jul 1997 05:00:01 GMT");
                		exit;
                	}
                
                	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
                	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
                	break;
                case 11:			// RSS のページは常に 200 OK ETag は単なる飾りではない
                	$modx_last_modified = $modx->runSnippet('Ditto', array( 'parents'=>'2','display'=>'1', 'tpl'=>'@CODE:[+editedon+]','orderBy'=>'editedon DESC') );
                	$etag = '"' . md5($modx_last_modified) . '"';
                	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
                	header("ETag: $etag");
                	break;
                default:			// ドキュメント自身が最終更新日となるページ
                	$modx_last_modified = $modx->documentObject["editedon"];
                	if (in_array($parent,$isBlog)) {
                		$comment_last_modified = getLastModified('modx_jot_content');
                		if ($comment_last_modified > $modx_last_modified) {
                			$modx_last_modified = $comment_last_modified;
                		}
                	}
                	$client_last_modified = empty($_SERVER['HTTP_IF_MODIFIED_SINCE']) ? '' : trim($_SERVER['HTTP_IF_MODIFIED_SINCE']);
                	$client_modified_timestamp = $client_last_modified ? strtotime($client_last_modified) : 0;
                
                	if ( ($client_last_modified) ? ($client_modified_timestamp >= $modx_last_modified) : 0 ) {
                		header("HTTP/1.1 304 Not Modified");
                		header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
                		exit;
                	} 
                
                	header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
                	header("Last-Modified: " . gmdate('r', $modx_last_modified) . " GMT");
                }
                
                function getLastModified($table) {
                	global $modx, $cash_last_modified;
                
                	if ( isset($cash_last_modified)) {
                		$etag = '"' . md5($cash_last_modified) . '"';
                		header("ETag: $etag");	// メモリキャッシュデバッグ用です
                		return $cash_last_modified;
                	}
                
                	$sql= "SHOW TABLE STATUS WHERE Name='".$table."'";
                	$result = $modx->dbQuery($sql);
                	$tmpRow = $modx->fetchRow($result);
                	$last_modified = $tmpRow['Update_time'];
                	$cash_last_modified = strtotime($last_modified);
                	return $cash_last_modified;
                }
                
                function isUserLoggedIn() {
                	global $modx;
                
                	$userdetails= array ();
                	if ($modx->isFrontend() && isset ($_SESSION['webValidated'])) {
                		// web user
                		$userdetails['loggedIn']= true;
                		$userdetails['id']= $_SESSION['webInternalKey'];
                		$userdetails['username']= $_SESSION['webShortname'];
                		$userdetails['usertype']= 'web'; // added by Raymond
                		return $userdetails;
                	}
                
                	if ($modx->isFrontend() && isset ($_SESSION['mgrValidated'])) {
                		// manager user
                		$userdetails['loggedIn']= true;
                		$userdetails['id']= $_SESSION['mgrInternalKey'];
                		$userdetails['username']= $_SESSION['mgrShortname'];
                		$userdetails['usertype']= 'manager'; // added by Raymond
                		return $userdetails;
                	}
                	return false;
                }