কমেন্টস.এইচপিপি লোড করতে কমেন্ট_টেমপ্লেট () প্রতিরোধ করুন


9

আমি একটি টেম্পলেট ইঞ্জিন ব্যবহার করে একটি ওয়ার্ডপ্রেস থিম বিকাশ করছি। আমি চাই আমার কোডটি ডাব্লুপি কোর কার্যকারিতার সাথে যথাসম্ভব সামঞ্জস্যপূর্ণ হোক।

প্রথমে কিছু প্রসঙ্গ

আমার প্রথম সমস্যাটি হ'ল ডাব্লুপি কোয়েরি থেকে শুরু করে টেমপ্লেটটি সমাধান করার উপায় খুঁজে পাওয়া। আমি আমার একটি লাইব্রেরি ব্যবহার যে এক মীমাংসিত ব্রেন \ শ্রেণীক্রম

get_template_part()পার্টিয়ালগুলির মতো এবং অন্যান্য অনুরূপ লোড হওয়া সম্পর্কিত এবং অন্যান্য ক্রিয়াকলাপগুলি get_header(), get_footer()টেম্পলেট ইঞ্জিনের আংশিক কার্যকারিতাটিতে মোড়কের লিখন লেখা বেশ সহজ ছিল।

সমস্যাটি

আমার সমস্যা এখন মন্তব্য টেমপ্লেট কীভাবে লোড করা যায়।

ওয়ার্ডপ্রেস ফাংশন comments_template()একটি 200 ডলার লাইনের ফাংশন যা অনেক কিছুই করে, যা আমি সর্বোচ্চ মূল সামঞ্জস্যের জন্যও করতে চাই।

তবে, আমি কল করার সাথে সাথেই comments_template()একটি ফাইল requireডি হয়, এটি এর মধ্যে প্রথম:

  • স্থির মধ্যে ফাইল COMMENTS_TEMPLATE, সংজ্ঞায়িত হলে
  • comments.php থিম ফোল্ডারে যদি পাওয়া যায়
  • /theme-compat/comments.php ডাব্লুপি-তে সর্বশেষ রিসর্ট ফ্যালব্যাক হিসাবে ফোল্ডার অন্তর্ভুক্ত

সংক্ষেপে, পিএইচপি ফাইলটি লোড করার জন্য ফাংশনটি রোধ করার কোনও উপায় নেই, যা আমার পক্ষে কাম্য নয়, কারণ আমার টেমপ্লেটগুলি রেন্ডার করা দরকার এবং কেবল ব্যবহার করা উচিত নয় require

বর্তমান সমাধান

এই মুহুর্তে, আমি একটি খালি comments.phpফাইল পাঠাচ্ছি এবং আমি কোনও 'comments_template'ফিল্টার হুক ব্যবহার করছি , ওয়ার্ডপ্রেস কোন টেম্পলেট লোড করতে চায় তা জানতে, এবং টেমপ্লেট লোড করতে আমার টেম্পলেট ইঞ্জিন থেকে বৈশিষ্ট্যটি ব্যবহার করুন।

এটার মতো কিছু:

function engineCommentsTemplate($myEngine) {

    $toLoad = null; // this will hold the template path

    $tmplGetter = function($tmpl) use(&$toLoad) {
       $toLoad = $tmpl;

       return $tmpl;
    };

    // late priority to allow filters attached here to do their job
    add_filter('comments_template', $tmplGetter, PHP_INT_MAX);

    // this will load an empty comments.php file I ship in my theme
    comments_template();

    remove_filter('comments_template', $tmplGetter, PHP_INT_MAX);

    if (is_file($toLoad) && is_readable($toLoad)) {
       return $myEngine->render($toLoad);
    }

    return '';    
}

প্রশ্নটি

এটি কাজ করে, মূল সামঞ্জস্যপূর্ণ তবে ... খালি শিপ না করে এটিকে কাজ করার কোনও উপায় আছে comments.phpকি?

কারণ আমি এটি পছন্দ করি না।

উত্তর:


4

ওপিতে সমাধানের চেয়ে নীচের সমাধানটি আরও ভাল Not

আমার মনে হয় আপনি যখন 'comments_template'ফিল্টার প্রয়োগ করা হয় তখন আপনি ওয়ার্ডপ্রেস সম্পাদন বন্ধ করতে পিএইচপি ব্যতিক্রম ব্যবহার করতে পারেন ।

