WordPressのパスワード保護している記事のtitleも変更する

今現在、WordPressでパスワード保護された記事の本文やコメントは非表示になりますが、titleエレメントやRSSなんかは非表示になりません。
今回は非推奨になったwp_titleとWordPress 4.4から登場したadd_theme_support('title-tag')を有効化したテーマ等で使うwp_get_document_title()でも使える方法でいきます。

序でに「非公開:」や「保護中:」って文字も削除・変更しちゃいますー。

まずは完成したWordPressのプラグインコード。

<?php
/*
Plugin Name: Change Password POST Title
Plugin URI: http://blog.wolfs.jp/20160513-3616/
Description: パスワードで保護された記事のタイトルを変更します。
Version: 1.0.0
Author: Kerberos
Author URI: http://blog.wolfs.jp/
*/
 
class changePasswordPostTitle {
    private $plugin_dir = ABSPATH.'/wp-content/plugins/change_password_post_title/feed/';
    private $post_password_title = '[パスワードで保護された記事]';
 
    public function __construct() {
        add_filter('the_title', array($this, 'the_title'), 10, 2);
        add_filter('pre_get_document_title', array($this, 'pre_get_document_title'));
        add_filter('protected_title_format', array($this, 'protected_title_format'));
 
        add_filter('aioseop_title_single', array($this, 'aioseop_title'));
        add_filter('aioseop_title_page', array($this, 'aioseop_title'));
 
        remove_action('do_feed_rss2', 'do_feed_rss2');
        remove_action('do_feed_atom', 'do_feed_atom');
        add_action('do_feed_rss2', array($this, 'do_feed_rss2'), 10, 1);
        add_action('do_feed_atom', array($this, 'do_feed_atom'), 10, 1);
    }
 
 
    public function the_title($title = '', $currentID = 0) {
        global $post;
 
        if ($currentID !== 0) {
            if (post_password_required($currentID) === true) {
                if ($post->ID == $currentID && is_admin() === false) {
                    return $this->post_password_title;
                }
            }
 
            return $this->remove_title_prefix($title);
        }
 
        return $title;
    }
 
    public function pre_get_document_title($title) {
        if (is_single() === true || is_page() === true) {
            if (post_password_required($post->ID) === true) {
                return $this->post_password_title;
            }
 
            return $this->remove_title_prefix($title);
        }
 
        return $title;
    }
 
    public function protected_title_format($title) {
        global $post;
 
        if (post_password_required($post->ID) === false) {
            return '&#x1F512; %s';
        }
 
        return $this->post_password_title;
    }
 
    public function aioseop_title($title) {
        global $post;
 
        if (post_password_required($post->ID) === true) {
            return $this->post_password_title;
        }
 
        return $title;
    }
 
    private function remove_title_prefix($title) {
        $search[0] = '/^' . str_replace('%s', '(.*)', preg_quote(__('Protected: %s'), '/' )) . '$/';
        $search[1] = '/^' . str_replace('%s', '(.*)', preg_quote(__('Private: %s'), '/' )) . '$/';
 
        return preg_replace($search, '$1', $title);
    }
 
 
    public function do_feed_rss2($for_comments) {
        if ($for_comments) {
            load_template($this->plugin_dir.'feed-rss2-comments.php');
        }
    }
 
    public function do_feed_atom($for_comments) {
        if ($for_comments) {
            load_template($this->plugin_dir.'feed-atom-comments.php');
        }
    }
}
 
new changePasswordPostTitle();
?>

フィルターのフック名と関数は同じ名前にしてあるのでわかると思うので、その辺は略しますw
このプラグインでパスワード保護ページはこうなります:サンプルページ
続きを読む

e621.netで画像保存を楽にする

e621.netってケモノ絵や話題を投稿するサイトがあるんです。
ここは健全な絵もあるけれどR18な絵も多数ある所。
ケモノが好きな人は見てて飽きない所ですねw

ぼーっと見ていたら、とあるアーティストさんの過去絵が沢山あったので、ガンガン保存していたら保存ダイアログを出すのがメンドウになってきましたw
なので自動化・・はダルイしイラナイ画像も拾うから画像をダブルクリックするだけで保存ダイアログが出るようにuserChromeを作ってみました。