আপনি ডিটিও হিসাবে একটি কাস্টম ব্যতিক্রম শ্রেণি ব্যবহার করতে পারেন টেমপ্লেটটি বহন করতে ।

এটি ব্যতিক্রমের জন্য একটি খসড়া:

class CommentsTemplateException extends \Exception {

   protected $template;

   public static function forTemplate($template) {
     $instance = new static();
     $instance->template = $template;

     return $instance;
   }

   public function template() {
      return $this->template;
   }
}

এই ব্যতিক্রম শ্রেণিটি উপলভ্য হওয়ার সাথে সাথে আপনার ফাংশনটি হয়ে যায়:

function engineCommentsTemplate($myEngine) {

    $filter = function($template) {
       throw CommentsTemplateException::forTemplate($template);
    };  

    try {
       add_filter('comments_template', $filter, PHP_INT_MAX); 
       // this will throw the excption that makes `catch` block run
       comments_template();
    } catch(CommentsTemplateException $e) {
       return $myEngine->render($e->template());
    } finally {
       remove_filter('comments_template', $filter, PHP_INT_MAX);
    }
}

দ্য finallyব্লক পিএইচপি 5.5+ প্রয়োজন।

একইভাবে কাজ করে এবং খালি টেম্পলেট প্রয়োজন হয় না।


4

আমি আগে এই সঙ্গে কুস্তি করেছ এবং আমার সমাধান ছিল - এটা ফাইল প্রয়োজন নিজেই কোপ আউট করতে পারেন, যতদিন এটা করে না কি কিছু।

এখানে আমার মেডো টেম্প্লেটিং প্রকল্পের প্রাসঙ্গিক কোড :

public function comments_template( \Twig_Environment $env, $context, $file = 'comments.twig', $separate_comments = false ) {

    try {
        $env->loadTemplate( $file );
    } catch ( \Twig_Error_Loader $e ) {
        ob_start();
        comments_template( '/comments.php', $separate_comments );
        return ob_get_clean();
    }

    add_filter( 'comments_template', array( $this, 'return_blank_template' ) );
    comments_template( '/comments.php', $separate_comments );
    remove_filter( 'comments_template', array( $this, 'return_blank_template' ) );

    return twig_include( $env, $context, $file );
}

public function return_blank_template() {

    return __DIR__ . '/blank.php';
}

আমি comments_template()গ্লোবাল এবং এই জাতীয় সেট আপ করার গতিগুলির মধ্য দিয়ে যেতে দিয়েছি , তবে এটিকে খালি পিএইচপি ফাইলটি খাওয়ান requireএবং আউটপুটটির জন্য আমার আসল টুইগ টেম্পলেটটিতে যেতে।

দ্রষ্টব্য যে এটির প্রাথমিক comments_template()কলটি বাধা দিতে সক্ষম হওয়া দরকার , যা আমি করতে পারি যেহেতু আমার টুইগ টেম্পলেটটি সত্যিকারের পিএইচপি ফাংশনের চেয়ে মধ্যস্থতাকারী বিমূর্তি কল করছে।

আমাকে এখনও এটির জন্য খালি ফাইল পাঠাতে হবে, আমি লাইব্রেরিতে এটি করি এবং থিম প্রয়োগ করে এটিকে মোটেই যত্ন নেওয়ার দরকার নেই।


উত্সাহিত, ধন্যবাদ। আমি ইতিমধ্যে আপনার পদ্ধতিটি দেখেছি যেহেতু আমি আগে মেডো ব্যবহার করেছি। আমি এখানে যা পছন্দ করি না তা হ'ল কোনও ফাঁকা টেম্পলেট যেভাবেই প্রেরণ করা দরকার। তদ্ব্যতীত, এটি টেমপ্লেটটি কাস্টমাইজ করার জন্য comments_templateফিল্টার বা COMMENTS_TEMPLATEধ্রুবক ব্যবহারের যে কোনও প্রচেষ্টা ভঙ্গ করে । যা গুরুত্বপূর্ণ নয়, তবে যেমনটি আমি বলেছি, আমি মূলের সাথে যথাসম্ভব সামঞ্জস্যপূর্ণ থাকতে চেয়েছিলাম।
গাজাজ্যাপ

@ গাজাজাপ হুম্মম ... কোনও কারণেই আমি আমার মোড়কগুলিতে ফিল্টার এবং ধ্রুবকটির জন্য সমর্থন যোগ করতে পারি নি, তবে এটি মাইক্রোম্যানেজিংয়ে যায়।
রর্স্ট

3