e621net-supporter.uc.js

// ==UserScript==
// @name           e621.net: 画像保存サポーター
// @namespace      http://blog.wolfs.jp/
// @description
// ==/UserScript==
 
var e621netSupporterObj = {
    targetHost: 'e621.net',
    targetPage: 'e621.net/post/show/',
 
    isTargetPage: false,
    lastTime: 0,
 
    clickID: {
        left: 0,
        right: 2,
        center: 1
    },
 
    init: function() {
        gBrowser.mPanelContainer.addEventListener("dblclick", this, true);
    },
 
    handleEvent: function(event) {
        if (gBrowser.currentURI.asciiSpec.indexOf(this.targetPage) != -1) {
            event = new XPCNativeWrapper(event);
            if (event.target instanceof HTMLImageElement) {
                if (event.target.id == 'image') {
                    event.preventDefault();
 
                    if (new Date().getTime() - this.lastTime > 5000) {
                        this.lastTime = new Date().getTime();
 
                        var img = this.getImage(event.target.src);
                        if (img != null) {
                            this.saveImage(img, this.getFileName(event.target.src));
                        }
                        img = null;
                    }
                }
            }
        }
    },
 
    getFileName: function(url) {
        return url.match(".+/(.+?)([\?#;].*)?$")[1];
    },
 
    getImage: function(url) {
        var request = new XMLHttpRequest();
        request.open('GET', url, false);
        request.overrideMimeType('text/plain; charset=x-user-defined');
        request.channel.loadFlags |= Components.interfaces.nsIRequest.LOAD_BYPASS_CACHE;
        request.send(null);
 
        if (request.status == 200) {
            return request.responseText;
        }
 
        request = null;
        return null;
    },
 
    saveImage: function(imageData, requestFileName) {
        var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(Components.interfaces.nsIFilePicker);
        fp.init(window, 'Select a file', Components.interfaces.nsIFilePicker.modeSave);
        //fp.appendFilters(Components.interfaces.nsIFilePicker.filterImages);
        //fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
        fp.appendFilter('JPEG Image', '*.jpg');
        fp.appendFilter('PNG Image', '*.png');
        fp.appendFilter('GIF Image', '*.gif');
        fp.appendFilters(Components.interfaces.nsIFilePicker.filterAll);
 
        fp.defaultString = requestFileName;
        switch (requestFileName.split('.')[1]) {
            case 'jpg':
                fp.defaultExtension = 'jpg';
                fp.filterIndex = 0;
                break;
            case 'png':
                fp.defaultExtension = 'png';
                fp.filterIndex = 1;
                break;
            case 'gif':
                fp.defaultExtension = 'gif';
                fp.filterIndex = 2;
                break;
            default:
                fp.filterIndex = 3;
        }
 
        switch (fp.show()) {
            case Components.interfaces.nsIFilePicker.returnOK:
            case Components.interfaces.nsIFilePicker.returnReplace:
                var outStream = Components.classes["@mozilla.org/network/safe-file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
                outStream.init(fp.file, 0x02 | 0x08 | 0x20, 0664, 0);
                outStream.write(imageData, imageData.length);
                if (outStream instanceof Components.interfaces.nsISafeOutputStream) {
                    outStream.finish();
                } else {
                    outStream.close();
                }
                outStream = null;
                break;
            case Components.interfaces.nsIFilePicker.returnCancel:
                break;
        }
    }
};
 
e621netSupporterObj.init();

本当はグリモンとかでサクッと実装したかったけれど、保存ダイアログをだすfilepickerやfile-output-streamなんかは呼び出せないので、権限があるuserChromeで実装。

内容は簡単。
 1.ダブルクリックされたらページのURLがe621.net/post/show/かどうか比較。
 2.対象のページだった場合はクリック先のエレメントがHTMLImageElementかつIDがimageか確認。
 3.imageだった場合はXMLHttpRequestで画像のバイナリを獲得。
   これは既に表示されている画像のキャッシュが効くのでいいb
 4.画像を正常に読み込めたら保存ダイアログを呼び出して保存先やファイル名を決定。
って感じ。

userChromeだけれど、内容はFirefox系のAPIに依存しているのでFirefox系ブラウザ専用です。