সমাধান: একটি অস্থায়ী ফাইল ব্যবহার করুন - একটি অনন্য ফাইলের নাম সহ

প্রচুর ঝাঁপিয়ে পড়ার পরে এবং পিএইচপি-র সবচেয়ে গভীরতম কোণে হামাগুড়ি দেওয়ার পরে, আমি প্রশ্নটি পুনরায় উত্তর দিয়েছি:

কিভাবে এক করতে রত ফেরার মধ্যে পিএইচপি TRUEজন্য file_exists( $file )?

মূল কোড যেমন হয়

file_exists( apply_filters( 'comments_template', $template ) )

তারপরে প্রশ্নটি দ্রুত সমাধান করা হয়েছিল:

$template = tempnam( __DIR__, '' );

এবং এটাই. wp_upload_dir()পরিবর্তে এটি ব্যবহার করা ভাল হবে:

$uploads = wp_upload_dir();
$template = tempname( $uploads['basedir'], '' );

আরেকটি বিকল্প হতে পারে get_temp_dir()কোনটি মোড়ানো ব্যবহার করতে পারে WP_TEMP_DIR। ইঙ্গিত: এটি আশ্চর্যরূপে ফিরে আসে /tmp/যাতে ফাইলগুলি রিবুটগুলির মধ্যে সংরক্ষণ করা যায় না , যা /var/tmp/হবে। একটি শেষে একটি সাধারণ স্ট্রিং তুলনা করতে পারে এবং রিটার্নের মানটি পরীক্ষা করে তার প্রয়োজনীয়তার ক্ষেত্রে এটি ঠিক করতে পারে - যা এই ক্ষেত্রে নয়:

$template = tempname( get_temp_dir(), '' )

এখনই পরীক্ষা করার জন্য যদি সামগ্রীগুলি ছাড়াই অস্থায়ী ফাইলের জন্য ত্রুটি ফেলে দেওয়া হয়:

<?php
error_reporting( E_ALL );
$template = tempnam( __DIR__, '' );
var_dump( $template );
require $template;

এবং: কোনও ত্রুটি নেই

সম্পাদনা: @ টসচো মন্তব্যগুলিতে যেমন উল্লেখ করেছেন, এটি করার আরও ভাল উপায় এখনও রয়েছে :

$template = tempnam( trailingslashit( untrailingslashit( sys_get_temp_dir() ) ), 'comments.php' );

দ্রষ্টব্য: পিএইচপিএন ডক্সে ব্যবহারকারীর নোট অনুসারে , sys_get_temp_dir()আচরণগুলি সিস্টেমের মধ্যে পৃথক হয়। ফলস্বরূপ ফলাফল পিছনে স্ল্যাশ সরানো হবে, তারপরে আবার যুক্ত করা হবে। যেহেতু মূল বাগ # 22267 স্থির হয়েছে, এটি এখন উইন / আইআইএস সার্ভারগুলিতেও কাজ করা উচিত।

আপনার রিফ্যাক্টরড ফাংশন (পরীক্ষিত নয়):

function engineCommentsTemplate( $engine )
{
    $template = null;

    $tmplGetter = function( $original ) use( &$template ) {
        $template = $original;
        return tempnam( 
            trailingslashit( untrailingslashit( sys_get_temp_dir() ) ),
            'comments.php'
        );
    };

    add_filter( 'comments_template', $tmplGetter, PHP_INT_MAX );

    comments_template();

    remove_filter( 'comments_template', $tmplGetter, PHP_INT_MAX );

    if ( is_file( $template ) && is_readable( $template ) ) {
        return $engine->render( $template );
    }

    return '';
}

বোনাস Nr.1: tmpfile()ফিরে আসবে NULL। হাঁ সত্যিই.

বোনাস Nr.2: file_exists( __DIR__ )ফিরে আসবে TRUE। হ্যাঁ, সত্যিই ... যদি আপনি ভুলে গেছেন।

^ এটি ডাব্লুপি কোরে প্রকৃত বাগ বাড়ে।


অন্যকে এক্সপ্লোরার মোডে যেতে এবং সেগুলি (খারাপভাবে অননুমোদিত টুকরো টুকরো টুকরো করা) সন্ধানে সহায়তা করার জন্য, আমি যা চেষ্টা করেছি তাড়াতাড়ি সংক্ষেপ করব:

চেষ্টা 1: মেমরিতে অস্থায়ী ফাইল

আমি প্রথম চেষ্টাটি হ'ল ব্যবহার করে একটি অস্থায়ী ফাইলে একটি স্ট্রিম তৈরি করেছিলাম php://temp। পিএইচপি ডক্স থেকে:

উভয়ের মধ্যে একমাত্র পার্থক্য হ'ল এটি php://memoryসর্বদা স্মৃতিতে তার ডেটা সঞ্চয় করে php://tempরাখবে , যেখানে একবারে সংরক্ষণ করা ডেটার পরিমাণ পূর্বনির্ধারিত সীমাতে হিট হয়ে যায় (ডিফল্টটি 2 মেগাবাইট)। এই অস্থায়ী ফাইলটির অবস্থানটি sys_get_temp_dir()ফাংশনের মতোই নির্ধারিত হয় ।

কোড:

$handle = fopen( 'php://temp', 'r+' );
fwrite( $handle, 'foo' );
rewind( $handle );
var_dump( file_exist( stream_get_contents( $handle, 5 ) );

সন্ধান করা: না, কাজ করে না।

চেষ্টা 2: একটি অস্থায়ী ফাইল ব্যবহার করুন

আছে tmpfile(), তাই না কেন যে ব্যবহার ?!

var_dump( file_exists( tmpfile() ) );
// boolean FALSE

হ্যাঁ, এই শর্টকাট সম্পর্কে অনেক কিছু।

চেষ্টা 3: একটি কাস্টম স্ট্রিম র‌্যাপার ব্যবহার করুন

পরবর্তী আমি ভেবেছিলাম আমি একটি কাস্টম স্ট্রিম মোড়ক তৈরি করতে এবং এটি ব্যবহার করে নিবন্ধ করতে পারিstream_wrapper_register() । তারপরে আমি সেই ফাইলটি থেকে ভার্চুয়াল টেমপ্লেটটি ব্যবহার করতে পারি যে আমাদের কাছে কোনও ফাইল রয়েছে into নীচের উদাহরণ কোড (আমি ইতিমধ্যে পূর্ণ শ্রেণি মুছে ফেলেছি এবং ইতিহাসের পর্যাপ্ত পদক্ষেপ নেই ...)

class TemplateStreamWrapper
{
    public $context;

    public function stream_open( $path, $mode, $options, &$opened )
    {
        // return boolean
    }
}

stream_wrapper_register( 'vt://comments', 'TemplateStreamWrapper' );
// … etc. …

আবার, এই ফিরে NULLউপর file_exists()


পিএইচপি 5.6.20 দিয়ে পরীক্ষিত


আমি মনে করি যে আপনার প্রচেষ্টা 3 টি তত্ত্বের সাথে কাজ করা উচিত। আপনার কাস্টম স্ট্রিম মোড়কে, আপনি কি প্রয়োগ করেছেন stream_stat()? আমি মনে করি যে file_exists()এটি যাচাই করার জন্য ডাকবে ... php.net/manual/en/streamwrapper.stream-stat.php
অ্যালেইন

আপভোটেড কারণ এটি বেশ সুন্দর এবং খুব হ্যাকিশ নয়। তবে, যেহেতু আমার কোডটি বিভিন্ন সেটআপে ব্যবহার করার উদ্দেশ্যে, তাই আমি ভয় করি যে লেখার অনুমতি কোনও সমস্যা হতে পারে। তদুপরি, অস্থায়ী ফাইলগুলি মুছতে হবে, যা উড়তে এতটা সহজ নয়, কারণ এটি দ্বারা ফিরে আসা পুরো পথটি থামানো সহজ নয় tempnam()। ক্রোন জব ব্যবহার করা কাজ করবে তবে এটি অতিরিক্ত ওভারহেড ...
গাজাজাপ

আমি মনে করি অস্থায়ী ফাইল লেখা খালি টেম্পলেট শিপিংয়ের চেয়ে খারাপ। স্থির খালি টেম্পলেট অপকোডে ক্যাশে হবে। টেম্প ফাইলটি ডিস্কে লিখতে হবে, কোল্ড-পার্সড (কোনও অপকোড নেই), তারপরে মুছে ফেলা হবে। কোনও ভাল কারণ ছাড়াই ডিস্কের হিটগুলি হ্রাস করা ভাল।
রাস্টটি

@ রারস্ট প্রশ্নটি কখনই পারফরম্যান্স বুদ্ধিমান ছিল না "ভাল কি" ? টেমপ্লেট ফাইল না থাকায় প্রশ্নটি সেদ্ধ হয়েছে :)
কায়সার

1
tempnam( sys_get_temp_dir(), 'comments.php' )একবার লিখিত হয় , আপনি ফাইলের নামটি পুনরায় ব্যবহার করতে পারেন , এবং ফাইলটি খালি রয়েছে , সুতরাং এটি অনেক সংস্থান ব্যবহার করে না। এছাড়াও আপনার কোডে এটি বোঝা সহজ। এখন পর্যন্ত সেরা সমাধান, ইমো।
ফুক্সিয়া

3

হিসাবে @AlainSchlesser রুট (এবং অ পরিশ্রমী জিনিষ হিসাবে সবসময় আমাকে বাগ) অনুসরণ করার পরামর্শ দেওয়া, আমি ভার্চুয়াল ফাইলগুলির জন্য একটি স্ট্রিম মোড়কের বিল্ডিং পুনঃচেষ্টা। আমি নিজেই এটি সমাধান করতে পারি না (পড়ুন: ডক্সে রিটার্নের মানগুলি পড়ছি), তবে এটি এসও-তে @ এইচপিয়ার্সের সহায়তায় সমাধান করেছি ।

class VirtualTemplateWrapper
{
    public $context;

    public function stream_open( $path, $mode, $options, &$opened_path ) { return true; }

    public function stream_read( $count ) { return ''; }

    public function stream_eof() { return ''; }

    public function stream_stat() {
        # $user = posix_getpwuid( posix_geteuid() );
        $data = [
            'dev'     => 0,
            'ino'     => getmyinode(),
            'mode'    => 'r',
            'nlink'   => 0,
            'uid'     => getmyuid(),
            'gid'     => getmygid(),
            #'uid'     => $user['uid'],
            #'gid'     => $user['gid'],
            'rdev'    => 0,
            'size'    => 0,
            'atime'   => time(),
            'mtime'   => getlastmod(),
            'ctime'   => FALSE,
            'blksize' => 0,
            'blocks'  => 0,
        ];
        return array_merge( array_values( $data ), $data );
    }

    public function url_stat( $path, $flags ) {
        return $this->stream_stat();
    }
}

আপনার কেবল নতুন প্রোটোকল হিসাবে নতুন ক্লাসটি নিবন্ধিত করতে হবে:

add_action( 'template_redirect', function() {
    stream_wrapper_register( 'virtual', 'VirtualTemplateWrapper' );
}, 0 );

এরপরে এটি ভার্চুয়াল (বিদ্যমান নেই) ফাইল তৈরি করতে দেয় :

$template = fopen( "virtual://comments", 'r+' );

আপনার ক্রিয়াকলাপটি তখন এতে রিফ্যাক্টর পেতে পারে:

function engineCommentsTemplate( $engine )
{
    $replacement = null;
    $virtual = fopen( "virtual://comments", 'r+' );

    $tmplGetter = function( $original ) use( &$replacement, $virtual ) {
        $replacement = $original;
        return $virtual;
    };

    add_filter( 'comments_template', $tmplGetter, PHP_INT_MAX );

    comments_template();

    remove_filter( 'comments_template', $tmplGetter, PHP_INT_MAX );

    // As the PHP internals are quite unclear: Better safe then sorry
    unset( $virtual );

    if ( is_file( $replacement ) && is_readable( $replacement ) ) {
        return $engine->render( $replacement );
    }

    return '';
}

যেমন file_exists()কোর আয় চেক TRUEএবং require $fileকোন ত্রুটি ছোঁড়ার।

আমার মনে রাখতে হবে যে ইউনিট পরীক্ষায় এটি সত্যিই সহায়ক হতে পারে বলে আমি কীভাবে খুশি।


1
দুর্দান্ত আবিষ্কার! আমি এই পদ্ধতির সেরাটি পছন্দ করি ;-) আমি নিশ্চিত যে মূলটির আরও কিছু অংশ রয়েছে যা এটি প্রয়োগ করা যেতে পারে।
বিরগিরে

1
উত্সাহিত এবং ধন্যবাদ! ইউনিট পরীক্ষা জন্যে রয়েছে ইতিমধ্যই থাকা github.com/mikey179/vfsStream তাই চাকা reinvent কোন প্রয়োজন;) BTW, আমি এই পদ্ধতির মত, না নিশ্চিত আমি এটি ব্যবহার করবেন, কারণ ব্যতিক্রম পদ্ধতি আমাকে সুখে মন্দ বোধ: ডি
gmazzap


@ কায়সার নাহ, আমি এটি পেয়েছি কারণ আমি আরটিএফএম
গাজাজাপ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.